@docx4j/jsonix
v3.3.0
Published
Jsonix (JSON interfaces for XML) is a JavaScript library which allows converting between XML and JSON structures.
Maintainers
Readme
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 JSON (this process is called unmarshalling) or serialize JSON in XML form (this is called marshalling).
- These conversions are based on declarative XML/JSON mappings which can be written manually or generated from an XML Schema.
Jsonix advantages:
- Strongly structured
- Type-safe
- Bidirectional
- (Optionally) XML Schema-driven
See also the other Jsonix features.
Example
Here's a working example for the purchase order schema (try it online in JSFiddle).
Generate mappings
Mappings are generated by the separate jsonix-schema-compiler (JDK 11+; its jar is not part of this package):
java -jar jsonix-schema-compiler-full-<VERSION>.jar -d mappings -p PO purchaseorder.xsd [-b bindings.xjb]Generates mappings for the purchaseorder.xsd schema in mappings/PO.js; mappings will be placed in the variable PO.
Binding files (.xjb) must use the Jakarta namespace (xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb", version="3.0")
with current compiler releases; customisations in the old http://java.sun.com/xml/ns/jaxb namespace are silently ignored.
Parse XML into JS
// Include or require PO.js so that PO variable is available
// For instance, in node.js:
var PO = require('./mappings/PO').PO;
// First we construct a Jsonix context - a factory for unmarshaller (parser)
// and marshaller (serializer)
var context = new Jsonix.Context([PO]);
// Then we create a unmarshaller
var unmarshaller = context.createUnmarshaller();
// Unmarshal an object from the XML retrieved from the URL
unmarshaller.unmarshalURL('po.xml',
// This callback function will be provided
// with the result of the unmarshalling
function (unmarshalled) {
// Alice Smith
console.log(unmarshalled.value.shipTo.name);
// Baby Monitor
console.log(unmarshalled.value.items.item[1].productName);
});You can also unmarshalString, unmarshalDocument and (under node.js) unmarshalFile.
Serialize JS as XML
// Create a marshaller
var marshaller = context.createMarshaller();
// Marshal a JavaScript Object as XML (DOM Document)
var doc = marshaller.marshalDocument({
name: {
localPart: "purchaseOrder"
},
value: {
orderDate: { year: 1999, month: 10, day: 20 },
shipTo: {
country: "US",
name: "Alice Smith",
street: "123 Maple Street",
city: "Mill Valley",
state: "CA",
zip: 90952
},
billTo: { /* ... */ },
comment: 'Hurry, my lawn is going wild!',
items: { /* ... */ }
}
});You can also marshalString.
TypeScript
Run the compiler with -generateTypeScript to get, next to each mapping file, a declaration file describing the
objects Jsonix unmarshals and marshals (PO.d.ts). Together with this package's own typings the results need no casts:
import { Jsonix } from '@docx4j/jsonix';
import { PO } from './mappings/PO';
import type { PurchaseOrderElement, USAddress } from './mappings/PO';
const context = new Jsonix.Context([PO]);
const element = context.createUnmarshaller().unmarshalString(xml); // RootElement, inferred from PO
const po = context.createUnmarshaller().unmarshalString<PurchaseOrderElement>(xml).value;
po.shipTo.name; // string
po.orderDate?.year; // number | undefined: dates are Jsonix calendars, not JS Dates
const shipTo: USAddress = { name: 'Alice Smith', street: '123 Maple Street', city: 'Mill Valley', state: 'CA', zip: 90952 };
const text = context.createMarshaller().marshalString<PurchaseOrderElement>({
name: { namespaceURI: '', localPart: 'purchaseOrder' },
value: { shipTo, billTo: shipTo, items: {} }
});- An unmarshaller returns
Jsonix.TypedNamedValue<T>, i.e.{ name: QName, value: T }; generated files alias it per global element (PurchaseOrderElement) and as the union of all of them (RootElement). The generated mapping constant is declared asJsonixMapping<RootElement>, so a context built from generated mappings infers that union as the result ofunmarshal*when no type argument is given; a type argument narrows it. - Unmarshalled objects carry
TYPE_NAME(e.g.'PO.USAddress'), which the generated interfaces declare as a literal type usable as a discriminant. It is optional on input; you need not set it when marshalling. - The compiler can also write the mapping as an ES module (
<jsonix:output format="esm"/>givesPO.mjs), and this package has an ES-module entry point, soimport { Jsonix } from '@docx4j/jsonix'works in Node ESM and bundlers. - Node and Node bundlers get an entry with static imports of the DOM dependency (
jsonix.node.mjs, selected by the package'sexportsnodecondition), browsers an entry with none (jsonix.mjs);require()keeps the UMD. Where the runtime cannot detect its environment (workers, sandboxes),Jsonix.DOM.use({ DOMParser, XMLSerializer, DOMImplementation })supplies the DOM to use. In Node, XML 1.0 text keeps raw U+0085 and U+2028 (xmldom's default would turn them into line feeds). new Jsonix.Context(mappings, { parentPointers: true })gives every unmarshalled typed object a non-enumerablePARENTpointing at its containing typed object (root objects have none), andJsonix.Util.deepCopy(value, parent?)copies a subtree and re-links the pointers, like docx4j's-Xparent-pointer/-Xdocx4j-copymodel. Generated declarations typePARENTas the union of the types that can contain each type.PARENTis invisible tofor...in,Object.keys, JSON and the marshaller.
Jsonix Features
- Runs in almost any modern browser
- Runs in Node.js
- Runs with CommonJS modules, ES modules, AMD modules as well as vanilla (globals, without any module loader)
- Ships TypeScript typings that compose with the declarations generated by jsonix-schema-compiler (see TypeScript)
- Bidirectional (XML -> JS as well as JS -> XML)
- Implements marshalling (serializing the JavaScript object into XML)
- Supports string data and DOM nodes as result
- Implements unmarshalling (parsing a JavaScript object from XML)
- Supports string data, DOM nodes, URLs or files (with Node.js) as source
- Driven by declarative XML/JS mappings which control how JavaScript object is converted into XML or vice versa
- Mappings can be automatically generated based on the XML Schema
- Strongly-structured - XML/object mappings describe structures of JavaScript objects
- Strongly-typed - Conversion between string content on XML side and values on the JavaScript side is controlled by declared property types
- Provides extensible type system
- Supports most XML Schema simple types (inlcuding QNames)
- Supports enumerations, list and union simple types
- Allows adding own simple types
- Supports complex types consisting of several properties
- Supports deriving complex types by extension
- Provides advanced property system
- Value, attribute, element, element reference properties for string processing of XML content
- Any attribute, any element properties for "lax" processing for XML content
Documentation
Lineage
Forked from highsource/jsonix (Dr. Alexey Valikov) via MITRE's fork
(@mitre/jsonix, up to 3.0.11). From 3.2.0 maintained by Plutext at
plutext/jsonix and published as @docx4j/jsonix.
