Convert legacy system GoDiagram XML models to GoJS models

Hello.
I have a few hundred models in XML format made in GoDiagram (Windows forms) on a legacy 2014 system.
Now we are remaking this system on the web using Angular.
I need to convert all these models from old 2014 GoDiagram to newest version of GoJS (Angular).
What is the best solution to do this?
Thanks.

There’s no standard way to do that, since the information that is stored in the XML is probably more than you need or want in the GoJS model. GoDiagram works with documents, whereas GoJS works with models. Models are more abstract than documents – documents have to include all of the information needed to do a complete rendering. Think of a Word document or HTML DOM – those are documents. Whereas GoJS models are much simpler, since many of the decisions about what to show (how big, what shape, what colors, etc) are determined by the templates.

Initially I highly recommend doing this development in a simple, stand-alone HTML page that does not use Angular or any other libraries. You’ll be able to develop much faster and easier by avoiding complications from HTML, CSS, and other libraries. In fact, you might want to start with a “minimal” sample, as shown below.

Or consider starting with: Minimal GoJS Sample
Or if you want to have a Palette: Minimal Editor
Those already have the boilerplate code for the gojs.net web site stripped out.

To get started, from the XML I would produce two Arrays, one holding the node data and one holding the link data. These you will pass as the Model.nodeDataArray and the GraphLinksModel.linkDataArray. If you don’t want to change the property names, set the appropriate properties on the model to match the property names you are using on the data. Those might include:

  • Model.nodeKeyProperty (if you aren’t using the default name “key”)
  • GraphLinksModel.linkFromKeyProperty (if you aren’t using the default name “to”)
  • GraphLinksModel.linkToKeyProperty (if you aren’t using the default name “from”)
  • GraphLinksModel.linkFromPortIdProperty (if you have multiple ports on a node)
  • GraphLinksModel.linkToPortIdProperty (if you have multiple ports on a node)

Also, if your node data do not have location information, assign a reasonable Diagram.layout to suit your needs:

Now you can create the GraphLinksModel with those two Arrays of rudimentary data and assign it to the Diagram.model. You should now see the outlines of your diagram as a GoJS Diagram, where each node only shows as a simple text and each link is only a simple line with a default arrowhead.

Then you can start thinking about making each Node and each Link look more like what you want by defining templates:

If you do have location information for each node, then instead of setting Diagram.layout you should just add a Binding on the Node.location property, as discussed in the Introduction page about Data Binding.

As you define your template(s), you will want to decide to copy particular attributes from the XML as properties in your JavaScript data, so that they can be used as the source of a Binding.

I do not recommend adding Bindings for all of the properties that you have in the XML data. Chances are that many (most?) of the properties will have the same value for all instances of a template, so there’s no need for a Binding using that property.

Here’s an example using an XML document that I have copied in-line in the code:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="https://unpkg.com/gojs/release/go-debug.js"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      // initializations of the Diagram or its tools
      "undoManager.isEnabled": true
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.Shape,
      { fill: "white" }),
    $(go.TextBlock,
      { margin: 8 },
      new go.Binding("text", "label"))
  );

myDiagram.linkTemplate =
  $(go.Link,
    { curve: go.Link.Bezier },
    $(go.Shape),
    $(go.Shape, { toArrow: "Standard" })
  );


