xml-artist
v2.0.11
Published
Read, manipulate and render xml files like an artist
Downloads
7
Maintainers
Readme
Clean wrapper around the sax
library to read, manipulate and render xml files like an artist.
Quick example :
<!-- input.xml -->
<heroes>
<hero:ally name="Foo"/>
<hero:enemy name="Bar"/>
<hero:enemy/>
</heroes>
const XML = require('xml-artist')
// we get the data from the given xml file
const data = XML.parseFile('input.xml')
// we find all nodes which name begin with `hero:` and which have the attribute `name`
// and we replace them by some text
for (const node of data.findAll('hero:*', ['name']))
node.replaceWith(`I'm a hero and my name is ${node.attributes.name}`)
// we write the transformed xml to an output file
data.toXmlFile('output.xml')
<!-- output.xml -->
<heroes>
I'm a hero and my name is Foo
I'm a hero and my name is Bar
<hero:enemy/>
</heroes>
Read more to discover the awesome versatility and ease-of-use of the library.
Parse/read xml
There are several ways to create the data tree from xml data :
const XML = require('xml-artist')
// with template strings
const data = XML `
<heroes>
<hero:ally name="Foo"/>
<hero:enemy name="Bar"/>
<hero:enemy/>
</heroes>
`
// with the parse function
const data = XML.parse(xmlString, options?)
// read from a file
const data = XML.parseFile(filename, options?)
// create a node and then parse content
const { XmlNode } = XML
const root = new XmlNode
root.parse(xmlString, options?)
You can also get your XmlNode
tree from previously created JSON data :
const data = XML.parse(xmlString)
const json = data.toJson()
const sameDataButFromJson = XML.parseJson(json)
Options
The default options are :
{
// set to false if you want to parse non-strict xml
strict: true,
// whether or not to trim text and comment nodes
// (if you intend to pretty print, you should set it to true)
trim: false,
// if true, turn any whitespace into a single space
normalize: false,
// if true, lowercase tag and attribute names
// instead of uppercasing
lowercase: true,
// if true, only parse predefined XML entities
// (& ' > < and ")
strictEntities: false,
}
The XmlNode object
Properties
class XmlNode {
name : String
attributes : { [key : String] : String }
children : [ XmlNode | String ]
parent? : XmlNode
processingInstructions? : [ { name: String, body: String} ]
}
Every XmlNode
has the field children
which can contain plain text or other XmlNode
s.
The processingInstructions
field is not always defined and contains the name
and body
informations of tags which have the form : <?${name} ${body}?>
.
Constructor
The constructor takes as single argument a XmlNode-like object :
const { XmlNode } = XML
let node = new XmlNode({
name: "foo",
attributes: {
bar: 1234
}
})
node.pushTo(data)
Finder methods
find(name: String|RegExp)
: return the first XmlNode with the matching name, ornull
if no result is found.find(attributes: [String])
: same, but take an array of attributes as argument. Exemple :find(['id', 'class=foo*'])
will find the first node which have the attributeid
and a value beginning by 'foo' for the attributeclass
.find(name: String|RegExp, attributes: [String])
: same, but with conditions on the name and the attributes.find(callback: Function)
: You can also specifiy your own function to match the desired node. Your function must return the node itself it is valid, or a null value otherwise.
Every string passed to these functions will be transformed into regular expressions with this very simple rule : all *
characters will be treated as .*
Be aware that if you use special characters (like [
, ]
) they will be treated as part of the regular expression unless you double-escape them.
The following finder functions all take the same argument(s) :
findAll
: return an array of nodes instead of the first one.findChild
: do not search recursively, only amongst direct children. Return the first result.findAllChildren
: Return all the result amongst direct children only.findParent
: Return the first matching parent.findAllParents
: Return an array of all matching parents (closer parents first).
Walk methods
xmlNode.walk({
node(xmlNode) {...},
text(value, xmlNodeParent) {...},
comment(value, xmlNodeParent) {...},
cdata(value, xmlNodeParent) {...},
doctype(value, xmlNodeParent) {...},
})
You pass an object to the walk
function that can have up to five callback functions, one for each type of child a xmlNode can have.
If a non-null (ie not null
and not undefined
) value is returned by one of the callback functions, the walking stops and this value is returned by the walk
method.
If you need to pass asynchronous functions as callbacks, call the asynchronous version of the walker :
await xmlNode.asyncWalk({
async node(xmlNode) {...},
async text(value, xmlNodeParent) {...},
async comment(value, xmlNodeParent) {...},
async cdata(value, xmlNodeParent) {...},
async doctype(value, xmlNodeParent) {...},
})
When using asyncWalk
, you can mix async
and sync
callbacks.
Tree mutator methods
push(element: XmlNode|String, before?: Integer|XmlNode)
: push a new child. Thebefore
parameter indicates before which XmlNode element (or index) the new child should be pushed.push(arrayOfElements: [XmlNode|String], before?: Integer|XmlNode)
: you can also push an array of elements, which can be very handful in combination with thefindAll
method. You should use this method if you plan to push many elements at once for speed efficiency.replaceWith(element: XmlNode|String)
: replace an element by another one. Note : if the element already belonged to the tree, it is moved (not copied). If you want to create a copy, use theclone
method first.replaceWith(arrayOfElements: [XmlNode|String])
: you can also replace with an array of elements, which can be very handful in combination with thefindAll
method.clone()
: create a copy of an element. All children will be cloned too.remove()
: self-remove from the tree.removeChild(element: XmlNode|String)
: remove the given child element.pushTo(element: XmlNode, before?: Integer|XmlNode)
: move itself as a new child to the given XmlNode.empty()
: remove all children.
Renderer methods
toXml(pretty: Boolean)
: Generate XML, pretty-printed or not. If you want to pretty-print your xml, you should consider to set thetrim
option totrue
when parsing.toXmlFile(filename: String, pretty: Boolean)
: Generate XML and write it to the given file.toJson()
: Create clean and reusable JSON.
Other methods (and getters)
get innerText()
: Return the text of the node.
Be an artist