Rendering real XML formats

The rendering example families compile external XSDs, bind real XML documents into Python trees, and render those trees as SVG, PNG, HTML, PDF, WAV, or Markdown. This page describes the pattern they share and the catalog of formats they cover.

Other example families do different work and have their own documentation: the Arrow/DuckDB analysis workflows in Data workflow examples, Sequential multi-document parsing processing, the End-to-end demo walkthrough transform tour, and the healthcare family described in its examples/healthcare/README.md.

The pattern

Every rendering family follows the same shape:

  1. Compile. Compile the family’s schema into Python classes. Reuse the compiled schema when rendering multiple documents sequentially.

  2. Bind. Schema.parse() validates and binds the document into a typed tree. Each family decides whether errors prevent rendering: BPMN requires valid input, while CityGML can render with recorded findings. Schema findings are on schema.report; the merged schema and instance findings are on document.report. See Validation.

  3. Walk. The renderer reads the bound tree — typed descriptors, to_dict() projections, or XPath — and extracts exactly the facts it presents.

  4. Render plain Python. Output is built with the standard library or a single-purpose library. SVG, HTML, and WAV generation need only pyxsd’s base environment; the plotting, server, and PDF families use example-only dependency groups.

pyxsd handles schema interpretation, typed binding, and diagnostics; application code decides how to present the data. That boundary is the same one described in Data workflow examples, and the transform API is in Writing transforms.

CityGML, BPMN, OpenDRIVE, XRechnung, and MusicXML pin their sources per family: sources.toml records URLs, revisions, licenses, and SHA-256 digests; the downloader installs verified files under the family’s gitignored .cache/, and repeating the command verifies the cache without network access. Rendered artifacts go under the family’s gitignored out/. Output is byte-deterministic except where a library stamps metadata (reportlab PDFs carry a creation date).

DOCX uses download_schemas.py to populate schemas/; its documented transform writes document.md in the working directory. Follow its README for setup and output paths.

uv sync --group examples-matplotlib --group examples-fastapi --group examples-reportlab

These groups do not add dependencies to the published library; each uv sync matches the groups named in that command, so omit one and it is removed from the environment.

The families

Family

Data source

Artifacts

One caveat

CityGML

OGC CityGML 2.0 LOD1/LOD2 buildings

SVG plan, 3D PNG

known schema findings; needs examples-matplotlib

BPMN

BPMN 2.0 with diagram interchange

SVG diagram

draws the saved layout; not an auto-layout engine

OpenDRIVE

ASAM OpenDRIVE 1.4–1.7 roads

SVG map, profile PNG

schema picked from the header revision; needs examples-matplotlib

XRechnung

UBL 2.3 / EN 16931 invoices

HTML, PDF

keeps lexical amounts; XSD validity is not business-rule conformance

MusicXML

MusicXML 4.0 scores

WAV, SVG preview

merged ties, fixed tempo; not an engraver

DOCX

ECMA-376 WordprocessingML

Markdown

fetches its own schema set (download_schemas.py)

Each README has the commands, the binding details that family demonstrates, and its full list of limitations.

FastAPI: serve each family

Each of the five pinned XML families (CityGML, BPMN, OpenDRIVE, XRechnung, MusicXML) owns its own local FastAPI use beside its CLI renderers. A server reuses only that family’s pinned sources, schema, samples, and render functions:

uv run --group examples-fastapi uvicorn examples.bpmn.server:app --port 8000
uv run --group examples-fastapi uvicorn examples.citygml.server:app --port 8000
uv run --group examples-fastapi uvicorn examples.opendrive.server:app --port 8000
uv run --group examples-fastapi uvicorn examples.xrechnung.server:app --port 8000
uv run --group examples-fastapi uvicorn examples.musicxml.server:app --port 8000

Every family server exposes the same single-source routes:

Method and route

Purpose

GET /

Browse that family’s sample inventory.

GET /api/samples

Read that inventory as JSON.

GET /render/{sample}

Render a curated sample; ?format= selects an optional artifact.

POST /validate

Submit XML for diagnostics and family-specific facts.

Run one family at a time, or give each uvicorn process a different port. These are local examples, not deployment recipes for untrusted uploads; see XML security and untrusted input for parser policies and resource limits. Each family README documents its run command, samples, output formats, and caveats.

Sources and licensing

For the five manifest-based families, see SOURCES.md for provenance, attribution, and license evidence, and sources.toml for pinned digests. Their downloaded files stay in .cache/ and default artifacts in out/. DOCX documents its separate fetcher and paths in its README. Keep downloaded schemas, sample corpora, and generated artifacts out of version control.