User Guide

Introduction

Take a look at this question on Stackoverflow which incepted the development of Jsonix.

Jsonix (JSON interfaces for XML) is a JavaScript library which allows you to convert between XML and JSON structures.

With Jsonix you can parse XML into JavaScript objects (this process is called unmarshalling) or serialize JavaScript objects in XML form (this is called marshalling).

These conversions are based on simple XML/JSON mappings which can be written manually or generated from an XML Schema.

Strictly speaking, Jsonix works with JavaScript objects, which are not limited to JSON. But for the sake of simplicity we'll use JSON to denote these "plain old simple JavaScript objects".

In short, with Jsonix you can:

Related projects

JAXB

Jsonix is inspired by and based on JAXB which is a great tool to convert between XML and Java objects. Jsonix is literally a JAXB analog for JavaScript.

Jsonix mappings are heavily influenced by JAXB annotations.

Jsonix schema compiler is based on XJC, schema compiler from the JAXB Reference Implementation.

Features

Working Example

This chapter demonstrates the usage of Jsonix in a classic "purchase order" example.

Assume you need to develop a JavaScript program which should process an XML in the following XML Schema:

Here's an example of XML for this schema:

<purchaseOrder orderDate="1999-10-20">
  <shipTo country="US">
    <name>Alice Smith</name>
    <street>123 Maple Street</street>
    <city>Mill Valley</city>
    <state>CA</state>
    <zip>90952</zip>
  </shipTo>
  <billTo country="US">
    <name>Robert Smith</name>
    <street>8 Oak Avenue</street>
    <city>Old Town</city>
    <state>PA</state>
    <zip>95819</zip>
  </billTo>
  <comment>Hurry, my lawn is going wild!</comment>
  <items>
    <item partNum="872-AA">
      <productName>Lawnmower</productName>
      <quantity>1</quantity>
      <USPrice>148.95</USPrice>
      <comment>Confirm this is electric</comment>
    </item>
    <item partNum="926-AA">
      <productName>Baby Monitor</productName>
      <quantity>1</quantity>
      <USPrice>39.98</USPrice>
      <shipDate>1999-05-21</shipDate>
    </item>
  </items>
</purchaseOrder>

Usage example

Here's how you would parse this XML document with Jsonix:

// The PO variable provides Jsonix mappings for the purchase order test case
// Its definition will be shown in the next section

var PO = { };

// ... Declaration of Jsonix mappings for the purchase order schema ...

// First we construct a Jsonix context - a factory for unmarshaller (parser)
// and marshaller (serializer)
var context = new Jsonix.Context([ PO ]);

// Then we create an unmarshaller
var unmarshaller = context.createUnmarshaller();

// Unmarshal an object from the XML retrieved from the URL
unmarshaller.unmarshalURL('/org/hisrc/jsonix/samples/po/test/po-0.xml',
	// This callback function will be provided with the result
	// of the unmarshalling
	function(result) {
		// We just check that we get the values we expect
		assertEquals('Alice Smith', result.value.shipTo.name);
		assertEquals('Baby Monitor', result.value.item[1].productName);
	});

The callback function will receive the result of the unmarshalling in a form of a JavaScript object. Here's approximately how it would look like in a JSON form:

{
	name : {
		localPart : "purchaseOrder"
	},
	value : {
		orderDate : new Date(1999, 10, 20),
		shipTo : {
			name : "Alice Smith",
			street : "123 Maple Street",
			city : "Mill Valley",
			state : "CA",
			zip : 90952,
			country : "US"
		},
		billTo : { ... },
		comment : 'Hurry, my lawn is going wild!',
		item : [ { ... }, {
			partNum : '926-AA',
			productName : 'Baby Monitor',
			quantity : 1,
			usPrice : 39.98,
			shipDate : new Date(1999, 4, 21)
		} ]
	}
}

Here's how marshalling of a JavaScript object into XML would look like:

// Marshal a JavaScript Object as XML (DOM Document)
var unmarshaller = context.createUnmarshaller();

var doc = marshaller.marshalDocument({
	name: { localPart: "purchaseOrder" },
	value: {
		orderDate : new Date(1999, 10, 20),
		shipTo: {
			name: "Alice Smith",
			street: "123 Maple Street",
			city: "Mill Valley",
			state: "CA",
			zip: 90952,
			country : "US"
		}
		// ...
	}
});

Defining mappings

Now let us take a look at the XML/object mappings, the part we skipped previously:

PO = {};
// Declare types
PO.PurchaseOrderType = new Jsonix.Model.ClassInfo({
	name : "PO.PurchaseOrderType"
});
PO.USAddress = new Jsonix.Model.ClassInfo({
	name : "PO.USAddress"
});
PO.Item = new Jsonix.Model.ClassInfo({
	name : "PO.Item"
});
// Declare properties
PO.PurchaseOrderType.properties = [ new Jsonix.Model.ElementPropertyInfo({
	name : "shipTo",
	typeInfo : PO.USAddress
}), ..., new Jsonix.Model.ElementPropertyInfo({
	name : "item",
	typeInfo : PO.Item,
	collection : true,
	wrapperElementName : new Jsonix.XML.QName("items")
}), new Jsonix.Model.AttributePropertyInfo({
	name : "orderDate",
	typeInfo : Jsonix.Schema.XSD.Date.INSTANCE
}) ];
//
PO.USAddress.properties = [ new Jsonix.Model.ElementPropertyInfo({
	name : 'name',
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
}), new Jsonix.Model.ElementPropertyInfo({
	name : 'street',
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
}), ... ];
//
PO.Item.properties = [ new Jsonix.Model.ElementPropertyInfo({
	name : 'productName',
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
}), ... ];

