pyxsd compared with libxml2

libxml2 is an XML toolkit implemented in C. Its build documentation identifies the schema module as XML Schemas 1.0 support; XSD 1.1 is unsupported. The upstream schema API header also describes its XML Schemas implementation as incomplete. Neither the presence of a schema API nor a high test-suite agreement rate establishes complete standards conformance.

pyxsd defaults to XSD 1.1 and offers an explicit XSD 1.0 mode. This page compares scope and interfaces, then records one dated validity-verdict probe. It is not a performance benchmark or a ranking of all releases.

Scope, APIs, and resources

Dimension

pyxsd

libxml2

Implementation

Pure Python base with elementpath and defusedxml

C library; capabilities depend on build configuration

XSD modes

XSD 1.1 default; optional xsd_version="1.0"

XSD 1.0; XSD 1.1 unsupported

Main model

Compile a schema, bind instances to generated Python classes, query/export/transform the bound tree

Compile a schema and validate XML through native tree, file, or streaming/SAX interfaces

Validation interface

Schema.report, Document.report, and ValidationReport

Schema parser/validation contexts, return codes, and error callbacks

Streaming

No lazy/streaming instance mode

xmlSchemaValidateStream and xmlSchemaSAXPlug, alongside xmlSchemaValidateDoc

Resource model

Local-only default; trusted custom ResourcePolicy or opt-in HTTPS RemoteResourcePolicy

Parser options, resource loaders, and XML catalogs; available controls depend on release and integration

libxml2’s schema API and catalog documentation describe its native interfaces. Those interfaces are not pyxsd’s generated Python binding model. A Python wrapper can add its own APIs and loading policies; this comparison does not measure such wrappers.

Resource policy must be evaluated separately from schema validity. pyxsd’s default can read local schema paths named by input; local-only is not path confinement. Its parser protections and finite budgets are opt-in, and it is not a sandbox; see XML security and untrusted input. For libxml2, inspect the exact deployed release, parser options, loaders, catalogs, and wrapper rather than assuming a network or filesystem policy from a validity result. The probe below disabled network access; that is a property of the probe, not a statement about every libxml2 application.

Preliminary macOS libxml2 2.9.13 probe

Measured 2026-10-31; preliminary evidence about this build and adapter only. The local probe used macOS system libxml2 2.9.13 through its C schema API, alongside pyxsd 1.2.1 at source revision d79079fedb4f880a1e4df46981dedf52beab9c14. Both used the XSD 1.0 case catalog and outcome rules for the main suite.xml at w3c/xsdtests revision 7bc3365c652a322f3d762021b3879eb92dae7e30: 41,735 emitted cases per engine. This does not include extra-suite.xml.

Network access was disabled. Local catalog mappings supplied only W3C’s standard xml.xsd and xlink.xsd, so those resources did not depend on live HTTP retrieval. Schema compilation calls that did not return were isolated at the process level.

Outcome

libxml2 2.9.13 probe

Paired pyxsd 1.2.1 run

pass

38,783

39,285

fail

618

153

Checked (pass + fail)

39,401

39,438

adapter-gap

56

24

timeout

5

0

not-applicable

2,258

2,258

not-checkable

15

15

False accepts

490

121

False rejects

128

32

Raw checked-case agreement for this libxml2 probe was 98.4315% = 100 × 38,783 / 39,401, rounded to four decimal places. Current pyxsd agreement and baseline provenance remain in the generated tables in XSTS methodology and results, not in a second hand-maintained headline here.

The checked denominators differ because adapter gaps and timeouts differ. Neither is a validity verdict, and neither enters pass + fail. Failure directions compare an engine’s actual verdict with the selected corpus expectation; they are not determined by what the other engine says.

Pairing the same case IDs provides additional evidence:

Paired outcome

Cases

Both engines match the corpus (pass / pass)

38,729

pyxsd matches, libxml2 disagrees (pass / fail)

519

libxml2 matches, pyxsd disagrees (fail / pass)

53

Both engines disagree (fail / fail)

95

These rows cover only cases checked by both engines, not either engine’s full denominator. Here, pass means agreement, not acceptance of the document; correct rejection of an invalid case is also a pass. The 53 cases where libxml2 matches and pyxsd disagrees are useful residual-adjudication inputs, but neither implementation is normative truth. Disputes need the corpus metadata and the relevant XSD specification.

Timeout and reproducibility limits

The probe recorded five timeouts across particlesZ012, particlesZ015, and particlesZ020, including dependent instances, after libxml2 schema compilation did not return. A durable adapter needs per-case process-level timeouts: a Python exception or signal cannot reliably interrupt a blocking C call. These probe timeouts are not invalid-schema verdicts or evidence about every libxml2 release.

The probe is not a maintained, pinned-build comparison gate. A durable measurement needs a pinned libxml2 build and maintained adapter with the same catalog/applicability and schema-bundle rules, an offline standard-resource catalog, per-case process timeouts, and recorded build/run provenance. No libxml2 runtime dependency or default adapter is added to pyxsd.

What was not measured

Dimension

Evidence from this comparison

Top-level schema/instance verdicts

Preliminary XSD 1.0 probe above

Throughput, latency, or memory use

Not measured

Diagnostic quality or source-location accuracy

Not measured

PSVI correctness or completeness

Not measured

Security or resistance to malicious inputs

Not measured

libxml2 XSD 1.1 agreement

Unsupported, not a zero score

Other libxml2 releases, Xerces, or Saxon

Not measured

C versus Python, or streaming versus tree processing, does not establish a performance advantage without a separate workload and benchmark. Likewise, XSTS top-level verdict agreement does not test complete PSVI output, diagnostics, or security. The upstream suite README states the verdict-only scope. Do not extrapolate the 2.9.13 result to newer builds, wrappers, or XSD 1.1.

See also