Validating ISOXML Against the ISO 11783 Schema
TL;DR: Load the ISO 11783-10 XSD with xmlschema, run iter_errors over your generated TASKDATA.XML, print the path, reason, and offending value for each failure, and assert zero errors as a CI gate so a structurally invalid prescription file can never reach a controller.
Why Validate Before Shipping
A prescription export writes an ISOXML task set — a TASKDATA.XML plus binary grid files — that a controller such as John Deere GreenStar, Trimble, or Raven reads to drive variable-rate application. If that XML violates the ISO 11783-10 schema, the failure modes are quietly expensive: some terminals refuse to load the task, others load it but skip the malformed portion, and the worst apply a zero or default rate across a field before anyone notices. By the time a misformed TZN (treatment zone) element surfaces, the applicator has already driven the field.
Schema validation is the cheapest gate that catches an entire class of these errors before the file leaves your pipeline. The generation step — covered in exporting prescription maps to John Deere GreenStar format — emits the file; this validation step is the assertion that stands between that file and a terminal. Wiring it into CI means a bad export fails the build instead of failing in the cab.
XSD validation does have a hard boundary: it proves the document is structurally correct against the schema — right elements, right attribute types, right cardinality — but it cannot prove the file is semantically correct. A treatment zone that references a product definition id that does not exist is perfectly valid XML and perfectly invalid ISOXML. So schema validation is necessary, not sufficient; pair it with cross-reference checks.
This guide is part of Variable Rate Export to ISOXML — see there for the full pipeline context including task-set generation and grid packaging.
Prerequisites
xmlschema==3.3.1
lxml==5.2.2
Install with:
pip install xmlschema==3.3.1 lxml==5.2.2
Input requirements:
- A generated
TASKDATA.XMLfrom your export step. - The ISO 11783-10 XSD set on disk. Keep the root schema (commonly
ISO11783_TaskFile_V4-3.xsdor the version matching your controller) together with its included component XSDs in one directory so relative<xsd:include>references resolve. - Never fetch the schema over the network inside CI — a network failure would let the file pass unvalidated.
Step-by-Step
Step 1 — Load the schema once
Instantiate xmlschema.XMLSchema11 against the root XSD. Use the 1.1 loader because the ISO 11783-10 schemas use XSD 1.1 assertions; the default XMLSchema (1.0) loader silently ignores them. Build the schema object once and reuse it across many files in a batch export.
Step 2 — Parse the task file namespace-aware
Load TASKDATA.XML with lxml.etree so parse-level errors (malformed XML, bad encoding) surface separately from schema-validity errors. A file that will not even parse is a different bug from one that parses but violates the schema.
Step 3 — Iterate all errors, do not stop at the first
Call schema.iter_errors(doc) rather than is_valid or validate. iter_errors yields every violation so you fix them in one pass instead of playing whack-a-mole; validate raises on the first error and hides the rest.
Step 4 — Report path, reason, and value
For each error, print the XPath-style error.path, the human-readable error.reason, and the offending value. That triplet is what turns a red build into a one-line fix.
Step 5 — Assert zero errors
The complete, runnable validation script:
import sys
import xmlschema
from lxml import etree
SCHEMA_ROOT = "iso11783/ISO11783_TaskFile_V4-3.xsd" # root XSD; includes resolve relative to it
TASKDATA = "output/TASKDATA.XML"
def validate_isoxml(schema_path: str, xml_path: str) -> int:
# ── 1. Load the schema with the XSD 1.1 loader (ISO 11783-10 uses 1.1) ──
try:
schema = xmlschema.XMLSchema11(schema_path)
except xmlschema.XMLSchemaException as exc:
print(f"FATAL: could not load schema {schema_path}: {exc}")
return -1
# ── 2. Parse the task file (catch malformed XML before schema checks) ──
try:
doc = etree.parse(xml_path)
except etree.XMLSyntaxError as exc:
print(f"FATAL: {xml_path} is not well-formed XML: {exc}")
return -1
# ── 3. Collect every schema violation (not just the first) ─────────────
errors = list(schema.iter_errors(doc))
# ── 4. Report path, reason, and offending value for each ───────────────
for i, err in enumerate(errors, start=1):
value = getattr(err, "value", None)
print(f"[{i}] path : {err.path}")
print(f" why : {err.reason}")
if value is not None:
print(f" value: {value!r}")
print("-" * 60)
print(f"{xml_path}: {len(errors)} schema error(s) against {schema_path}")
return len(errors)
if __name__ == "__main__":
n_errors = validate_isoxml(SCHEMA_ROOT, TASKDATA)
# ── 5. CI gate: a non-zero count blocks the build ──────────────────────
assert n_errors == 0, (
f"TASKDATA.XML failed ISO 11783-10 validation with {n_errors} error(s) — "
f"do not ship to a controller. See the paths above."
)
print("PASS: TASKDATA.XML is schema-valid against ISO 11783-10.")
sys.exit(0)
Run it in CI. A clean file prints PASS; any violation prints the offending element paths and the assert exits non-zero so the export job fails. A frequent first failure is path : /ISO11783_TaskData/TSK/TZN/PDV with reason “value … is not an instance of xs:long” — a rate written as a float where the schema demands an integer scaled value.
Gotchas & Edge Cases
- Using the XSD 1.0 loader silently skips assertions. ISO 11783-10 schemas rely on XSD 1.1
<xsd:assert>rules;xmlschema.XMLSchemaignores them and reports a false pass. Always useXMLSchema11. - Fetching the schema over the network turns outages into false passes. Vendor the XSD set into your repo and point the validator at the local root so CI is deterministic and offline-safe.
- Schema-valid is not controller-valid. Cross-references (a
TZNpointing at a missingPDTproduct id) and firmware-specific subsets pass XSD validation but fail on the terminal. Add referential checks and test against target firmware. validate()hides the tail of your errors. It raises on the first violation;iter_errorsenumerates all of them so one build fixes the whole batch.
Frequently Asked Questions
Where do I get the ISO 11783-10 XSD schema files?
The XSD set is distributed by AEF and ISO as part of the ISO 11783-10 data dictionary and ships with most manufacturer developer kits. Point the validator at the root ISO11783_TaskFile schema and keep the included component XSDs in the same directory so relative includes resolve. Do not fetch schemas over the network in CI because a network failure would turn into a false validation pass.
Why does validation pass locally but the controller still rejects the file?
XSD validation only proves the file is structurally well formed against the schema. It cannot catch referential errors such as a treatment zone pointing at a product id that is never defined, or units that are valid but agronomically wrong. Add cross-reference checks on top of schema validation, and test against the specific controller firmware since vendors enforce stricter subsets.
Should schema validation fail the build or just warn?
Fail the build. A structurally invalid TASKDATA file can cause a controller to silently skip a task or apply a zero rate across a field, so a schema error is a shipping blocker, not a warning. Assert zero errors in the export pipeline so an invalid file can never reach a terminal.
Related
- Variable Rate Export to ISOXML — the parent section covering task-set generation and grid packaging
- Exporting Prescription Maps to John Deere GreenStar Format — the export step that produces the TASKDATA.XML this guide validates
- Shapefile Validation for Farm Equipment — the equivalent structural gate for shapefile-based prescription formats