Codecs
Introduction
The Codec
feature is used for serialization and deserialization of objects in XML format.
It can be used to export/encode and import/decode maxGraph
data, for example to save and load the state of graphs or the configuration of a graph.
- export/encode: convert a
maxGraph
object to an XML string - import/decode: convert an XML string to a
maxGraph
object
The serialization/deserialization process is based on Codec
classes that map the maxGraph objects to XML nodes and attributes.
The codecs are registered with CodecRegistry
to let maxGraph
know how to map a class to its related Codec
.
Codecs registration
To use codecs, you must register them for the classes you want to encode/decode before using a Codec
. The registration is done with the CodecRegistry
class.
CodecRegistry
is a singleton so it holds a global state.
maxGraph
provides several functions to register the codecs provided out of the box:
From version 0.6.0 of maxGraph
, codecs supplied by maxGraph
are no longer registered by default, they MUST be registered before performing an encode
or decode
Registering codecs has an impact on the tree-shaking, so, only register the codecs you need to reduce the size of the final bundle.
Encode/Export and Decode/Import
To encode and decode data, you can use the encode
and decode
functions.
import { Codec, popup, xmlUtils } from '@mxgraph/core';
// encode/export
const sourceObject = {}; // your object
const encoder = new Codec();
const node = encoder.encode(sourceObject);
const encodedXml = xmlUtils.getPrettyXml(node);
// decode/import
const xml = '...'; // your XML string
const targetObject = {}; // object to decode into
const decoder = new Codec();
const doc = xmlUtils.parseXml(input);
new Codec(doc).decode(doc.documentElement, targetObject);
Special support of the GraphDataModel
ModelXmlSerializer
As explained above, the typical usage of the Codec
class requires you to:
- Register the codecs for the classes you want to encode/decode (using
registerModelCodecs
) - Call the
encode
ordecode
method
To simplify the process of encoding and decoding the GraphDataModel
, the ModelXmlSerializer
class is provided.
It registers codecs under the hood and provides a simpler syntax.
The code becomes:
import { GraphDataModel, ModelXmlSerializer } from '@mxgraph/core';
const model = new GraphDataModel();
const serializer = new ModelXmlSerializer(model);
// import/decode
const xml = '...'; // your XML string
serializer.import(xml);
// export/encode
const exportedXml = serializer.export();
Import/Decode mxGraph
models
maxGraph
provides a special support to import mxGraph
models which have a different XML structure (mainly because the name of the class are prefixed by mx
in mxGraph
).
This allows interoperability with draw.io/diagrams.net
and ease the migration from mxGraph
.
Here is an example of how to import an mxGraph
model:
const mxGraphModelAsXml = `<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" vertex="1" parent="1" value="Vertex #2">
<mxGeometry x="380" y="20" width="140" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" vertex="1" parent="1" value="Vertex #3">
<mxGeometry x="200" y="80" width="380" height="30" as="geometry">
<mxPoint x="1" y="1" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="7" edge="1" source="2" target="3" parent="1" value="Edge #7">
<mxGeometry as="geometry">
<Array as="points">
<Object x="420" y="60"/>
</Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
`;
const model = new GraphDataModel();
new ModelXmlSerializer(model).import(mxGraphModelAsXml);
There is no support for export/encode mxGraph models
Troubleshooting
The most common error you may encounter when using Codecs is the "maximum call stack trace" error. It occurs when a class that you are trying to encode doesn't have a codec registered.
Uncaught RangeError: Maximum call stack size exceeded
at ObjectCodec.writeAttribute (ObjectCodec.js:384:19)
at ObjectCodec.encodeValue (ObjectCodec.js:376:22)
at ObjectCodec.encodeObject (ObjectCodec.js:346:22)
at ObjectCodec.encode (ObjectCodec.js:326:14)
at Codec.encode (Codec.js:285:28)
at ObjectCodec.writeComplexAttribute (ObjectCodec.js:415:27)
at ObjectCodec.writeAttribute (ObjectCodec.js:389:18)
at ObjectCodec.encodeValue (ObjectCodec.js:376:22)
at ObjectCodec.encodeObject (ObjectCodec.js:346:22)
at ObjectCodec.encode (ObjectCodec.js:326:14)
Generally, this error is thrown when you try to encode a class that is not registered in the CodecRegistry
. To fix this error, you need to register the codec for the class.
Start by using one of the register functions provided by maxGraph
.
Using custom object and custom Codec
This paragraph is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0).
It is adapted from the original mxGraph tutorial.
Copyright 2021-present The maxGraph project Contributors
Copyright (c) JGraph Ltd 2006-2020
The default encoding scheme maps all non-object fields to string attributes and all object fields to child nodes, using the constructor
name of the object as the node name and the field name for the as-attribute value.
This default encoding scheme may be overridden by custom codecs, which are registered in the CodecRegistry
.
For example, consider the following JavaScript object definition:
const object = {
myBool: true,
myObject: {
name: 'Test'
},
myArray: ['a', ['b', 'c'], 'd']
};
To encode/export this object and show the resulting XML in a new window, the following code is used:
import { Codec, popup } from '@mxgraph/core';
const encoder = new Codec();
const node = encoder.encode(object);
popup(xmlUtils.getXml(node));
And here is the XML structure that represents the object:
<Object myBool="1">
<Object name="Test" as="myObject"/>
<Array as="myArray">
<add value="a"/>
<Array>
<add value="b"/>
<add value="c"/>
</Array>
<add value="d"/>
</Array>
</Object>
Note that the codecs will turn booleans into numeric values, no array indices are stored if they are numeric and non-object
array members are stored inside the value-attribute.
Furthermore, one may include other XML files by use of the include
directive in the XML structures.
Examples and Demos
More complex examples and demos involving Codecs are available in the maxGraph
repository.
Load a data model from an XML file using ModelXmlSerializer or from a custom text file with custom parsing (no Codecs involved)
- live demo: FileIO
- source code: FileIO.stories.ts
Import mxGraph data model
- live demo: CodecImport_mxGraph
- source code: Codec.stories.ts
Import vertex including custom XML data in the Cell value, with ModelXmlSerializer and a Custom Codec to handle the custom XML data
- live demo: JsonData
- source code: JsonData.stories.ts
Export the data model to an XML file using ModelXmlSerializer, custom data in the Cell value
- live demo: UserObject
- source code: UserObject.stories.ts
In addition, the js-example
package in this repository is importing an maxGraph model stored as XML string. This is a vanilla JS project built with Webpack.
So, it should contain everything you need for your use case. See js-example source code