Python API¶
Everything importable from xsdkit. Types come from the shipped stubs, so
mypy and pyright see exactly what is written here.
Start here
SchemaSet is the entry point — build one, then
subscript it. Element and Type are
where you will spend your time.
Loading¶
SchemaSet
¶
A compiled set of schema components.
elements
property
¶
elements: NamedComponents[Element]
Every global element declaration, in name order and by name.
A view: iterate it or index it by position, as a list, or look a
declaration up by name, as a mapping — schemas.elements["{ns}name"].
types
property
¶
types: NamedComponents[Type]
Every global type definition this schema declares, in name order and by name.
An element and a type may share a name, which is why types have a view
of their own. The XSD built-ins are excluded: they are in every schema
set and would bury the ones the documents wrote. type("{...}string")
still resolves them.
attributes
property
¶
attributes: NamedComponents[Attribute]
Every global attribute declaration this schema declares, in name order and by name.
The xml: and xsi: attributes every schema set carries are
excluded; attribute() still resolves them.
counts
property
¶
Component tallies — types, elements, particles and the rest — for
diagnostics and smoke tests. Counts a great deal more than the globals
len() reports.
from_file
classmethod
¶
from_file(path: str | PathLike[str], *, search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'strict', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> SchemaSet
Loads a schema from a file, following its includes and imports.
Raises SchemaError, carrying every diagnostic, when the schema has
errors; load returns them instead. version="1.1" reads XSD 1.1: open
content, conditional inclusion, assertions on wildcards,
xs:precisionDecimal and the relaxed Unique Particle Attribution rule.
max_depth caps how deeply elements nest in each schema document, 256 by
default; a deeper document is refused with XSD1001 rather than parsed.
from_string
classmethod
¶
from_string(xsd: str, *, uri: str = '<string>', search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'strict', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> SchemaSet
Loads a schema from a string. The text must already be decoded.
Relative schemaLocation hints resolve against uri; with the default
uri, against the working directory and search_paths.
from_bytes
classmethod
¶
from_bytes(data: bytes, *, uri: str = '<bytes>', search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'strict', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> SchemaSet
Loads a schema from raw bytes, detecting the encoding.
Prefer this over from_string when the encoding is not known to be
UTF-8: a byte-order mark or the XML declaration decides it.
from_files
classmethod
¶
from_files(paths: Iterable[str | PathLike[str]], *, search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'strict', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> SchemaSet
Loads a schema from several files at once, following each one's includes and imports into one set.
For a schema with no single root document: a vendor bundle, or a directory of XSDs that import one another. A single path, or an empty list, is refused.
deserialize
classmethod
¶
deserialize(data: bytes) -> SchemaSet
Reads back what serialize wrote.
Raises ValueError for bytes that are not a serialized schema set, or
that another xsdkit version wrote: a name is an index into the
interner, so a schema set from another build means nothing here. Read
only bytes you trust, as with pickle.
serialize
¶
The compiled schema set as bytes, for deserialize to read back
without compiling the schema again.
For a cache, and for handing a schema set to another process: pickling
goes through this. Only the xsdkit version that wrote the bytes reads
them back, so key a cache on xsdkit.__version__.
__len__
¶
How many global elements this schema declares.
SchemaSet is a mapping of global elements. Types and attributes
are separate symbol spaces — an element and a type often share a name
— and have views of their own in types and attributes.
__getitem__
¶
The global element of that name, raising KeyError when there is
none — and saying so when the name belongs to a type or an attribute.
The lookup methods return None instead, for when absence is an
ordinary answer rather than a mistake.
get
¶
The global element of that name, or default when there is none.
keys
¶
The global element names, sorted.
Present so this really is a mapping: dict(schemas) needs keys
alongside __getitem__.
element
¶
Looks up a global element. None if there is none.
type
¶
Looks up a global type. None if there is none.
attribute
¶
Looks up a global attribute. None if there is none.
validate
¶
validate(xml: Instance, *, uri: str | None = None) -> ValidationReport
Validates an instance document against this schema.
Never raises for an invalid document — an invalid document is an
answer, not an error. Inspect .is_valid and .diagnostics.
Diagnostics name uri, or the file when the document was given as a
path.
decode
¶
decode(xml: Instance, *, uri: str | None = None, lax: bool = False, root: bool = False) -> Any
Decodes a document into Python data.
Elements become dictionaries, values arrive in their value space —
Decimal, datetime, int — and a child the schema allows more than
once is always a list, whether the document carries two of them, one,
or none. That shape comes from the schema, so it does not change under
you when a document leaves something out.
Keys are local names, spelled out in Clark notation only where two
names under one parent would otherwise collide. Attributes are
prefixed with @, and where an element has both a value and
attributes the value sits under $. xsi:nil decodes to None, or
to None under $ when the element carries attributes too.
Raises DocumentError if the document is invalid; pass lax=True to take
the data anyway. Unlike validate, this one raises, because a caller
asking for data has said what it wants and silently handing back data
from a document that does not fit its schema is the trap this is meant
to remove. Text that is not XML at all raises even with lax=True:
there is nothing in it to take.
The result is the root element's content. Pass root=True for
{root name: content}, which says which global element the document
was; the key follows the same rule as every other.
iter_typed
¶
iter_typed(xml: Instance, *, uri: str | None = None) -> PsviEvents
Reads a document into typed PSVI events, as it is validated.
for ev in schemas.iter_typed(xml) composes with everything Python has
for iterables. Validation runs on a thread of its own and hands events
over a batch at a time, so memory stays flat however large the
document is, and an iterator dropped part way stops the reading.
The outcome is on report once every event has been read. To know
whether a document is valid before reading it, call validate.
read_typed
¶
read_typed(xml: Instance, *, uri: str | None = None) -> tuple[list[PsviEvent], ValidationReport]
Reads a document into typed PSVI events, all at once.
Returns (events, report): every event, as a list, and the outcome.
Memory grows with the document; iter_typed reads one of any size.
NamedComponents
¶
Bases: Generic[_C]
A schema's global components of one kind, in name order and by name.
Elements, types and attributes are separate symbol spaces, and an element and a type sharing a name is one of the most common patterns in XSD, so each kind has a view of its own rather than one mapping over all three. A view iterates its components and indexes them by position the way a list does, and looks them up by name the way a mapping does.
load
¶
load(path: str | PathLike[str], *, search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'lax', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> tuple[SchemaSet, list[Diagnostic]]
Loads a schema and returns it with its diagnostics, rather than raising.
Use this when a schema is expected to be imperfect — a vendor schema with dangling imports, say — and you want the components anyway.
load_files
¶
load_files(paths: Iterable[str | PathLike[str]], *, search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'lax', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> tuple[SchemaSet, list[Diagnostic]]
The same, from several root documents at once.
load_string
¶
load_string(xsd: str, *, uri: str = '<string>', search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'lax', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> tuple[SchemaSet, list[Diagnostic]]
The same, from a string.
load_bytes
¶
load_bytes(data: bytes, *, uri: str = '<bytes>', search_paths: Sequence[str | PathLike[str]] | None = None, conformance: Conformance = 'lax', version: XsdVersion = '1.0', nodes_limit: int | None = None, max_depth: int | None = None, resolver: Resolver | None = None) -> tuple[SchemaSet, list[Diagnostic]]
The same, from bytes whose encoding is detected.
Document
¶
One schema document that went into the set.
A schema is often many files — xs:include and xs:import pull in more —
and this is the record of each, including which namespace it ended up in.
uri
property
¶
Where this document was read from — a path, a URL, or whatever a custom resolver called it.
target_namespace
property
¶
The namespace its declarations landed in, None for a no-namespace
schema.
chameleon
property
¶
True when this document had no targetNamespace of its own and was
absorbed into its includer's.
version
property
¶
The xs:schema version attribute, verbatim. The specification gives
it no structure and no meaning, so it is reported, not interpreted.
Declarations¶
Element
¶
An element declaration: a name, a type, and how it may appear.
An element behaves as its children — iterable, sized, and subscriptable by
name — so a schema is walked without a .type hop at every level:
report["item"]["price"], or [child.local_name for child in report].
A handle into the schema, not a copy — holding ten thousand of them costs ten thousand refcounts. Two handles to the same declaration compare equal and hash alike, so they work as dict keys and set members.
>>> report = schemas.element("urn:example", "report")
>>> report.children # what may appear inside
>>> report.substitutes # what may appear *instead*
children
property
¶
children: list[Child]
Elements that may appear directly inside this one.
The same as element.type.children, without the hop — an element's
children are its type's, and browsing a schema should not have to say
so at every level. Empty for a simple type.
attributes
property
¶
attributes: list[AttributeUse]
The attributes this element may carry, with how it may carry them.
The same as element.type.attributes, without the hop.
name
property
¶
(namespace, local); the namespace is None when unqualified.
nillable
property
¶
Whether an instance may be empty by saying xsi:nil="true".
Nil is not the same as absent, and not the same as empty: it says the element is present and has no value.
abstract
property
¶
Whether this element may not appear itself.
An abstract head exists to be substituted for — see substitutes.
is_global
property
¶
Whether this is a global declaration rather than one scoped to a type.
substitutes
property
¶
substitutes: list[Element]
Every element that may appear where this one is permitted, including itself when it is not abstract.
Transitive, and with block applied — so this is what a document may
actually name here, not merely who is in the substitution group. A
head that blocks substitution has members that this does not list.
default
property
¶
The default value, supplied when the element is present but empty.
fixed
property
¶
The fixed value, which an instance may repeat but not contradict.
__getitem__
¶
The child of that name, raising KeyError when there is none.
A local name is enough, since a child is almost always in its parent's namespace.
tree
¶
tree(depth: int = 3) -> Tree
A readable tree of what may appear inside, for looking at a schema.
Regular-expression markers for how often a child may appear — ?
optional, + one or more, * any number, nothing for exactly once —
and @name for attributes, ? when they are not required. Recursion
stops where the shape repeats, so a section containing sections prints
once rather than to the depth limit.
>>> print(schemas["{urn:example}report"].tree())
report
title: xs:string
item+
@sku
price: xs:decimal
note?: xs:string
Child
¶
An element as a child of one particular type.
Everything Element answers, this answers too, plus how often it may
appear here. That pairing is the point: maxOccurs and minOccurs are
written on the use, not on the declaration, so one global element may be
a repeating child of one type and a required single child of another.
Both flags come from the same pass over the content model that produced the child list, so reading them costs nothing beyond the walk that was already done.
repeats
property
¶
Whether it may appear here more than once, which makes it a list when a document is decoded.
element
property
¶
element: Element
The declaration on its own, without this parent's occurrence.
Rarely needed — a Child answers everything an Element does — but
it is what to compare against SchemaSet["{ns}name"], which has no
parent to have occurrence in.
name
property
¶
(namespace, local); the namespace is None when unqualified.
is_global
property
¶
Whether the declaration is global rather than scoped to a type.
substitutes
property
¶
substitutes: list[Element]
Every element that may stand in for this one. Transitive.
default
property
¶
The default value, supplied when the element is present but empty.
fixed
property
¶
The fixed value, which an instance may repeat but not contradict.
attributes
property
¶
attributes: list[AttributeUse]
The attributes this child may carry, with how it may carry them.
Type
¶
A type definition, simple or complex.
The centre of the model. A complex type answers what may appear inside it
(children, attributes, accepts); a simple type answers what its
values may be (validate, facets, variety). is_complex says which
you have.
>>> t = schemas.type("urn:example", "Sku")
>>> t.validate("AB-1042") # the typed value, or ValueError
>>> t.facets.patterns # the constraints in force
name
property
¶
(namespace, local), or None for an anonymous inline type.
qname
property
¶
The name in Clark notation, or None for an anonymous type.
A type declared inline inside an element has no name to report.
is_simple
property
¶
Whether this type has a value space — something validate can parse.
abstract
property
¶
Whether an instance may not use this type directly, only one derived from it.
derivation
property
¶
"extension" or "restriction"; None for simple types.
attributes
property
¶
attributes: list[AttributeUse]
Attribute uses, with inherited attribute groups already flattened in.
children
property
¶
children: list[Child]
Every element that may appear directly inside this type, with substitution groups expanded and inherited content included.
Each one is a Child: the declaration, plus whether it may repeat and
whether it may be left out. Those two belong to the pair rather than
to the declaration — one global element may be used by several types
under different bounds — and they come from the same single pass over
the content model that found the children.
content
property
¶
content: ContentKind | None
"empty", "simple", "element-only" or "mixed"; None for a
simple type.
content_model
property
¶
content_model: ModelKind | None
How the content model was compiled: "empty", "automaton" or
"all".
primitive
property
¶
The primitive this simple type reduces to, e.g. "string".
member_types
property
¶
member_types: list[Type]
A union's member types, in the order they are tried.
facets
property
¶
facets: Facets | None
The facets in force, composed down the whole restriction chain.
Not the ones this type declares — those are on
declared_facets. A restriction inherits everything its base
constrained, so a type that says only maxLength still has its base's
minLength, and reporting the declared set alone disagrees with what
validate does. For a complex type with simple content, the facets of
that content's simple type.
declared_facets
property
¶
declared_facets: Facets | None
The facets this type declares, without its base's.
What the restriction step wrote, which is what a tool rendering a
schema back wants. facets is what a validator applies.
appinfo
property
¶
appinfo: list[AppInfo]
The xs:appinfo blocks, with their XML kept verbatim.
Kept as written, because a summary cannot be un-summarised: this is where a schema hides labels, mappings and anything else its authors agreed on.
tree
¶
tree(depth: int = 3) -> Tree
A readable tree of what may appear inside this type.
The same rendering as Element.tree, rooted at the type rather than at
a declaration — so the first line is the type's name and the rest is
its content.
__getitem__
¶
The child element of that name, raising KeyError when absent.
derives_from
¶
derives_from(other: Type) -> bool
Whether this type is, or derives from, other.
Always False for a type from another SchemaSet: a type in one set says
nothing about a type in another.
accepts
¶
accepts(names: Iterable[Name]) -> bool
Whether a sequence of child names satisfies this type's content model.
Names may be Clark notation, (ns, local) pairs, or bare local names,
resolved against this type's children exactly as type[name] resolves
them. A single str is refused rather than read one character at a
time.
validate
¶
validate(lexical: str, /, *, namespaces: Mapping[str, str] | None = None) -> XsdValue
Validates a lexical form against this type, returning its typed value.
namespaces maps prefixes to namespace URIs, "" for the default
namespace, for an xs:QName, whose value is whatever its prefix is
bound to where it was written. A complex type with simple content
validates against the simple type of that content.
Raises InvalidValueError, which is also a ValueError, with the
reason when the value is not valid.
is_valid
¶
Whether a lexical form is valid against this type.
Attribute
¶
An attribute declaration.
The declaration itself, shared by every type that uses it. How a particular
type uses it — required, optional, prohibited, with what default — is on
AttributeUse, which is what Type.attributes returns.
AttributeUse
¶
An attribute declaration as used by one complex type.
attribute
property
¶
attribute: Attribute
The declaration this use refers to.
Several types may use one declaration, each with its own use and
value constraint.
required
property
¶
Whether an instance must carry this attribute.
The same question as use == "required", asked the way it is usually
asked.
Facets
¶
A set of facets on a simple type.
The bounds and enumerations are kept as the lexical forms the schema wrote,
not as typed values: a facet constrains the lexical space as much as the
value space, and the string is what the document said. Pass one through
Type.validate to get the value.
patterns
property
¶
Patterns as declared: the outer list is one entry per restriction step, ANDed; the inner alternatives at that step are ORed.
enumeration
property
¶
The permitted values, as the lexical forms the schema wrote.
Compared in the value space, so an enumeration listing 1.0 admits
1.00.
white_space
property
¶
"preserve", "replace" or "collapse" when stated explicitly.
fraction_digits
property
¶
Most digits a decimal may have after the point.
AppInfo
¶
Machine-readable annotation content, kept verbatim.
source
property
¶
The source attribute — a URI naming what convention the payload
follows, when the schema said.
xml
property
¶
The appinfo element's content as the schema document wrote it. Each
top-level element declares the namespaces in scope, so
xml.etree.ElementTree.fromstring accepts it on its own and a prefix
inside it, such as the xs: of a type name, still resolves.
Escapes, comments and CDATA sections are kept as written. An entity declared in the document's DTD stays a reference.
Validation¶
ValidationReport
¶
The outcome of validating a document.
is_valid
property
¶
Whether the document satisfied the schema.
The report is falsy when it did not, so if not report: reads.
PsviEvents
¶
An iterator over one document's typed events, read as it is validated.
Validation runs on a thread of its own, so memory stays flat however large
the document is, and an iterator dropped part way stops the reading. The
outcome is on report once every event has been read.
report
property
¶
report: ValidationReport
The outcome, once every event has been read.
Whether a document is valid is only known at its end, which is where
this is too. Raises RuntimeError before then; to know first, call
validate.
PsviEvent
¶
One post-schema-validation event.
A single class with a kind discriminator rather than three, because the
consuming loop is invariably a dispatch on kind.
name
property
¶
The element's name as a (namespace, local) pair; None on a
"text" event, which belongs to the element around it.
local_name
property
¶
The local part of the name, without its namespace; None on a
"text" event.
declaration
property
¶
declaration: Element | None
The declaration this element matched.
Absent under a skip wildcard, or a lax one with nothing to match.
type_from_instance
property
¶
Whether xsi:type chose the type, rather than the declaration.
nil
property
¶
Whether the element is nil: it said xsi:nil="true", and its
declaration allows that. An xsi:nil the declaration refuses is an
error, and leaves this False.
attributes
property
¶
attributes: list[AttributeValue]
The attributes, typed, including any the schema supplied.
from_schema
property
¶
Whether the schema supplied this text, because the element was empty
and its declaration had a default or fixed value.
AttributeValue
¶
Diagnostics¶
Diagnostic
¶
Something the reader found wrong, or worth saying.
Carries a stable code to match on, a message for people, spans for
where, and often help for what to do. str() renders the lot the way a
compiler would.
Span
¶
Where in a document a diagnostic points, and what that place is.
One diagnostic may carry several — an ambiguous content model names both particles that could match, and the labels say which is which.
XsdError
¶
Bases: Exception
The base of the errors about schemas, documents and values. A wrong argument type raises TypeError, and a path that cannot be read raises OSError.
diagnostics
instance-attribute
¶
diagnostics: Sequence[Diagnostic]
Built-in immutable sequence.
If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable's items.
If the argument is a tuple, the return value is the same object.
SchemaError
¶
Bases: XsdError
Raised when a schema cannot be built. Carries every diagnostic on .diagnostics.
diagnostics
instance-attribute
¶
diagnostics: Sequence[Diagnostic]
Built-in immutable sequence.
If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable's items.
If the argument is a tuple, the return value is the same object.
DocumentError
¶
Bases: XsdError
Raised by decode for a document that does not satisfy its schema. Carries every diagnostic on .diagnostics.
diagnostics
instance-attribute
¶
diagnostics: Sequence[Diagnostic]
Built-in immutable sequence.
If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable's items.
If the argument is a tuple, the return value is the same object.
InvalidValueError
¶
Bases: XsdError, ValueError
Raised by Type.validate for a lexical form its type does not admit. Also a ValueError.
Rendering and iteration¶
Tree
¶
Rendered text that knows how to show itself.
A plain str is the wrong return type for something meant to be looked
at: a notebook displays repr() of the last expression, and repr of a
string escapes every newline into \n. This renders as itself in a REPL,
in a notebook, and through print.
splitlines
¶
The lines, so a tree can be sliced and searched like the text it is.
ChildIterator
¶
NameIterator
¶
Walks the global names of a SchemaSet.
A snapshot rather than a live cursor: the model is immutable, so there is nothing to invalidate, and holding the names costs one allocation against the alternative of keeping an index into two maps in step.
Type aliases¶
The names the signatures above use, importable for annotating your own code:
from xsdkit.typing import XsdValue.
Type aliases for code that uses xsdkit.
The names the type stub uses in its signatures, importable at runtime so that annotated code can name them too::
from xsdkit.typing import XsdValue
def total(values: list[XsdValue]) -> int: ...
They lived only in the stub, where a type checker could read them and a program could not import them.
Conformance
module-attribute
¶
How strictly a schema is read: "strict" reports errors, "lax"
downgrades what it can to warnings.
XsdVersion
module-attribute
¶
Which XSD to read the documents as.
Severity
module-attribute
¶
How serious a diagnostic is.
Variety
module-attribute
¶
What kind of simple type a type is.
ContentKind
module-attribute
¶
What a complex type may contain.
ModelKind
module-attribute
¶
How a complex type's content model is checked.
Use
module-attribute
¶
Whether an attribute must, may or must not appear.
Name
module-attribute
¶
A name as Clark notation ({ns}local), a bare local name, or a
(namespace, local) pair.
Resolver
module-attribute
¶
Resolves a schema location to a document.
Called with (location, base), where base is the URI of the document
containing the reference, or None. Return the document as bytes —
leaving the encoding to xsdkit, which reads the byte-order mark and the XML
declaration — or as str, or as (uri, document) to say where it was
actually found. Raise to report that it could not be resolved; the exception
becomes the diagnostic, and the first one raised is the SchemaError's
__cause__. KeyboardInterrupt and SystemExit end the build and
propagate as themselves.
Replaces the filesystem rather than adding to it, so it is an alternative to
search_paths, not a layer on top.
Instance
module-attribute
¶
A document: XML as text, as bytes whose encoding is detected, or a path to
read it from. A str is always content — a path and a document cannot be
told apart once both are strings — so pass pathlib.Path for a file.
XsdValue
module-attribute
¶
XsdValue = str | bool | int | float | decimal.Decimal | bytes | datetime.datetime | datetime.date | datetime.time | datetime.timedelta | list[Any]
An XSD value as its closest native Python type.
Durations and gregorian fragments stay as their canonical lexical strings —
xs:duration has no lossless Python counterpart, since months and seconds
are not commensurable. xs:dayTimeDuration alone becomes a timedelta.
A value datetime cannot hold exactly stays lexical too: a year outside 1 to
9999, an xs:date with a timezone, or digits below the microsecond.
An xs:QName arrives as Clark notation ({namespace}local) with its
prefix already resolved, since the prefix is a spelling rather than part of
the value.