const xml = `<statechart version="4" name="">
  <state id="0" Port="7" label="Idle" loc="160 89" color="-1" midcolor="none" forecolor="-10040320" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-13408768" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <state id="1" Port="8" label="Add coins" loc="430 108" color="-1" midcolor="none" forecolor="-6710836" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-16777216" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <state id="2" Port="9" label="Check&#xD;&#xA;price" loc="662 183.999985" color="-1" midcolor="none" forecolor="-6710836" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-16777216" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <state id="3" Port="10" label="Dispense&#xD;&#xA;Product" loc="349 361" color="-1" midcolor="none" forecolor="-6710836" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-16777216" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <state id="4" Port="11" label="Return change" loc="345 204.000015" color="-1" midcolor="none" forecolor="-6710836" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-16777216" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <state id="6" Port="12" label="OK to&#xD;&#xA;Dispense" loc="545 364" color="-1" midcolor="none" forecolor="-26368" midfraction="NaN" brushstyle="ShapeHighlightGradient" pencolor="-16777216" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="1" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="7" to="7" curviness="20" brush="-16777216" adjusted="Scale" points="146.452682 75.95443 106 37 190.026566 36.9832878 167.526566 75.95443" label="wait" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="7" to="8" curviness="20" brush="-16777216" adjusted="Scale" points="181.287766 84.33882 217.527573 76.5495 313.539948 67.77492 392.346436 94.95443" label="Coin Inserted" pencolor="-16777216" penwidth="1.5" pendashstyle="Dot" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="256" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="8" to="8" curviness="20" brush="-16777216" adjusted="Scale" points="430 94.95444 430 25.0000038 492 40.0000038 441.8945 94.95444" label="Coin inserted" pencolor="-16777216" penwidth="1.5" pendashstyle="Dot" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="8" to="9" curviness="20" brush="-16777216" adjusted="Calculate" points="469.735046 112.675041 530.2507 119.795029 584.540161 137.579514 632.6035 166.383133" label="product&#xD;&#xA;selected" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="9" to="8" curviness="20" brush="-52429" adjusted="Calculate" points="632.6035 181.250931 572.0879 175.591721 517.7984 157.807236 452.996277 121.045578" label="price &gt; coins" pencolor="-52429" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="9" to="12" curviness="20" brush="-16777216" adjusted="Calculate" points="654.932068 204.591125 635.3075 261.763458 605.2303 308.036 567.1609 343.408844" label="enough money&#xD;&#xA;inserted" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="10" to="11" curviness="20" brush="-16777216" adjusted="Scale" points="341.7444 340.408844 327.4342 299.79715 383 254 354.914642 217.045578" label="money inserted&#xD;&#xA;more than price" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="11" to="7" curviness="20" brush="-16777216" adjusted="Calculate" points="303.988281 190.954437 265.109039 178.2781 217.690979 148.641815 172.618866 102.045578" label="default" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="10" to="7" curviness="20" brush="-16777216" adjusted="Scale" points="310.667969 347.619965 137 287 151 195 158.892349 102.045578" label="no change needed" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="8" to="11" curviness="20" brush="-16777216" adjusted="Scale" points="425.273 121.045578 412.1869 157.565018 344.131927 148.213211 344.7118 190.954437" label="cancel" pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <comment id="5" label="Coin Op Vending &#xD;&#xA;Machine states" center="63.634758 155.500015" color="-1331" midcolor="none" forecolor="none" midfraction="NaN" brushstyle="Solid" pencolor="-2894893" penwidth="1" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="12" to="10" curviness="20" brush="-16777216" adjusted="Scale" points="511.0852 384.591125 461 415 420 406 381.48822 381.591125" label="Product in&#xD;&#xA;stock " pencolor="-16777216" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
  <transition from="12" to="8" curviness="20" brush="-52429" adjusted="Calculate" points="530.5318 343.408844 484.209717 277.4832 450.913116 203.362122 432.860931 121.045578" label="Product&#xD;&#xA;sold out" pencolor="-52480" penwidth="1.5" pendashstyle="Solid" labelfamilyname="Microsoft Sans Serif" labelfontsize="10" labelalignment="2" labelbold="false" labelitalic="false" labelmultiline="true" labelstrikethru="false" labelunderline="false" labeltextcolor="-16777216" />
</statechart>`;

// ought to handle parse errors here:
var xmldoc = new DOMParser().parseFromString(xml, "text/xml");

// now initialize the two Arrays from the XML DOM
const nda = [];
const lda = [];

const states = xmldoc.getElementsByTagName("state");
for (let s of states) {
  nda.push(
    {
      key: s.getAttribute("Port"),
      label: s.getAttribute("label"),
      loc: s.getAttribute("loc"),
    });
}

const transitions = xmldoc.getElementsByTagName("transition");
for (let t of transitions) {
  lda.push(
    {
      from: t.getAttribute("from"),
      to: t.getAttribute("to"),
    });
}

// then can initialize the Diagram.model
myDiagram.model = new go.GraphLinksModel(
  {
    nodeDataArray: nda,
    linkDataArray: lda
  });

  </script>
</body>
</html>

This produces:

If you evaluate myDiagram.model.toJson(), you will see that the GoJS model is much smaller than the GoDiagram XML document:

"{ \"class\": \"GraphLinksModel\",
  \"nodeDataArray\": [
{\"key\":\"7\",\"label\":\"Idle\",\"loc\":\"160 89\"},
{\"key\":\"8\",\"label\":\"Add coins\",\"loc\":\"430 108\"},
{\"key\":\"9\",\"label\":\"Check\\r\\nprice\",\"loc\":\"662 183.999985\"},
{\"key\":\"10\",\"label\":\"Dispense\\r\\nProduct\",\"loc\":\"349 361\"},
{\"key\":\"11\",\"label\":\"Return change\",\"loc\":\"345 204.000015\"},
{\"key\":\"12\",\"label\":\"OK to\\r\\nDispense\",\"loc\":\"545 364\"}
],
  \"linkDataArray\": [
{\"from\":\"7\",\"to\":\"7\",\"curviness\":20},
{\"from\":\"7\",\"to\":\"8\",\"curviness\":20},
{\"from\":\"8\",\"to\":\"8\",\"curviness\":20},
{\"from\":\"8\",\"to\":\"9\",\"curviness\":20},
{\"from\":\"9\",\"to\":\"8\",\"curviness\":20},
{\"from\":\"9\",\"to\":\"12\",\"curviness\":20},
{\"from\":\"10\",\"to\":\"11\",\"curviness\":20},
{\"from\":\"11\",\"to\":\"7\",\"curviness\":20},
{\"from\":\"10\",\"to\":\"7\",\"curviness\":20},
{\"from\":\"8\",\"to\":\"11\",\"curviness\":20},
{\"from\":\"12\",\"to\":\"10\",\"curviness\":20},
{\"from\":\"12\",\"to\":\"8\",\"curviness\":20}
]}"