PO.typeInfos = [ PO.PurchaseOrderType, PO.USAddress, PO.Item ];
PO.elementInfos = [ {
	elementName : new Jsonix.XML.QName('purchaseOrder'),
	typeInfo : PO.PurchaseOrderType
}, ... ];

Basically, Jsonix mappings is a JavaScript program which describes how XML constructs (simple and complex types, elements, attributes) should be represented in object form. From the other hand, Jsonix mappings define the target object structure: objects, properties, their types and cardinalities. XML/object mappings are required to guarantee strongly-structured and strongly-typed mapping.

Generating mappings from an XML Schema

As we've seen above, Jsonix needs XML/object mappings to operate. These mappings can be created manually, they are just simple JavaScript programs which use Jsonix API.

There is, however, another possibility for creating Jsonix mappings: you can generate them automatically from an XML Schema. Jsonix provides a schema compiler which take an XML Schema as input and generates Jsonix mappings for it. So instead of writing PO.js per hand you can generate it from an XML Schema (po.xsd) using the Jsonix schema compiler:

java
  -jar jsonix-full-<VERSION>.jar // Run executable Java archieve
  -d src/main/webapp/js // Target directory
  po.xsd // Schema

Mapping XML to JavaScript Objects

Jsonix needs XML/object mappings to operate. These mappings can be created manually or generated from an XML Schema. Either way, they are just simple JavaScript programs which use Jsonix API. This sections explains concepts of these mappings and describes how to create them.

Basic concepts

Jsonix mappings are defined in a module object which provides information about declared types and XML elements which they are mapped to. Below is a very simple module One which declares a complex type One.ValueType (containing a single property value) and maps this type to the global XML element value:

One = {};

One.ValueType = new Jsonix.Model.ClassInfo({
	name : 'One.ValueType'
});
One.ValueType.properties = [ new Jsonix.Model.ValuePropertyInfo({
	name : 'value',
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
}) ];
One.elementInfos = [ {
	elementName : new Jsonix.XML.QName('value'),
	typeInfo : One.ValueType
} ];

Provided this module object, we can create a Jsonix context and use it for marshalling or unmarshalling:

var context = new Jsonix.Context([ One ]);
var unmarshaller = context.createUnmarshaller();

Now we can enumerate basic components of Jsonix mappings:

These components will be described in the following sections

Modules

In the previous section we've seen a declaration of module One. Here's even simpler module:

Two = {
	elementInfos : [ {
		elementName : new Jsonix.XML.QName('string'),
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	} ]
};

This module maps the XML element string to the string type. With this module, we'd unmarshal the following XML:

<string>test</string>

Into the following JavaScript object:

{
	name : { localPart : 'string' },
	value : 'test'
}

Modules is a JavaScript object which contains a property named elementInfos. This property must be an array-valued property which lists element mappings declared by this module.

Apart from this required elementInfos property, modules may also declare types - just like the module One declared the type One.ValueType.

There are no specific requirements for how exactly the module object should be built. Below is a recommended flow:

// Declare the module object
MyModule = {};

// Declare types
MyModule.MyType = new Jsonix.Model.ClassInfo( ... );

// Declare properties
MyModule.MyType.properties = [ ... ];

// Declare element mappings
MyModule.elementInfos = [ {
        elementName: new Jsonix.XML.QName('myElement'),
        typeInfo: MyModule.MyType
    }, ... ];

This structure is mainly driven by the fact that you can't use the type object before you declare it. That's why types are declared before properties (which may need to use these types).

Element declarations

Every valid XML document has a single root element which is called the document element. When unmarshalling an XML document, Jsonix runtime needs to know onto which type does the root element of this document map. For instance that the element value maps onto the type One.ValueType in the module One.

This mapping is defined by the elementInfos property of the module object. The elementInfos property is an array of element declarations. Each element declaration is an object with the following structure:

{
    // Qualified name of the element
    name: new Jsonix.XML.QName('urn:myNamespaceURI', 'myLocalPart'),
    // Target type of the element
    typeInfo: MyModule.MyType
}
Element declaration has two more options, scope and substitutionHead which will be explained later on.

Element mapping defined above maps an element like:

<my:myLocalPart xmlns:my="urn:myNamespaceURI" ...>
    ...
</my:myLocalPart>

onto the type MyModule.MyType declared in the MyModule module. So when Jsonix unmarshals such an element it will produce a result like:

{
    name : { namespaceURI : 'urn:myNamespaceURI', localPart: 'myLocalPart'},
    value : {
        // Contents according to the MyModule.MyType  
    }
}

You mostly need to declare only your global elements in MyModule.elementInfos. All other elements, attributes etc. mappings are done via properties.

However, you may also need to use MyModule.elementInfos to declare scoped elements.

Types

A concept of type is a central concept in Jsonix mappings. Element declarations map XML elements onto types; most of the properties have a target type and so on.

Jsonix distinguished two categories of types: simple and complex types. The difference between them is that complex types contain properties whereas simple types don't.

Either way, types can convert between XML structures (elements, attributes, character data) and JavaScript structures (objects, arrays, strings, numbers etc.).

Simple types

Simple types convert between character data on XML side and primitive or basic types on the JavaScript side. For instance, Jsonix boolean type converts between "true" or "false" text on XML side and true or false boolean values on JavaScript:

