Supported features¶
pyxsd is an XSD 1.1 processor with an optional XSD 1.0 mode
(Schema.compile(xsd, xsd_version="1.0") / --xsd-version 1.0; see
Parse modes and binding and the version section below). This page summarizes what is
validated, and what is deliberately not.
The W3C XML Schema Test Suite (XSTS) measures agreement on catalogued schema and instance validity verdicts, not complete feature coverage or certification.
Raw checked-case agreement for pyxsd against the pinned main suite.xml
corpus:
Profile |
Passed |
Checked |
Agreement on checked |
|---|---|---|---|
XSD 1.1 |
41,515 |
41,605 |
99.7837% |
XSD 1.0 |
39,285 |
39,438 |
99.6120% |
Checked cases are pass + fail; agreement is 100 * pass / (pass + fail).
Main-suite cases only: extra-suite.xml is excluded, and no combined
XSD 1.0/1.1 rate is reported. See
XSTS methodology and residuals.
XSTS methodology and results identifies the pinned corpus, reviewed baselines, provenance,
non-verdict outcomes, and residual failures behind this headline. A separate
manifest-driven regression corpus backs the integration paths
(uv run python tests/report_conformance.py for its live report).
Parser profiles, structural limits, remote schema rules, and the untrusted-input boundary are covered in XML security and untrusted input. The defaults remain stdlib parsing and local-only loading.
Built-in type lattice¶
All 45 XSD 1.0 built-in datatypes are implemented with lexical
validation in __new__ (pyxsd.xsd_data_types): the full string family
(string, normalizedString, token, Name, NCName, NMTOKEN, language, ID,
IDREF, ENTITY, anyURI, QName, NOTATION), all integer variants with correct
ranges, decimal, float/double (including INF/-INF/NaN), the date/time family
(date, dateTime, time, duration, gYear, gYearMonth, gMonth, gMonthDay,
gDay), base64Binary, hexBinary, anySimpleType/anyType, and the list types
NMTOKENS/IDREFS/ENTITIES.
Structural schema elements¶
xs:sequence,xs:choice,xs:allcontent models with order and occurrence checkingxs:groupdefinitions and references (nested, with cycle detection); a reference’sminOccurs/maxOccursstays with that reference and never affects other uses of the shared groupxs:attributeGroupdefinitions and referencesxs:any/xs:anyAttributewildcards with namespace lists (##any,##other,##local,##targetNamespace, explicit URIs) andprocessContents(strict/lax/skip), enforced in namespaced mode; wildcard particles take part in sequence order and occurrence matching, and each matched child is bound through the particle that admitted it — position decides, not the child’s name (including wildcards contributed by a group)repeated declarations and inherited extension declarations validate each occurrence through the particle that consumed it, so
fixedand type constraints stay with the declaration they were written onelement and attribute declarations sharing a name: both are kept — the attribute keeps the natural accessor and the element is exposed under a collision-safe alias (
<name>_element, with a numeric suffix when that is taken)XML Namespaces in namespaced mode:
targetNamespace,elementFormDefault/attributeFormDefault(including the source schema’s defaults for imported components and explicitformoverrides), prefixed type/refQNames, cross-namespacexs:import, and QName value identityxs:listwith named or inline item types and per-item facet validation; item types may be atomic or unions without list membersxs:unionwith declared or inline anonymous members, including nested unions and list membersxs:notationdeclarations andxs:NOTATIONrestrictions with enumeration validationelement references (
ref) and substitution groupscomplex content
xs:extension/xs:restrictionderivation withfinalenforcement
Instance semantics¶
minOccurs/maxOccursenforcement (includingunbounded)xsi:nilon nillable elements: a nilled element must be completely empty (whitespace-only text and child elements are reported), may not carry afixedvalue, still has its attributes validated, and is preserved as nil in outputdefaultandfixedfor attributes and simple-content elementsxsi:typedynamic dispatch on child elements and the document rootabstractelements and types;block/prohibitedrestrictionsroot dispatch: both complex-typed and primitive-typed document roots
expanded-name matching of elements and attributes against form defaults (namespaced mode)
Composition and identity¶
xs:include(chameleon schemas supported),xs:import(cross-namespace components in namespaced mode, including imports without aschemaLocationwhen the namespace is supplied), andxs:redefine, including chained redefinitionsxs:key,xs:unique,xs:keyrefwith the XSD identity-constraint XPath subset: namespace-qualified child and attribute steps,.//descendants, wildcards,., union paths, andxpathDefaultNamespace
Validation reporting¶
Non-fatal, code-tagged issue reporting via Schema.report and
Document.report (see Validation), plus --strict CI-friendly
exit codes, require_valid(), and the ValidationReport API for
library users. Schema.compile(..., mode=...) / --mode
selects how invalid or unrecognized content is bound (strict vs. lax)
without changing what is reported — see Parse modes and binding. The same policy
carries a namespaces field: Schema.compile(..., mode=ParseModes.NAMESPACED) or --namespaces strict turns on
namespace-aware validation (the default legacy behavior is unchanged).
Extending and typing generated classes¶
Mixin extensions attach user classes to the schema’s generated types at compile time (
Schema.compile(..., extensions=...)), selected by type name, namespace, kind, instance path, or predicate, with an optional__pyxsd_validate__hook whose findings join the instance report (see Mixin extensions). There is no post-compile class patching and no builtin-type extension.Type-stub emission (
Schema.stub()/pyxsd --emit-stubs) renders a.pyityping surface, or a compact agent-oriented view, for the classes a compiled schema creates at runtime; a construct that cannot be typed truthfully degrades toAny(see API reference).Native value conversions and facet introspection on the XSD value types — temporal (
to_date/to_datetime/to_time,to_gregorian), duration, binary, QName, and URI conversions, plusXsdDataType.patterns()/enumerations()— see Data model.
XSD versions (1.0 and 1.1)¶
The processor defaults to XSD 1.1 and accepts an explicit version:
Schema.compile(xsd, xsd_version="1.0"), or --xsd-version 1.0 on the
CLI. Version selection applies the conditional-inclusion rules
(vc:minVersion / vc:maxVersion / vc:typeAvailable and friends) at
the declared version, and in 1.0 mode it reports XSD 1.1-only vocabulary
(assert, assertion, alternative, openContent, override,
notNamespace, notQName, defaultAttributes, inheritable,
xpathDefaultNamespace, dateTimeStamp, dayTimeDuration,
yearMonthDuration, anyAtomicType) as the schema error
xsd11-construct. Three 1.0/1.1 semantic differences are also enforced:
the 1.0 xs:all 0..1 child-occurrence cap (all-rule), the 1.0
requirement that a union declare at least one member type
(declaration-child), and the 1.1 prohibition on use="prohibited"
together with fixed.
Some XSD 1.0 differences remain unswitched because they live in shared machinery (the built-in datatype constructors) or need case-specific identity-constraint and name-resolution work rather than a clean version switch:
the 1.0-only lexical forms around year
0000and the+INF/-INFspelling (the shared datatype constructors are version-agnostic);keyref cardinality under 1.0;
several 1.0 name-resolution edge cases in cross-namespace references.
These remain raw XSD 1.0 test-suite failures, including version-specific implementation gaps. See Interpreting residual failures for expectation relationships and reviewed dispositions, and XML and XSD validation for the distinction between XML and XSD versions.
Known gaps¶
Feature |
Construct |
Status |
Note |
|---|---|---|---|
Namespace-aware schemas |
|
partial |
Opt-in in namespaced mode ( |
Wildcard namespace filtering |
|
partial |
Enforced in namespaced mode (including |
General XPath in identity constraints |
Expressions outside the XSD selector/field subset |
unsupported |
The XSD subset is supported. Predicates, absolute paths, additional axes, and function calls are reported and skipped. |
Mixed content |
|
partial |
Character data is preserved verbatim in the bound tree — leading text in |
Remote schema hints |
URL |
partial |
The default loader resolves local filesystem paths only and never fetches a URL. |
Unique particle attribution |
UPA checking with XSD 1.1 wildcard exclusions |
partial |
Effective content models are checked, including inherited models and substitution groups. Wildcards carrying |
DTD entities |
|
partial |
Validation considers the internal DTD subset only, and only as far as expat’s built-in entity expansion and default-attribute handling go. No built-in profile retrieves an external subset or external entity. The stdlib default keeps that behavior for speed and compatibility and neither fetches nor reports a DOCTYPE declaration; |
XML 1.1 documents |
|
unsupported |
The stdlib expat parser behind |
Concurrent parses per schema |
parsing in parallel from one |
unsupported |
A compiled |
This table is maintained as machine-readable data in
tests/conformance/unsupported.toml, which also feeds the conformance
report.
Note
Free-threaded builds. pyxsd is pure Python and runs on free-threaded
Python (the 3.15t / 3.14t builds) without changes. The
concurrent-parses-per-schema rule above is a hard requirement there:
the GIL hid many violations on regular builds, while a free-threaded build
runs them for real. Concurrent compiles and concurrent parses on separate
Schema objects remain supported. Compiled extras (pydantic, pyarrow)
may re-enable the GIL when imported if their wheels do not yet support
free-threading; that is a performance note, not a failure.