Using transforms¶
A transform is anything that accepts the parsed tree root — a plain
function, or a Transform subclass — optionally takes its own
arguments, manipulates the tree, and (usually) returns the root so the
writer can serialize it.
Built-in transforms¶
Transform |
What it does |
|---|---|
|
Writes the tree as readable text to a file or stdout. |
|
Returns the bound tree as a plain dictionary; the CLI writes mapping results as JSON. |
After a transform changes the tree’s shape, revalidate the transformed
document with Document.revalidate() — it re-parses the serialized tree
against the same schema and returns a fresh document whose report
reflects the new structure. It also carries the original parse’s DTD
declaration evidence, so a declared ENTITY/ENTITIES value does not
become invalid merely because serialization drops the DOCTYPE.
Transform syntax¶
Transform calls are class names with parenthesized arguments:
PrintData()
SphereCutter(0.5)
The class name must match the module name containing it, modulo casing and
underscores (PrintData resolves to print_data and printData;
underscore-insensitive fallback matching is applied).
On the command line, chain calls with > and separate transforms run in
order, each seeing the previous transform’s result:
pyxsd -i input.xml -t 'ExpandCell() > PrintData()'
Or place one call per line in a file and pass it with -T:
ExpandCell()
PrintData()
(See examples/legacy/sampleTransformFile.txt.)
Bundled application transforms¶
The crystallography transforms that shipped with pyxsd 0.1 — ExpandCell,
SphereCutter, CellSizer, BravaisLattice, CoordViewer,
FormatForVisit, plus the Atom/Vector helper libraries — now live in
examples/legacy/ and are no longer part of the installed
package. To use them:
run pyxsd from that directory (
cd examples/legacy), orcopy the transform files you need next to your data, or
pass the module file via your transform library setup.
They expect crystallography-shaped data and are meant as adaptable examples.
See examples/legacy/README.md.
Library use¶
When driving pyxsd as a library, transforms are callables applied with
Document.transform. A Transform subclass is invoked through a small
wrapper (the class takes the root in __init__, its __call__ does the
work); a plain function taking the root needs no wrapper:
import pyxsd
from pyxsd.cli import parse_transform_call, resolve_transform_class
schema = pyxsd.Schema.compile("inventory.xsd")
document = schema.parse("inventory.xml")
def normalize_units(root): ...
# A plain callable:
updated = document.transform(normalize_units)
updated.write("out.xml")
# A Transform class, resolved by name exactly like the CLI does:
name, args, kwargs = parse_transform_call("PrintData()")
transform_cls = resolve_transform_class(name)
document.transform(lambda root: transform_cls(root)(*args, **kwargs))
A transform that returns a tree root comes back as a new Document. Any
other return value, including None, is returned unchanged. An in-place
transform can therefore return None while the original document remains
available. After a structural change, call Document.revalidate() on the
document you want to check.