Jsonix.Schema.XSD.Boolean = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, { ...,

	print : function(value) {
		Jsonix.Util.Ensure.ensureBoolean(value);
		return value ? 'true' : 'false';
	},
	parse : function(text) {
		Jsonix.Util.Ensure.ensureString(text);
		if (text === 'true') {
			return true;
		} else if (text === 'false') {
			return false;
		} else {
			throw "Either [true] or [false] expected as boolean value.";
		}
	}, ...
};

Jsonix provides supports most simple types defined in the XML Schema out of the box. You can also define your own simple types using derivation by list, by union, defining enumerations or writing a custom simple type.

Built-in simple types

Jsonix supports most simple types defined in the XML Schema. These types are called built-in simple types and are based on the following hierarchy of types:

To support this hierarchy, Jsonix declares an individual JavaScript class for each of these types. Each of the classes also has a pre-instantiated instance (ex. Jsonix.Schema.XSD.String.INSTANCE). Below is the type mapping table:

XML Schema Type JavaScript Class Instance
anySimpleType Jsonix.Schema.XSD.AnySimpleType Jsonix.Schema.XSD.AnySimpleType.INSTANCE
string Jsonix.Schema.XSD.String Jsonix.Schema.XSD.String.INSTANCE
normalizedString Jsonix.Schema.XSD.NormalizedString Jsonix.Schema.XSD.NormalizedString.INSTANCE
token Jsonix.Schema.XSD.Token Jsonix.Schema.XSD.Token.INSTANCE
language Jsonix.Schema.XSD.Language Jsonix.Schema.XSD.Language.INSTANCE
Name Jsonix.Schema.XSD.Name Jsonix.Schema.XSD.Name.INSTANCE
NCName Jsonix.Schema.XSD.NCName Jsonix.Schema.XSD.NCName.INSTANCE
boolean Jsonix.Schema.XSD.Boolean Jsonix.Schema.XSD.Boolean.INSTANCE
base64Binary Jsonix.Schema.XSD.Base64Binary Jsonix.Schema.XSD.Base64Binary.INSTANCE
hexBinary Jsonix.Schema.XSD.HexBinary Jsonix.Schema.XSD.HexBinary.INSTANCE
float Jsonix.Schema.XSD.Float Jsonix.Schema.XSD.Float.INSTANCE
decimal Jsonix.Schema.XSD.Decimal Jsonix.Schema.XSD.Decimal.INSTANCE
integer Jsonix.Schema.XSD.Integer Jsonix.Schema.XSD.Integer.INSTANCE
nonPositiveInteger Jsonix.Schema.XSD.NonPositiveInteger Jsonix.Schema.XSD.NonPositiveInteger.INSTANCE
negativeInteger Jsonix.Schema.XSD.NegativeInteger Jsonix.Schema.XSD.NegativeInteger.INSTANCE
long Jsonix.Schema.XSD.Long Jsonix.Schema.XSD.Long.INSTANCE
int Jsonix.Schema.XSD.Int Jsonix.Schema.XSD.Int.INSTANCE
short Jsonix.Schema.XSD.Short Jsonix.Schema.XSD.Short.INSTANCE
byte Jsonix.Schema.XSD.Byte Jsonix.Schema.XSD.Byte.INSTANCE
nonNegativeInteger Jsonix.Schema.XSD.NonNegativeInteger Jsonix.Schema.XSD.NonNegativeInteger.INSTANCE
unsignedLong Jsonix.Schema.XSD.UnsignedLong Jsonix.Schema.XSD.UnsignedLong.INSTANCE
unsignedInt Jsonix.Schema.XSD.UnsignedInt Jsonix.Schema.XSD.UnsignedInt.INSTANCE
unsignedShort Jsonix.Schema.XSD.UnsignedShort Jsonix.Schema.XSD.UnsignedShort.INSTANCE
unsignedByte Jsonix.Schema.XSD.UnsignedByte Jsonix.Schema.XSD.UnsignedByte.INSTANCE
positiveInteger Jsonix.Schema.XSD.PositiveInteger Jsonix.Schema.XSD.PositiveInteger.INSTANCE
double Jsonix.Schema.XSD.Double Jsonix.Schema.XSD.Double.INSTANCE
anyURI Jsonix.Schema.XSD.AnyURI Jsonix.Schema.XSD.AnyURI.INSTANCE
QName Jsonix.Schema.XSD.QName Jsonix.Schema.XSD.QName.INSTANCE
duration Jsonix.Schema.XSD.Duration Jsonix.Schema.XSD.Duration.INSTANCE
dateTime Jsonix.Schema.XSD.DateTime Jsonix.Schema.XSD.DateTime.INSTANCE
time Jsonix.Schema.XSD.Time Jsonix.Schema.XSD.Time.INSTANCE
date Jsonix.Schema.XSD.Date Jsonix.Schema.XSD.Date.INSTANCE
gYearMonth Jsonix.Schema.XSD.GYearMonth Jsonix.Schema.XSD.GYearMonth.INSTANCE
gYear Jsonix.Schema.XSD.GYear Jsonix.Schema.XSD.GYear.INSTANCE
gMonthDay Jsonix.Schema.XSD.GMonthDay Jsonix.Schema.XSD.GMonthDay.INSTANCE
gDay Jsonix.Schema.XSD.GDay Jsonix.Schema.XSD.GDay.INSTANCE
gMonth Jsonix.Schema.XSD.GMonth Jsonix.Schema.XSD.GMonth.INSTANCE
Although all classes are defined, not all the types are already implemented. See JSNX-1 and JSNX-2 issues.

Deriving simple types by list

In addition to atomic simple types Jsonix supports list simple types. Such list types map an array of values to string (delimiter-separated items of the array).

Here's an example of a simple type which handles a list of doubles:

