Files
linuxcncAllWasm/configs/sim/axis/mtconnect/validate_schemas.py
2026-08-20 06:17:39 +08:00

72 lines
2.4 KiB
Python

#!/usr/bin/env python3
# Developer helper: validate the four MTConnect documents this agent produces
# against the official MTConnect 1.7 XSDs (plus the LinuxCNC extension schema for
# the streaming endpoints).
#
# Requires the `xmlschema` package (XSD 1.1; libxml2/xmllint cannot parse the
# 1.7 schema, which uses XSD-1.1 constructs). The official schemas are fetched
# from schemas.mtconnect.org unless a local directory is given via $MTC_XSD_DIR.
#
# pip install xmlschema
# ./validate_schemas.py [INI] # default: example.ini
#
# Exit status is non-zero if any document fails, so it can gate CI.
import io
import os
import sys
BASE = "http://schemas.mtconnect.org/schemas"
def _xsd(name):
d = os.environ.get("MTC_XSD_DIR")
return os.path.join(d, name) if d else "%s/%s" % (BASE, name)
def _bootstrap_mtc():
# mtc installs to $EMC2_HOME/lib/python (on PYTHONPATH under rip-environment);
# add it explicitly so this runs without the full environment.
home = os.environ.get("EMC2_HOME")
if home:
sys.path.insert(0, os.path.join(home, "lib", "python"))
def main(argv):
ini_path = argv[1] if len(argv) > 1 else "example.ini"
try:
import xmlschema
except ImportError:
print("error: needs the 'xmlschema' package (pip install xmlschema)")
return 2
_bootstrap_mtc()
from mtc.agent import AgentState, asset_dir
EXT_XSD = os.path.join(asset_dir(), "mtconnect-linuxcnc-1.xsd")
state = AgentState(ini_path)
state.poll_once()
docs = {
"MTConnectDevices_1.7.xsd": ("/probe", state.probe_document()),
"MTConnectAssets_1.7.xsd": ("/assets", state.assets_document()),
# Streams validate against the extension schema (which imports the base).
EXT_XSD: ("/current", state.current_document()),
}
ok = True
for xsd, (label, doc) in docs.items():
loc = xsd if xsd == EXT_XSD else _xsd(xsd)
schema = xmlschema.XMLSchema11(loc, validation="skip")
errors = list(schema.iter_errors(io.StringIO(doc)))
if errors:
ok = False
print("FAIL %s (%d errors)" % (label, len(errors)))
for e in errors[:8]:
print(" ", e.reason or e.message)
else:
base = "base" if xsd != EXT_XSD else "base+extension"
print("ok %s valid (%s)" % (label, base))
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main(sys.argv))