Format validators¶
Machine checks for .phyphox files, generated from the same
format specification that produces the reference
pages — so they cannot drift from the documentation.
- phyphox.rng — a RELAX NG grammar (XML syntax). Checks structure: which elements and attributes may appear where, required attributes and children, and attribute values — enumerations and colors exactly as the format defines them, numbers and booleans by syntax.
- phyphox.rnc — the same grammar in RELAX NG compact syntax, for reading rather than for tools.
- phyphox.sch — a
Schematron ruleset for what a grammar cannot
express: buffer references must name a declared container, container names
must be unique, the graph dataset pairing rules,
the numbered
mapColor[N]attribute shape, and — as warnings, not errors — the version gates: an element or attribute used by a file that declares an older format version than the feature requires.
Running them¶
With lxml (what this site's own build uses):
from lxml import etree
from lxml.isoschematron import Schematron
tree = etree.parse("experiment.phyphox")
rng = etree.RelaxNG(etree.parse("phyphox.rng"))
print(rng.validate(tree), rng.error_log)
sch = Schematron(etree.parse("phyphox.sch"), store_report=True)
sch.validate(tree)
for fail in sch.validation_report.iter("{http://purl.oclc.org/dsdl/svrl}failed-assert"):
level = "warning" if fail.get("role") == "warning" else "error"
print(level, fail.findtext("{http://purl.oclc.org/dsdl/svrl}text").strip())
xmllint --relaxng phyphox.rng experiment.phyphox works too, as does any
other RELAX NG validator. The grammar accepts a file with no namespace or
with the phyphox namespace in either URI spelling (http://phyphox.org/xml
or https://phyphox.org/xml). The apps themselves go further — they ignore
the namespace entirely and treat whatever the root element declares as the
file's own — but that rule is beyond what a fixed grammar can express, and
no other namespace is in circulation.
What a pass means — and what it does not¶
The grammar is deliberately no stricter than the apps' parsers. Files that load today must validate, so it allows what they allow:
- stray text between elements (the parsers skip text nodes they do not expect, and real files use that for inline notes);
- attributes from foreign namespaces anywhere (the parsers read
attributes by their plain name and ignore the rest — this is how
editor-generated files carry their
editor:*bookkeeping); - unknown elements in foreign namespaces likewise.
An unknown element in the phyphox namespace or in no namespace is an
error, matching the parsers. An unknown attribute is the one place the
validators are deliberately stricter than the apps: the parsers silently
ignore attributes they do not know (a compatibility guarantee — see the
format rules), while the validators flag them, because a misspelled
cycle= for cycles= loads fine and silently does the wrong thing. A
validator pass therefore means "no unknown attributes"; an app accepting a
file does not.
A pass is therefore necessary, not sufficient: whether an experiment makes
sense — buffers wired to the right modules, sensible rates, units that mean
something — is beyond any schema. The build of this site additionally runs
every corpus and shipped experiment file through both validators plus the
spec-driven checker in tools/validate_experiments.py, which knows a few
things the published artifacts cannot see.
The version gates are warnings because the apps only compare a file's
declared version against the newest version they support — a file that
understates its version still loads on a current app, but older app versions
will mishandle it, so an author should raise the declaration instead of
relying on that.