Jsonix.Schema.XSD.Double.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
	Jsonix.Schema.XSD.Double.INSTANCE);
//
assertEquals('0.1 1.2 2.3', Jsonix.Schema.XSD.Double.INSTANCE.LIST
	.print([ 0.1, 1.2, 2.3 ]));
Here's XML Schema analog:
<xsd:simpleType>
	<xsd:list itemType="xsd:double"/>
</xsd:simpleType>

List types are declared using the Jsonix.Schema.XSD.List class:

var myListType = new Jsonix.Schema.XSD.List(
	// Type of the item (must be simple type), required
	typeInfo,
	// Qualified name of the type, optional, defaults to null
	typeName,
	// Separator for parsing/printing item values, optional, defaults to ' '
	separator
);
Built-in simple types typically declare a list-derived variant as MyType.INSTANCE.LIST (ex. Jsonix.Schema.XSD.Double.INSTANCE.LIST), so you don't need to create new instances of list types built-in types.

Unlike XML Schema, Jsonix allows deriving list types from non-atomic types (ex. other list types). Below is an example of a list of lists of doubles:

var typeInfo = new Jsonix.Schema.XSD.List(
	// Item type
	Jsonix.Schema.XSD.Double.INSTANCE.LIST,
	// Type name
	null,
	// Separator
	 ', ');

// Print
assertEquals('0 0, 0 1, 1 1, 1 0, 0 0',
	typeInfo.print([ [ 0, 0 ], [ 0, 1 ], [ 1, 1 ], [ 1, 0 ], [ 0, 0 ] ]));

// Parse
var parsed = typeInfo.parse('0 0, 0 1, 1 1, 1 0, 0 0');
assertEquals(5, parsed.length);
assertEquals(0, parsed[0][0]);
assertEquals(0, parsed[0][1]);
// Etc.

Deriving simple types by union

This feature is planned but not supported, see JSNX-9.

Deriving simple types by restriction

Definition of complex types by restriction is not supported at the moment.

Defining custom simple types

Type system in Jsonix is extensible, so if your requirements are not covered by the built-in simple types, you can write custom simple types to match your needs.

Jsonix requires an instance of a simple types to provide the following properties and functions:

In most cases you can just inherit from Jsonix.Schema.XSD.AnySimpleType and just implement print and parse methods. See Jsonix.Schema.XSD.Boolean for example:

Jsonix.Schema.XSD.Boolean = Jsonix.Class(Jsonix.Schema.XSD.AnySimpleType, {
	typeName : Jsonix.Schema.XSD.qname('boolean'),
	print : function(value) {
		Jsonix.Util.Ensure.ensureBoolean(value);
		return value ? 'true' : 'false';
	},
	parse : function(text) {
		Jsonix.Util.Ensure.ensureString(text);
		if (text === 'true') {
			return true;
		} else if (text === 'false') {
			return false;
		} else {
			throw "Either [true] or [false] expected as boolean value.";
		}
	},
	CLASS_NAME : 'Jsonix.Schema.XSD.Boolean'
});
Jsonix.Schema.XSD.Boolean.INSTANCE = new Jsonix.Schema.XSD.Boolean();
Jsonix.Schema.XSD.Boolean.INSTANCE.LIST = new Jsonix.Schema.XSD.List(
		Jsonix.Schema.XSD.Boolean.INSTANCE);

Complex types

Complex types are defined using the Jsonix.Model.ClassInfo class:

MySchema.MyType = new Jsonix.Model.ClassInfo({
	// Name of the complex type, required
	name: 'MySchema.MyType',
	// Array of properties, optional
	properties: [ p0, p1, p2, ... ]
});

Complex type has a name and contains a number of properties. Properties can be provided on creation or added later on:

// Somewhen in the beginning...
MySchema.MyType = new Jsonix.Model.ClassInfo({
	name: 'MySchema.MyType'
});

// ... and later on
MySchema.MyType.properties = [ p0, p1, p2, ... ];

Properties declared in a complex type define both the structure of the JavaScript object as well as structure of the XML it will be mapped onto.

Defining complex types by extension

Complex types can be defined as extensions for other content types. This is achieved by setting the baseTypeInfo property of the extending type to point to the base type. Consider the following example:

org.hisrc.jsonix.tests.zero.BaseType = new Jsonix.Model.ClassInfo({
    name: 'org.hisrc.jsonix.tests.zero.BaseType'
  });
org.hisrc.jsonix.tests.zero.ExtendedType = new Jsonix.Model.ClassInfo({
    name: 'org.hisrc.jsonix.tests.zero.ExtendedType'
  });
{
    org.hisrc.jsonix.tests.zero.BaseType.properties = [new Jsonix.Model.ElementPropertyInfo({
          name: 'alpha',
          elmentName: new Jsonix.XML.QName('alpha'),
          typeInfo: Jsonix.Schema.XSD.String.INSTANCE
        }), new Jsonix.Model.ElementPropertyInfo({
          name: 'beta',
          collection: true,
          elmentName: new Jsonix.XML.QName('beta'),
          typeInfo: Jsonix.Schema.XSD.Integer.INSTANCE
        })];
}
{
    // Make ExtendedType an extension of BasType
    org.hisrc.jsonix.tests.zero.ExtendedType.baseTypeInfo = org.hisrc.jsonix.tests.zero.BaseType;

    org.hisrc.jsonix.tests.zero.ExtendedType.properties = [new Jsonix.Model.ElementPropertyInfo({
          name: 'gamma',
          elmentName: new Jsonix.XML.QName('gamma'),
          typeInfo: Jsonix.Schema.XSD.AnyURI.INSTANCE
        }), new Jsonix.Model.ElementPropertyInfo({
          name: 'delta',
          collection: true,
          elmentName: new Jsonix.XML.QName('delta'),
          typeInfo: Jsonix.Schema.XSD.DateTime.INSTANCE
        })];
}

