xmlschema-graph

The xmlschema-graph directive draws an XML schema as a Graphviz graph, from the schema file itself:

  • every complex type is a record of its name, its attributes, and its simple-typed child elements with their cardinality;

  • every complex-typed child element is an edge, labelled with its name and cardinality - so containment and recursion are edges rather than repeated type names;

  • an enumeration is a node of its own, listing its values;

  • a root element is a double circle.

The schema is read with xmlschema, a requirement of this package, and drawn by sphinx.ext.graphviz, which the extension sets up itself. The schema file becomes a dependency of the page.

.. xmlschema-graph:: TestReport-v0.1.xsd
   :caption: The types of TestReport-v0.1.xsd.

This is how the example renders, drawing pyTooling’s test report schema:

Diagram of TestReport-v0.1.xsd

The types of TestReport-v0.1.xsd.

.. xmlschema-graph:: <path of an XML schema>

Draws the schema the argument names, relative to the document.

:caption: <text>

A caption under the graph.

pyTooling’s schema pages show the graphs of the schemas pyTooling ships.

Another schema language

SchemaGraph is the directive’s language-neutral base-class, and DotGraph is the graph: a pyTooling.Graph.GraphViz.Graph with the look every schema graph shares, plus AddRecord() for a titled record of compartments and GetOrAddNode() for an edge’s target without a record of its own. A directive for another schema language derives from the base-class, names itself, and overrides _RenderGraph():

class JSONSchemaGraph(SchemaGraph):
  directiveName: str = "json-schema-graph"

  @classmethod
  def _RenderGraph(cls, schemaFile: Path) -> str:
    graph = DotGraph()
    person = graph.AddRecord("Person", "Person", [["name : string", "age : integer"]])
    graph.AddEdge(Edge(person, graph.GetOrAddNode("Address"), {"label": "address [0..1]"}))
    ...
    return str(graph)