pyxsd compared with xmlschema

xmlschema is the established Python library for XML Schema work, and the natural reference point for pyxsd. This page describes where the two overlap, where they differ, and which is the better fit for a given task. It is a design comparison, not a benchmark; the numbers quoted are from each project’s own conformance runs and are explained in Supported features.

At a glance

pyxsd

xmlschema

XSD support

1.1 processor, opt-in 1.0 mode (Schema.compile(xsd_version=), --xsd-version)

Full 1.0 and 1.1 (XMLSchema10 / XMLSchema11; xmlschema.XMLSchema is 1.0)

Runtime dependency

elementpath only (pure Python)

elementpath only (pure Python)

XML parser

stdlib xml.etree.ElementTree

stdlib ElementTree (with optional lxml injection for instance resources)

Primary model

validate, bind to a schema-defined Python object tree, query, export, transform

decode/encode XML↔Python/JSON, validate, inspect schema components

Instance → Python

Document bound tree of generated classes; to_dict() / to_json()

converters to nested dict, JSON, and DataElement bindings

Python/JSON → XML

not provided (transforms can build a Document)

encode(), from_json(), converter classes

Static code generation

no (classes are generated in memory per compiled Schema)

yes, Jinja2 templates

XPath/lookup

Document.xpath() / find() / findall() over a projected bound tree; elementpath used internally for XSD regular expressions and identity/assertion XPath, but there is no public schema-component XPath API

XPath-based schema component API; ElementPathMixin on components and XMLResource

Transform framework

callable transforms over the bound tree, addressable by class name from the CLI

converters plus code generation (no general transform hook)

Validation output

ValidationReport with stable short codes and phases

exception hierarchy plus iter_errors()

Lazy / incremental

no

XMLResource lazy modes (lazy, thin_lazy)

Resource hardening

no network access to schemas; entity expansion handled by expat

entity-forbidding parser, allow/defuse resource policy, timeouts, processing limits

Remote schema download

no (local paths and caller-supplied mappings only)

yes, with an offline cache

WSDL

no

yes (WSDL 1.1)

Maturity

first 1.0 release; new object model

mature, widely deployed, large user base

Where pyxsd is a good fit

  • Runtime binding without code generation. A schema is compiled once and reused; each parse produces a Document whose nodes are typed Python objects (descriptors for declared elements and attributes, XSD datatypes for simple values). There is no build step and no generated source tree.

  • Validation that continues instead of stopping. pyxsd collects issues on a ValidationReport with stable codes rather than raising on the first error, and Document.is_valid / require_valid() make the policy explicit.

  • Callable transforms. A transform is any callable over the bound tree, and the CLI can address a transform by class name (-t 'ToDict()'). This suits pipeline code that post-processes a validated document.

  • A small, predictable dependency and attack surface. The only runtime dependency is elementpath; the library does not fetch remote schemas and relies on the stdlib parser’s entity handling. There is nothing to compile and no network behavior to audit.

  • Direct query and export. xpath / find / findall and to_dict / to_json cover the “validate, then pull values out” pattern without a converter configuration step.

Where xmlschema is a better fit

  • Encoding and JSON round-tripping. xmlschema encodes Python data and JSON back to XML, with converter classes (ParkerConverter, BadgerFishConverter, JsonMLConverter, ColumnarConverter, DataElementConverter, and more). pyxsd does not implement encode; a transform can construct XML, but that is not the same tool.

  • Lazy and incremental processing. XMLResource with lazy / thin_lazy supports large documents and streaming, which pyxsd does not.

  • Resource controls and hardening. xmlschema exposes resource policy (allow / defuse), timeouts, processing limits, remote download with an offline cache, and a parser that forbids entities. If a deployment must fetch schemas over the network or defend against hostile schema input with explicit knobs, xmlschema has those knobs already.

  • Static code generation and WSDL. Generators and WSDL 1.1 processing have no pyxsd equivalent.

  • Schema-component inspection. xmlschema’s XPath-based component API and global maps are deeper for tooling that interrogates the schema itself.

  • Maturity. xmlschema has years of production use, a large body of documentation, and a broad user base. pyxsd 1.0 is a new object model on a long-dormant codebase; its main con is maturity, and the known limitations below are listed for that reason.

Honest limitations of pyxsd

  • Maturity. Version 1.0 is the first modern release. The API is stable for this release but has less field hardening than xmlschema.

  • No encode. There is no Python/JSON→XML serializer beyond writing a parsed Document back out.

  • Legacy namespace mode is the default binding policy. Strict namespace handling is a distinct opt-in mode (ParseModes.NAMESPACED), which surprises users who expect qualified names by default.

  • Mixed content is preserved but not a structured-export citizen. Interleaved text is kept verbatim in the bound tree (leading text in _value_, child tails in _tail_) and survives serialization and XPath queries, but the dict export can only concatenate the character data under $, and the Arrow/Pydantic integrations reject mixed content.

  • DTD is internal-subset only, and unobserved. Declarations beyond what expat exposes (notably unparsed NDATA entities) are not tracked; external subsets are not fetched, and a doctype declaration is neither processed nor reported.

  • One parse at a time per Schema. The compiled schema holds per-parse indexes on a shared host, so concurrent parses against the same Schema are not supported.

  • XML 1.1 documents are not fully supported (an expat limitation), though schema version mode 1.0/1.1 is.

Using them together

The two are complements in a test suite: pyxsd’s own conformance harness runs xmlschema as an oracle over the W3C XSTS corpus and compares each case’s verdict, so the libraries are exercised side by side rather than treated as mutually exclusive. If both are installed, xmlschema’s oracle can be enabled with PYXSD_RUN_ORACLE=1 for the conformance run.

See also