First, a warning
We use semver, and we're starting at 1.0.0 in order to easily communicate API changes, without breaking semver.
However, it's still beta and should be used with caution.
xml-js-converter
Convert between an XML string and JavaScript objects (in both directions), following a specific schema.
If you only need a generic conversion, you will probably find https://www.npmjs.com/package/xml2js or https://www.npmjs.com/package/xml2json suits your needs better.
What xml-js-converter
allows you to do, is specify the way in which certain nodes are converted.
For instance, say you had the following XML:
Alan Turing
What you might want in JavaScript is
person: id: '195' firstName: 'Alan' lastName: 'Turing'
So the id attribute is a property, but so is the sub-element firstName. Converting back should obviously do the same thing, so from the given JavaScript object, you get the same XML back.
Collections / arrays
Say you had the following XML
Alan Turing Computer theory Code breaking
(The skills list is by no means exhaustive!)
What you can obtain with xml-js-converter
is the following JavaScript object:
person: id: '195' firstName: 'Alan' lastName: 'Turing' skills: skill: id: 'CS101' name: 'Computer theory' skill: id: 'ENIG1' name: 'Code breaking'
Notice the extra "skill" object - ie. an object with a single property "skill". This is so that you can have an array of sub-elements with different tag names. For instance:
Alan Turing Computer theory Cracked the Enigma code
And end up with the JavaScript:
person: id: '195' firstName: 'Alan' lastName: 'Turing' attributes: skill: id: 'CS101' name: 'Computer theory' achievement: id: 'ENIG1' name: 'Code breaking'
Usage
npm install xml-js-converter
var xmlJsConverter = ;
fromXml
fromXml(xmlAsString, specification, callback)
Where callback is function (err, value) { ... }
, err is null unless there was an error,
and value is the javascript object. specification
is defined in the next section.
xmlJsConverter.fromXml('<demo>text content</demo>', {}, function (err, value) {
// value == { demo: { $content: 'text content' } }
});
toXml
toXml(jsObject, specification, callback)
Where callback is function (err, value) { ... }
, err is null unless there was an error,
and value is a string with the XML.
Specification
The specification can be an empty object. Otherwise each property can define how to handle that tag name.
For instance:
test: {}
Would be a (useless, ie. "non-effect having") specification for:
some content
This would result in
test: $content: 'some content'
$content
is the default name for the content of a tag. You can override this in the spec by setting $content.
$content
Set to a string to name the content property. e.g.
var spec = test: $content: 'name' ; xmlJsConverter;
Set to false
to suppress the content. Note that attributes of the node will then be skipped,
as there is nowhere to define them.
e.g.
var spec = test: $content: false ; xmlJsConverter;
To define $content
for deeply nested elements, simply define the path to the elements.
e.g.
var spec = test: name: firstName: $content: false lastName: $content: false ; xmlJsConverter;
$arrayElement
Set to true to include the children as an array. Each child node will be an object with a single property with the name of the tag, and then follow the conventions of sub-schema.
Note that the array will be the $content property, unless $content is also specified (either set as a name or to false to discard the attributes).
From the example above:
Alan Turing Computer theory Cracked the Enigma code
To obtain the following JavaScript:
person: id: '195' firstName: 'Alan' lastName: 'Turing' attributes: skill: id: 'CS101' name: 'Computer theory' achievement: id: 'ENIG1' name: 'Code breaking'
You'd use the specification:
var spec = person: firstName: $content: false lastName: $content: false attributes: $arrayElement: true $content: false achievement: $content: 'name' skill: $content: 'name' ;
Note how the $arrayElement
is true, and also $content
is false for the attributes
element.
This suppresses the $content property for the array. $content for array elements works exactly
the same as normal elements.
The specs for achievement
and skill
will be used for every achievement
and skill
element
in the parent element. If an unknown element occurs, it will simply use a default specification ({}
)
Contributing
Bugs, pull requests, comments all very welcome.
The tests are written in mocha, using the excellent unexpected assertion library.
To run the tests, just call
npm test
Versioning
We follow semver. We have started at version 1.0, not symbolise "production ready", but to effectively communicate changes.
Roadmap
Things we'd like soon:
- Support for numeric types
- Support to automatically case-switch (e.g. PascalCase in XML and camelCase in JS)
Things we'd like eventually:
-
Support for naming nodes differently in JS and XML
-
Support for dropping the wrapper on arrayElements e.g. from
To be transformed to
people: name: 'monica' name: 'steve'
- Support for using an attribute as the "content" e.g. from
To be transformed to
director: person: 'tim cook'
This would also enable the people
array in the previous example to be transformed to a simple array of strings.