Slice 4 of #92. The XSD complex-type and identity-constraint validators move
onto the validation framework, producing located results.
- ComplexValidator threads a coding path through its (inherently recursive)
descent, so every content-model, attribute, and simple-type violation is now
a ValidationError located by path ("... at path: order/qty"). Child steps
carry a sibling index only when a name repeats.
- IdentityValidator returns ValidationError instead of Issue.
- A new XSD rules enum wraps both as Validation<Node, XSDContext> values gated to
the document root, combined by Validator<XSDContext>. XSDContext carries the
type table, the identity constraints, and the root declaration.
- Schema.Document.validate builds the context and runs the validator, returning
[ValidationError].
XSD content-model validation is recursive by nature (a child's type depends on
its position), so the rules delegate to the recursion while contributing to one
error collection. Schematron is the last validator on Issue and migrates next.
Validate XSD identity constraints over the instance document in a pass that
walks the tree alongside type validation:
- xs:unique requires the selected nodes' field tuples to be distinct, excluding
any node that is missing a field.
- xs:key additionally requires every field to be present.
- xs:keyref requires each tuple to equal a tuple of the named key or unique
visible in an enclosing scope, resolved through a stack of scope frames so a
keyref and the key it refers to may sit on the same element.
The selector and field XPaths run on the existing XPath engine, relative to the
declaring element and each selected node. Constraints are gathered for every
element declaration at any depth, keyed by element name.
Closes#67