In this example the base type has the properties alpha and beta whereas the extended type has four properties alpha, beta, gamma and delta. This corresponds to the following XML Schema:

	<xs:complexType name="baseType">
		<xs:sequence>
			<xs:element name="alpha" type="xs:string" minOccurs="0"/>
			<xs:element name="beta" type="xs:integer" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>
	
	<xs:complexType name="extendedType">
		<xs:complexContent>
			<xs:extension base="baseType">
				<xs:sequence>
					<xs:element name="gamma" type="xs:anyURI" minOccurs="0"/>
					<xs:element name="delta" type="xs:dateTime" minOccurs="0" maxOccurs="unbounded"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>

Here's a couple of examples of XML and equivalent JavaScript objects

<base>
	<alpha>one</alpha>
	<beta>2</beta>
</base>
{
	name : new Jsonix.XML.QName('base'),
	value : {
		alpha : 'one',
		beta : [ 2 ]
	}
}
<extended>
	<alpha>one</alpha>
	<beta>2</beta>
	<gamma>urn:three</gamma>
	<delta>2004-05-06</delta>
</extended>
{
	name : new Jsonix.XML.QName('extended'),
	value : {
		alpha : 'one',
		beta : [ 2 ],
		gamma : 'urn:three',
		delta : [ new Date(2004, 4, 6) ]
	}
}

Defining complex types by restriction

Definition of complex types by restriction is not supported.

Properties

Properties define contents of a complex type. From one hand, they configure the structure of a JavaScript object which is mapped by this complex type. From the other hand, they describe, how this object will be presented in an XML form.

Jsonix allows you to map character content, attributes and elements using following property types:

Basic property characteristics

Property types enumerated above have different functionality. However, there are some basic characteristics shared by most properties.

Property name

Every property must have a name (string). Primary function of this name is to define the name of the matching JavaScript object property.

Consider the following example:

new Jsonix.Model.ElementPropertyInfo({
          name: 'alpha',
          elmentName: new Jsonix.XML.QName('beta'),
          typeInfo: Jsonix.Schema.XSD.String.INSTANCE
        })

The property named alpha is mapped to the element beta. So if we'll unmarshal the following element:

<someElement ...>
  <beta>a</beta>
</someElement>

We'll get an alpha property in the JavaScript object:

{
   // Some data ...
   // Property 'alpha'
   alpha: 'a'
}
Name of the property is also used by attribute, element and element reference properties to default the target XML attribute or element names if they are omitted.

Property cardinality

Element properties also have the cardinality characteristic; they can be collection or single properties.

Value, attribute and any attribute properties are always single.

Collection properties handle repeatable elements.

Consider this simple property:

new Jsonix.Model.ElementPropertyInfo({
	name : "element",
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
})

This will unmarshal the following XML:

<someElement ...>
  <element>a</element>
</someElement>

Into the following JavaScript object:

{  
   element : 'a'
}

Now, we can make this property collection:

new Jsonix.Model.ElementPropertyInfo({
	name : "element",
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE,
	collection : true
})

And then be able to process repeatable elements:

<someElement ...>
  <element>a</element>
  <element>b</element>
  <element>c</element>
</someElement>

JavaScript property value will in this case be an array:

{  
   element : ['a', 'b', 'c']
}

Mixed properties

Some of the properties (namely Element reference/references and any element properties) can be declared as mixed. Mixed properties can handle elements together with character content. Consider the following example:

new Jsonix.Model.ElementRefPropertyInfo({
	name: 'content',
	collection: true,
	mixed: true,
	elementName: new Jsonix.XML.QName('value'),
		typeInfo: Jsonix.Schema.XSD.String.INSTANCE
})

Here's an example of XML:

<elementRefMixed>
	<value>a</value>b<value>c</value>
</elementRefMixed>  

And the equivalent JavaScript object:

{
	content : [
		{
			name : new Jsonix.XML.QName('value'),
			value : 'a'
		},
		'b',
		{
			name : new Jsonix.XML.QName('value'),
			value : 'c'
		}
	]
}

Wrapper elements

A common XML Schema design pattern is the usage of wrapper elements to enclose repeated elements, for instance:

<someElement ...>
	<items>
		<item>a</item>
		<item>b</item>
		<item>c</item>
	</items>
</someElement>

The items element on its own has no meaning, it only encloses the item subelements. You can model such XML my using the wrapperElementName option in element properties:

new Jsonix.Model.ElementPropertyInfo({
	name : 'items',
	collection : true,
	elementName: new Jsonix.XML.QName('item'),
	wrapperElementName: new Jsonix.XML.QName('items'),
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
})

Below is the equivalent JavaScript object.

{
	items: [ 'a', 'b', 'c']
}

Defining properties

Value property

Value property maps to the textual content of the XML element. It is defined using the Jsonix.Model.ValuePropertyInfo class:

new Jsonix.Model.ValuePropertyInfo({
	// Name of the property, required
	name: 'value',
	// Type of the property, required, must be a simple type
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
});

See Defining complex type with simple content for usage example.

Usage constraints:

Defining complex type with simple content

Complex type with simple content can be defined with the help of the value property:

One.ValueType = new Jsonix.Model.ClassInfo({
	name : 'One.ValueType'
});
One.ValueType.properties = [ new Jsonix.Model.ValuePropertyInfo({
	name : 'value',
	typeInfo : Jsonix.Schema.XSD.String.INSTANCE
}) ];
Corresponding XML Schema would be:
<xs:element name="value">
	<xs:complexType>
		<xs:simpleContent>
			<xs:extension base="xs:string"/>
		</xs:simpleContent>
	</xs:complexType>
</xs:element>

The type converts between the following XML:

<value>test</value>

And JavaScript object:

{
	name : { localPart : 'value' },
	value : { value : 'test' }
}

Attribute property

Attribute property maps to the attribute of the XML element.

new Jsonix.Model.AttributePropertyInfo({
	// Name of the property, required
	name: 'attribute',
	// Name of the attribute, optional, defaults to name of the property
	attributeName: new Jsonix.XML.QName('attribute'),
	// Type of the property, required, must be a simple type
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
});

Usage constraints:

Any attribute property

"Any attribute" property maps to the attributes of the XML element.

new Jsonix.Model.AnyAttributePropertyInfo({
	// Name of the property, required
	name : 'attributes'
});

Value of the property is a map of the form:

{
	attribute0: value0,
	attribute1: value1,
	attribute2: value2,
	...
}

Where attributeX is the string representation of the qualified attribute name, valueX is the string value of the attribute.

For example, compare the following JSON:

{
	name : { localPart : "anyAttribute" },
	value : {
		attributes : {
			a : 'a',
			'{urn:b}b' : 'b',
			'{urn:c}c:c' : 'c'
		}
	}
}

With the equivalent XML:

<anyAttribute xmlns:b="urn:b" xmlns:c="urn:c"
	a="a"
	b:b="b"
	c:c="c"/>

Usage constraints:

Element property

Element property maps a JavaScript object property onto an XML element.

new Jsonix.Model.ElementPropertyInfo({
	// Name of the property, required
	name : 'element',
	// Whether the property is collection or not, defaults to false
	collection : false,
	// Name of the element, optional, defaults to the name of the property
	elementName: new Jsonix.XML.QName('myElement'),
	// Name of the wrapper element, defaults to null
	wrapperElementName: new Jsonix.XML.QName('myElements'),
	// Type of the property (can be simple or complex), required
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
        })

See Wrapper elements for an explanation of the wrapperElementName option.

Usage constraints:

Element property example - single element
Property declaration
new Jsonix.Model.ElementPropertyInfo({
	name : 'element',
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
        })
Sample XML
<someElement ...>
        <element>fire</element>
</someElement>
JavaScript object
{
        element : 'fire'
}

Elements property

Elements property maps several XML elements onto one JavaScript object property.

new Jsonix.Model.ElementsPropertyInfo({
	// Name of the property, required
	name : 'elements',
	// Whether the property is collection or not, defaults to false
	collection : true,
	// Name of the wrapper element, defaults to null
	wrapperElementName : new Jsonix.XML.QName('myElements'),
	// Element mappings, required
	elementTypeInfos : [
		{
			// Name of the element, required
			elementName : new Jsonix.XML.QName('string'),
			// Type of the property , required
			typeInfo : Jsonix.Schema.XSD.String.INSTANCE
		},
		{
			elementName : new Jsonix.XML.QName('integer'),
			typeInfo : Jsonix.Schema.XSD.Integer.INSTANCE
		}
        ]})

Elements property is provided with elementTypeInfos, an array of element/type mappings. These mappings are objects carrying elementName, qualified name of the element and typeInfo, type of the element.

When unmarshalling an element, this property uses the name of the element to find the corresponding type and then uses this type for actual unmarshalling.

When marshalling a value, this property searches for a matching type for this value and then uses the corresponding element name to create the outgoing XML element.

For instance, the property declared above would handle the following XML:

<someElement ...>
        <myElements>
                <string>one</string>
                <integer>2</integer>
                <string>three</string>
        </myElements>
</someElement>

The corresponding JavaScript object would be:

{
        elements: [ 'one', 2, 'three' ]
}

As you see, we're getting elements of different types (strings, integers) from differently-named elements (string, integer) in one array property elements. The elementTypeInfos definition of our elements property allows Jsonix to understand that string elements must be unmarshalled as strings, integer elements - as integers. During marshalling, Jsonix tries to find a matching type (that is, a type for which this given value would be an instance of) and then use the corresponding element name for marshalling.

The "instance of" operator is implemented differently for simple and complex types.

For simple types the "instance of" operator checks that value has an appropriate JavaScript type (like, string for strings, number for numeric types, boolean for booleans and so on). Simple type also checks that value is actually allowed (ex. integers are round numbers, bytes are in range from -128 to +127 and so on). This can surely be ambiguous, so caution is advised when mixing compatible simple types in one elements property.

Values of complex types are objects so there is no reliable way to determine if a given object is considered as "instance of" a certain complex type. To overcome this difficulty, objects may carry a special-purpose TYPE_NAME property, for instance:

{
	value : 'two',
	TYPE_NAME : 'One.ValueType'
}

Complex type thinks that value is an "instance of" itself if the value is an object and it has a string TYPE_NAME property matching the name of the complex type.

Element map property

Element map property allows mapping one or more elements to an object/hashmap-valued property. Element map property is configured with two further properties which describe, what should be taken as a key of the hashmap and what as value.

Since version 1.1 element map properties can be collections. In this case, values in the hashmap will be arrays. This allows modelling multimaps.

