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.

ISOXML schema validation CI gate Flow: prescription export writes TASKDATA.XML; the validator loads the ISO 11783-10 XSD and runs iter_errors; zero errors pass to the controller, any error blocks the build. Export writes TASKDATA.XML Validate vs XSD iter_errors ISO 11783-10 errors? 0 Ship to controller GreenStar · Trimble >0 Fail the build

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

TEXT
xmlschema==3.3.1
lxml==5.2.2

Install with:

BASH
pip install xmlschema==3.3.1 lxml==5.2.2

Input requirements:

  • A generated TASKDATA.XML from your export step.
  • The ISO 11783-10 XSD set on disk. Keep the root schema (commonly ISO11783_TaskFile_V4-3.xsd or 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

Validation is a build step, not a repair step Five steps: load the schema version the target terminal implements, validate and collect every error rather than stopping at the first, map each error to its cause in the generating code, fix the generator rather than hand-editing the XML, and re-validate from a fresh build. Load the XSD the version the terminal uses Validate collect every error Map to cause element and rule Fix at the source never patch the XML Re-validate from a fresh build Hand-editing a task file produces one working export and no reproducible pipeline; the next field starts from the same defect.

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:

PYTHON
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.XMLSchema ignores them and reports a false pass. Always use XMLSchema11.
  • 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 TZN pointing at a missing PDT product 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_errors enumerates all of them so one build fixes the whole batch.
The half of correctness a validator cannot see Two panels separating what an XML schema can verify — element presence, ordering, nesting, attribute types and reference resolution — from what it cannot: the coordinate reference system, ring orientation and whether declared rate units mean what the author intended. What the schema can check Element presence, order and nesting Attribute types and value ranges. That every reference target exists. Structure — completely and reliably. What it cannot check Whether coordinates are in EPSG:4326 Whether ring orientation is correct. Whether the rate units mean what you think. Meaning — which is where exports really fail.

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.