grunt-xmlstoke
An extended version of grunt-xmlpoke by Brian Dukes - a gruntjs port of the
xmlpoke
NAnt task.
In addition to updating the values of existing nodes, as provided by grunt-xmlpoke, grunt-xmlstoke can perform all basic CRUD operations on XML Files: creating/inserting new nodes, deleting existing nodes, and reading the values of existing nodes (to then save them in
grunt.option
).
The current API should be completely backward-compatible with grunt-xmlpoke
## Getting Started This plugin requires Grunt `~0.4.2`
If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
npm install grunt-xmlstoke --save-dev
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt;
## The "xmlstoke" task
Overview
In your project's Gruntfile, add a section named xmlstoke
to the data object passed into grunt.initConfig()
.
grunt
### Action Options grunt-xmlstoke is configured with a series of actions (an array of objects), each of which is a single Read, Create/Insert, Update, or Delete operation.
#### action.type (all actions) Type: `String`, Default value: `undefined` (Default operation is Update)
Denotes the type of operation. Only the first character is evaluated (case-insensitive) so you can pretty much name it whatever for readability in your gruntfile. `i`, `Ins`, `INSERT` and even `indian food` all denote an insertion.
First character should be:
C or I - Create/Insert
R - Read
U - Update (this is the default, type can be left blank for Update as well)
D - Delete
#### action.xpath (all actions) Type: `String` or `Array of Strings` of valid XPath selectors.
Note that for Read operations only the first selector is evaluated.
For Insertion operations, this points to the parentNode/ownerNode to have the new elements/attributes inserted into.
#### action.value (only Insert and Update) Type: `String` or `Function(node?)` returning a `String`
For Updates, this function is passed the selected node.
For Insertions, this function is passed the selected parentNode/ownerNode.
#### action.node (only Insert) Type: `String`
The name of the node to be inserted, e.g. "my-node"
to insert <my-node/>
into, or "@myattr"
to add the myattr
attribute to the node(s) selected with action.xpath
. Can also contain an XPath index (NOTE: unlike JavaScript Arrays ,XPath is 1-index) which is stripped from the name upon node creation, in order to create more than one of a kind:
actions: type: 'I' xpath: '/cds' node: 'cd' value: 'Slayer' type: 'I' xpath: '/cds' node: 'cd' value: 'More Slayer'
Would find that /cds/cd
already exists after the first insertion, and instead update its value (compare: mysql insert on duplicate key update).
actions: type: 'I' xpath: '/cds' node: 'cd[1]' value: 'Slayer' type: 'I' xpath: '/cds' node: 'cd[2]' value: 'More Slayer'
Would correctly insert two different CDs, the index being optional in the first line.
#### action.saveAs (only Read) Type: `String`
The key with which to save the retrieved value(s) in `grunt.option`. If set to `myFoo`, the value can later be retrieved by calling `grunt.option('myFoo')`. Note that the value saved can be a string if only one node was found, or an array of strings if more than one were found. This behaviour can be overridden using `action.returnArray`.
#### action.returnArray (only Read) Type: `String`
Always saves an array in `grunt.option`, even if only a single node was matched. I.e. turns `"result"` into `["result"]`
#### action.callback (only Read) Type: `Function`
A post-processor for the extracted value(s) if you will. Applied the the extracted values before saving them in `grunt.option`.
Examples:
{ // readValues := "100" // Typecast to int before storing return ;} { // readValues := ["A", "B"] if readValueslength < 3 // Return null to throw a grunt.error and abort the task // grunt.log.verbose("Aborting because there were only 2 nodes, expecting: 3+"); return null; return readValues;} { // readValues := null if readValues === null // Prevent grunt from throwing an Error because no nodes matched // grunt.log.verbose("Config elem not found, using default"); return grunt;; return readValues;}
### Task Options #### options.actions Type: `Array`, Default value: `undefined`
An array of Action
objects, see Actions Options.
Examples:
actions: // Delete all <foo> nodes type: 'D' xpath: '//foo' // Insert <baz> into all <baz> under /myroot type: 'I' xpath: '/rootelem/bar' node: 'baz' // Add an athe foobar="100" attribute to them type: 'I' xpath: '/rootelem/bar/baz' node: '@foobar' value: '100' // Change it to 200 for the second of those <baz>, type=update assumed as default xpath: '/rootelem/bar/baz[2]/@foobar' value: '200' // Read the value of the foobar attr from the 5th overall occurence of <baz>, // Save it in grunt.option as "myData" type: 'R' xpath: '//baz[5]/@foobar' saveAs: 'myData' }
Alternatively, the reads
, deletions
, insertions
and updates
/replacements
shorthands can be used instead of actions
. That way you don't have to specify the action type manually.
The config arrays are processed in the order reads, deletions, insertions, replacements || updates, actions.
options.updates (alias: options.replacements)
Type: Array
,
Default value: undefined
An Array of Update Actions. action.type
is set automatically.
options.deletions
Type: Array
,
Default value: undefined
An Array of Deletion Actions. action.type
is set automatically.
options.reads
Type: Array
,
Default value: undefined
An Array of Read Actions. action.type
is set automatically.
options.insertions
Type: Array
,
Default value: undefined
An Array of Insertion Actions. action.type
is set automatically.
### Usage Examples #### Example - Basic Updates In this example, the text content of an element is set to a static value. So if the `test.xml` file has the content ``, the generated result would be `123`. ```js grunt.initConfig({ xmlstoke: { setTheNumber: { options: { actions: [{ xpath: '/abc', value: '123' }, { xpath: '/abc/@attr', value: '2' }], } files: { 'dest/output.xml': 'src/test.xml' } }, }, }) ```
Example - Update with function as value
In this example, the value of an attribute is modified. So if the test.xml
file has the content <x y="abc" />
, the generated result in this case would be <x y="ABC" />
.
grunt
Example - Multiple XPath Selectors
In this example, the same value is updated in multiple locations. So if the testing.xml
file has the content <x y="999" />
, the generated result in this case would be <x y="111">111</x>
.
grunt
Example - Deleting Nodes
Given <x><a /><a /><b /><c /></x>
, will delete all matched nodes and return <x></x>
(<x />
)
grunt
Example - Inserting Elements and Attributes
Given <x a="1"></x>
, returns <x a="2"><foo bar="baz"/></a>
. Notice how an Insertion just performs an update if the node exists already as seen with the @a
attribute
grunt
Example - Namespaces and Reads
This example covers both basic Reads and namespaces. options.namespaces
must be specified whenever operations inolve namespaces. After that, simply use the usual ns:elemName
or ns:attrName
syntax everywhere.
Given <RDF><foo>A</foo><em:bar>B</em:bar></RDF>
, persists the values read from the tags in grunt.option, then retrieves them in value callbacks in order to swap them in the resulting XML: <RDF><foo>B</foo><em:bar>A</em:bar></RDF>
)
grunt
## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
Release History
- 0.1.0
— Initial release - 0.2.0
— Multiple replacements at once - 0.2.1
— Color filename when logged - 0.3.0
— Allow specifying replacement value as a function - 0.4.0
— Allow specifying namespaces - 0.5.0 (point of fork from grunt-xmlpoke)
— Allow adding elements or attributes viainsertions
option - 0.5.1
— Bugfixes - 0.5.2
— Allow [index] selection for insertion xpath (stripped from name for actual element creation)
— Allow removing elements viadeletions
option (barely tested) - 0.6.0
— Code cleanup - 0.7.0
— Fixed deleting attribute nodes
— Addedupdates
option as an alias forreplacements
— Addedreads
option to extract node values by xpath and save them togrunt.option
— Addedactions
option as a series of CRUD actions in arbitrary order
— Added tests for deletions, reads and new alias parameters
— TODO: Add tests for expected error scenarios