new Jsonix.Model.ElementMapPropertyInfo({
	// Name of the property, required
	name : 'element',
	// Whether the property is collection or not, defaults to false
	collection : true,
	// Name of the element, optional, defaults to the name of the property
	elementName: new Jsonix.XML.QName('myElement'),
	// Name of the wrapper element, defaults to null
	wrapperElementName: new Jsonix.XML.QName('myElements'),
	// Declaration of the key property
	key : new Jsonix.Model.AttributePropertyInfo({
		name : "key",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}),
	// Declaration of the value property
	value : new Jsonix.Model.ValuePropertyInfo({
		name : "value",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	})
});

Example:

Property declarations
One.ElementMapType.properties = [
new Jsonix.Model.ElementMapPropertyInfo({
	name : "element",
	key : new Jsonix.Model.AttributePropertyInfo({
		name : "key",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}),
	value : new Jsonix.Model.ValuePropertyInfo({
		name : "value",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	})
}),
new Jsonix.Model.ElementMapPropertyInfo({
	name : "elements",
	wrapperElementName : new Jsonix.XML.QName("elements"),
	elementName : new Jsonix.XML.QName("element"),
	key : new Jsonix.Model.AttributePropertyInfo({
		name : "key",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}),
	value : new Jsonix.Model.ValuePropertyInfo({
		name : "value",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	})
}),
new Jsonix.Model.ElementMapPropertyInfo({
	name : "elementCollection",
	collection : true,
	key : new Jsonix.Model.AttributePropertyInfo({
		name : "key",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}),
	value : new Jsonix.Model.ValuePropertyInfo({
		name : "value",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	})
}),
new Jsonix.Model.ElementMapPropertyInfo({
	name : "elementsCollection",
	wrapperElementName : new Jsonix.XML.QName("elementsCollection"),
	elementName : new Jsonix.XML.QName("element"),
	collection : true,
	key : new Jsonix.Model.AttributePropertyInfo({
		name : "key",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}),
	value : new Jsonix.Model.ValuePropertyInfo({
		name : "value",
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	})
}) ];
Sample XML
<elementMap> 
	<element key="one">earth</element> 
	<element key="two">wind</element> 
	<elements> 
		<element key="three">fire</element> 
		<element key="four">wood</element> 
	</elements> 
	<elementCollection key="one">1</elementCollection> 
	<elementCollection key="one">I</elementCollection> 
	<elementCollection key="two">2</elementCollection> 
	<elementCollection key="two">II</elementCollection> 
	<elementsCollection> 
		<element key="three">3</element> 
		<element key="three">III</element> 
		<element key="four">4</element> 
		<element key="four">IV</element> 
	</elementsCollection> 
</elementMap> 
JavaScript object
{ 
	name : { localPart : 'elementMap' },
	value : {
		element : {
			'one' : 'earth',
			'two' : 'wind'
		},
		elements : {
			'three' : 'fire',
			'four' : 'wood'
		},
		elementCollection : {
			one : [ '1', 'I' ],
			two : [ '2', 'II' ]
		},
		elementsCollection : {
			three : [ '3', 'III' ],
			four : [ '4', 'IV' ]
		}
	}
}

Element reference property

Element reference property maps a JavaScript object property onto XML element. This is similar to the element property, however what's different is content representation in the JavaScript object. Consider the following properties:

new Jsonix.Model.ElementPropertyInfo({
	name: 'a',
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
}),
new Jsonix.Model.ElementRefPropertyInfo({
	name: 'b',
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
})

XML elements for both properties is the same:

<data>
  <a>1</a>
  <b>2</b>
</data>

However, content representation in the JavaScript object is different:

{
	a : '1',
	b : {
		name : new Jsonix.XML.QName('b'),
		value: '2'
	}
}

In the example above the element reference property b is represented in the JavaScript object by the following construct:

{
	// Qualified name of the XML element
	name : new Jsonix.XML.QName('b'),
	// Content
	value: '2'
}

The advantage of this representation is that you can choose the name of the XML element dynamically:

{
	a : '1',
	b : {
		name : new Jsonix.XML.QName('c'),
		value: '2'
	}
}

Despite property name is still b, it will be marshalled as the element c:

<data>
  <a>1</a>
  <c>2</c>
</data>

Element reference property can be defined as follows:

new Jsonix.Model.ElementRefPropertyInfo({
	// Name of the property, required
	name : 'elementRef',
	// Whether the property is collection or not, defaults to false
	collection : false,
	// Name of the element, optional, defaults to the name of the property
	elementName: new Jsonix.XML.QName('myElementRef'),
	// Name of the wrapper element, defaults to null
	wrapperElementName: new Jsonix.XML.QName('myElementRefs'),
	// Type of the property (can be simple or complex), required
	typeInfo: Jsonix.Schema.XSD.String.INSTANCE
        })
Scoped elements

TODO

Substitution groups

TODO

Element references property

Element references property maps several XML elements onto one JavaScript object property. This is similar to elements property, but for references.

new Jsonix.Model.ElementRefsPropertyInfo({
	// Name of the property, required
	name : 'elementRefs',
	// Whether the property is collection or not, defaults to false
	collection : true,
	// Name of the wrapper element, defaults to null
	wrapperElementName : new Jsonix.XML.QName('myElementRefs'),
	// Element mappings, required
	elementTypeInfos : [
		{
			// Name of the element, required
			elementName : new Jsonix.XML.QName('string'),
			// Type of the property , required
			typeInfo : Jsonix.Schema.XSD.String.INSTANCE
		},
		{
			elementName : new Jsonix.XML.QName('integer'),
			typeInfo : Jsonix.Schema.XSD.Integer.INSTANCE
		}
        ]})

Any element property

