-
Notifications
You must be signed in to change notification settings - Fork 1
Api Reference
Damn Simple XML (DSX) is an XML serialization library meant to ease programmer's life. To use this module, install it using npm install damn-simple-xml
and then do require("damn-simple-xml")
to obtain the serializer constructor.
DSX behavior is similar to that of .NET serialization. As of today, we already support a declarative way to specify attribute fields and array items. Moreover, there is currently a way to obtain interleaved text within a set of given node with the _text
auto property. The next release shall support a fully declarative way to deserialize inline text like the XmlTextAttribute
class does in .NET.
The version 0.6 includes many breaking changes compared to the version 0.5 of the library. We did that to get back in-line with actual NodeJS existing standards and to ease declaration of field attributes and array items. We are truly sorry for impacts on your project but since this is my first node open source project, I wanted to get inline with most obvious generally accepted standards like (err, callback) asynchronous function calls as soon as possible. Breaking changes are in-line with Semantic Versioning 2.0 specifications for product version 0.x but its always a mess for the good coder who wants to stay on top.
Just like in .NET serialization, a DSX serializer is declared for a particular type of object. Since Javascript is not typed and don't have attribute / annotation mechanism, we use the constructor to inform the serializer of what needs to be serialized as attribute and what are the name of arrays and array items. See this example:
var Serializer = require("damn-simple-xml");
var serializer = new Serializer(
arrays: {
"organization.employees": "employee"
},
attributes: {
"organization.employees.employee": ["id", "number"]
}
);
In the preceding example, the serializer
constructor makes it tightly binded to the "organization" structure and will fall back to the default behavior for any other object not having the correct structure. Note that behavior declaration must be fully qualified, which means that the targeted field have to be named from the XML root stand point up to the field.
DSX default behavior is to dump every object's fields as XML elements and any field named _text
as in-line text within the current XML element.
The constructor creates a serializer instance using the optional behavior
object.
- behavior
- arrays
- attributes
See the serializer.behavior section for details.
Tells serialize
and deserialize
methods how to behave with fields or XML elements. The behavior
object contains two fields:
The arrays
field is a map relating a field path with its child items. The key must be the complete path to the corresponding field name, including all parents up to the XML root element name separated by dots(.) (that was the field path definition). The value part is the name of the array item.
A behavior
object example with two defined array fields:
var Serializer = require("damn-simple-xml");
var serializer = new Serializer({
arrays: {
"organization.employees": "employee",
"organization.customers": "customer"
}
});
When deserializing XML and encountering the employees
element inside the root element named organisation
, a JavaScript array will be created and each child elements will be added to that array (regardless of the element and array item name). When serializing, each children of the employees
will be serialized inside an employee
XML element. The same goes for customers
.
The attributes
field is a map between a field path and an array of field names to be serialized as attributes within the parent element. An attribute can be of any basic type and of the Date
type. Objects and arrays are prohibited and an error object will be returned in the callback function if such a field would be declared as an attribute. The attribute
behavior have no effect on deserialization.
A behavior
object example with attributes field definitions:
var Serializer = require("damn-simple-xml");
var serializer = new Serializer({
arrays: {
"organization.employees": "employee",
"organization.employees.employee.emails": "email"
}
attributes: {
"organization.employees.employee.emails.email": ["type"]
}
});
When deserializing and encountering the field type
inside the email
field of the organization
object hierarchy, the attribute type
will be added to the email
element with its corresponding value between double quotes(").
Generates XML given the root name and data.
-
root
- name: The name of the root element where the data object will be serialized.
- data: The object to be serialized.
-
callback: a function(err, xml) called when the serialization is complete. If an error occurs, the
err
parameter will contain the an Error object detailing the issue. If successful, the err parameter will be null and the serialization result inside thexml
parameter.
Warning! The actual serialize(root, callback)
method is synchronous. It will blcok until the callback function provided terminate its execution. We are actually working to make it asynchrosous for the next release.
The serialization dumps every elements one after the other in one long line. This is a design choice. We consider XML content beatification out of scope of the current library. To make the resulting XML human readable (quite easier to debug), just copy-paste the resulting XML data inside Notepad++ and format it using the XML plug-in. If you are working on some other OS than Windows (as I do most of the time) there is a plethora of XML formatter around the Web for your convenience.
By default, if no behavior
object is specified at construction, the root.data
object will be serialized in a root.name
element. After that, each fields of the root.data
object will be recursively serialized in an element of the same name.
When serializing, if there is no array field definition corresponding to the current array field name in the serializer behavior
object, array items will be named according to the parent item name concatenated with "Item". For example:
serializer.serialize({
name: "employees",
data: [
{
id: 123,
department: "Marketting",
fullname: "John Doe"
},
{
id: 456,
department: "Administration",
fullname: "Jane Doe"
}
]
});
will result in (XML data is formatted for the example purpose):
<employees>
<employeesItem>
<id>123</id>
<department>Marketting</department>
<fullname>John Doe</fullname>
</employeesItem>
<employeesItem>
<id>456</id>
<department>Administration</department>
<fullname>Jane Doe</fullname>
</employeesItem>
</employees>
The following example shows how to control both array names and attributes with the following behavior
object given to the constructor:
var Serializer = require("damn-simple-xml");
var serializer = new Serializer({
arrays: {
"employees" : "employee"
},
attributes: {
"employees.employee": ["id", "department"]
}
});
will result in:
<employees>
<employee id="123" department="Marketting">
<fullname>John Doe</fullname>
</employee>
<employee id="456" department="Administration">
<fullname>Jane Doe</fullname>
</employee>
</employees>
Creates a JavaScript object based on the xml
parameter.
- xml: The XML string to be deserialized into an object.
-
callback: a function(err, root) called when the deserialization is complete. If an error occurs, the
err
parameter will contain the an Error object detailing the issue. If successful, the err parameter will be null and the deserialization result will be in theroot
object. See root object documentation.
Deserialization will consider all attributes and sub nodes of the current element as fields of the currently deserialized object. Each values are parsed and automatically cast to the type they are the most likely to be.
In the absence of a corresponding behavior.arrays
field path definition, when an XML element is encountered and there is already a corresponding field in the deserialized object, the parent field is changed from an object to an array containing both XML elements. Each other child element will then be deserialized as an array item of the current field, regardless of its name. This behavior is called automatic array discovery. This example should make that point clear:
XML string:
<employee id="123">
<firstName>John</firstName>
<lastName>Doe</lastName>
<dateOfBirth>1984-03-12T00:00:00.000Z</dateOfBirth>
<languages>
<language>Java</language>
<language>C++</language>
<language>C#</language>
<language>JavaScript</language>
</languages>
</employee>
root.data
:
{
id: 123,
firstName: "John",
lastName: "Doe",
dateOfBirth: "1984-03-27T00:00:00.000Z",
languages: ["Java", "C++", "C#", "JavaScript"]
}
Given the absence of a second element with the same name, the following deserialized object will occurs:
<employee id="123">
<firstName>John</firstName>
<lastName>Doe</lastName>
<dateOfBirth>1984-03-12T00:00:00.000Z</dateOfBirth>
<languages>
<language>Java</language>
</languages>
</employee>
root.data
:
{
id: 123,
firstName: "John",
lastName: "Doe",
dateOfBirth: "1984-03-27T00:00:00.000Z",
languages: {
language: "Java"
}
}
To prevent this, all arrays should be declared beforehand with the following behavior.arrays
:
var Serializer = require("damn-simple-xml");
var serializer = new Serializer({
arrays: {
"employee.languages": "language"
}
})
The deserialize
function needs that the arrays
object returns a "truish" value (non-null and non-empty string) when checking for behavior.arrays[fieldPath]
. The actual array item name part is used only for serialization purpose.
So given the behavior
in the previous example, the resulting employee.languages
field will turn back to the expected array.