Any element property can handle arbitrary XML elements. Depending on the processing types and whether these elements are known within the current Jsonix context, you'll get objects, DOM nodes or strings on the JavaScript side.

new Jsonix.Model.AnyElementPropertyInfo({
	// Name of the property
	name : "any",
	// Whether the property is collection or not, defaults to false
	collection : false,
	// Whether the property allows DOM nodes, default to true
	allowDom : true,
	// Whether the property allows typed objects, default to true
	allowTypedObject : true,
	// If the property is a mixed property, default to true
	mixed : true
})

Any element property handles unmarshalling as follows:

Below is the correspondence between xs:any processing types and allowTypedObject/allowDom processing settings.

Processing type allowTypedObject allowDom
lax
strict
skip

Usage constraints:

Any element property example - lax processing

Consider the following property declaration:

new Jsonix.Model.AnyElementPropertyInfo({
	name : "any",
	collection : true
})

The allowsDom, allowsTypedObject and mixed options are defaulted to true, so this property will produce:

Assume we have declared the global elements string and value in our module:

One.ValueType = new Jsonix.Model.ClassInfo({
	name : "One.ValueType"
});
One.elementInfos = [ {
		elementName : new Jsonix.XML.QName('string'),
		typeInfo : Jsonix.Schema.XSD.String.INSTANCE
	}, {
		elementName : new Jsonix.XML.QName('value'),
		typeInfo : One.ValueType
	} ];

Compare the sample XML and the equivalent JavaScript object:

Sample XML
<anyElement>
	<string>one</string>
	<value>two</value>
	three
	<node>four</node>
</anyElement>
JavaScript object
{
	any : [
		{
			name : { localPart : 'string' },
			value : 'one'
		},
		{
			name : { localPart : 'value' },
			value : { value : 'two' }
		},
		'three',
		// <node>four</node> as a DOM element
		Jsonix.DOM.parse('<node>four</node>').documentElement ]
}

Using Jsonix in your JavaScript program

Including Jsonix scripts

In production you'll normally want to use the minified version of Jsonix:

<html>
	<head>
		<script type="text/javascript" src="../js/Jsonix/Jsonix-min.js"></script>
		<!-- ... --> 
	</head> 
	<!-- ... --> 
</html>

Available versions:

Using Jsonix

Creating Jsonix

In order to marshal or unmarshal you'll first need to create Jsonix context:

var context = new Jsonix.Context(
	// Array of mapping modules
	[ MyMappings1, MyMappings2 ],
	// Optional properties
	{
		// Default namespace/prefix mappings (optional)
		namespacePrefixes : {
			'http://acme.com/foo' : 'foo',
			'http://acme.com/bar' : 'bar'
		}
	}
);

Jsonix context is a factory which produces marshallers or unmarshallers. Jsonix context is thread-safe and reusable.

Once Jsonix context is created you can use it to produce marshallers or unmarshallers:

var marshaller = context.createMarshaller();
var unmarshaller = context.createUnmarshaller();

Unlike the context itself, marshaller and unmarshallers neither thread-safe nor reusable.

Marshalling

Once you have a marshaller, you can marshal your object as XML:

// Marshal as string
var objectAsXMLString = marshaller.marshalString(myObject);
// Marshal as document
var objectAsXMLDocument = marshaller.marshalDocument(myObject);

Unmarshalling

Unmarshaller can parse your object from XML:

// Unmarshal from string
var objectFromXMLString = unmarshaller.unmarshalString(myString);
// Unmarshal from document
var objectFromXMLDocument = unmarshaller.unmarshalDocument(myDocument);
// Unmarshal from URL via AJAX
unmarshaller.unmarshalURL(myURL,
	function (data)	{
		var objectFromURL = data;
	});

Generating mappings from XML Schema

Command-line tool

java
  -jar jsonix-full-<VERSION>.jar // Run executable Java archieve
  -d src/main/webapp/js // Target directory
  src/main/resources/purchaseorder.xsd // Schema
  -b src/main/resources/bindings.xjb // Bindings

XJC plugin

If you're already using XJC to compile your schemas, you'll just need to use the jsonix plugin for XJC. The plugin can be downloaded here. It is activated using the following command-line option:

-Xjsonix

Maven usage

<plugin>                                                                       
	<groupId>org.jvnet.jaxb2.maven2</groupId>                              
	<artifactId>maven-jaxb2-plugin</artifactId>                            
	<configuration>                                                        
		<extension>true</extension>                                    
		<args>                                                         
			<arg>-Xjsonix</arg>                                    
		</args>                                                        
		<plugins>                                                      
			<plugin>                                               
				<groupId>org.hisrc.jsonix</groupId>            
				<artifactId>jsonix-schema-compiler</artifactId>
				<version><VERSION></version>          
			</plugin>                                              
		</plugins>                                                     
	</configuration>                                                       
</plugin>                                                                      

Ant usage

<xjc destdir="${basedir}/target/generated-sources/xjc" extension="true">
	<binding dir="${basedir}/src/main/resources">
	 	<include name="**/*.xjb"/>
	</binding>
	<schema dir="${basedir}/src/main/resources">
	 	<include name="**/*.xsd"/>
	</schema>
	<!-- Plugins -->
	<classpath>
		<fileset dir="${basedir}/lib">
			<include name="jsonix-<VERSION>.jar"/>
		</fileset>
	</classpath>
	<arg line="-Xjsonix"/>
</xjc>

Browse Space

- Pages
- News
- Labels
- Attachments
- Bookmarks
- Mail
- Advanced
- Activity

Explore Confluence

- Popular Labels
- Notation Guide

Your Account

Log In

 

Other Features

Add Content