xs:ID, xs:IDREF, and xs:IDREFS were validated only lexically (as NCNames); the document-wide rules that every ID is unique and every IDREF/IDREFS item matches some ID were not enforced, so duplicate IDs and dangling references passed. The tree validator now records ID and reference values during its typed walk over elements and attributes (a new IDTracker), and reports duplicate IDs and unresolved references after the whole document is seen, so a forward reference resolves against an ID declared later. XSTS: invalid instances accepted 179 to 166. Baseline updated; regression tests cover unique IDs, a forward reference, a duplicate ID, an unresolved IDREF, and IDREFS item resolution. The ID/IDREF helpers live in a ComplexValidator extension to keep the type within the file/body length limits. Refs #147, #129.
24 lines
1.1 KiB
Swift
24 lines
1.1 KiB
Swift
extension PureXML.Schema.ComplexValidator {
|
|
/// The document-scoped ID uniqueness and IDREF resolution errors gathered
|
|
/// during validation. Call after validating the document root.
|
|
func idErrors() -> [PureXML.Validation.ValidationError] {
|
|
idTracker.errors()
|
|
}
|
|
|
|
/// Records a value for document-scoped ID/IDREF checking when its type is
|
|
/// xs:ID, xs:IDREF, or xs:IDREFS. Values are whitespace-collapsed (these types
|
|
/// are NCName-based); an IDREFS value contributes one reference per list item.
|
|
func recordIDs(_ type: PureXML.Schema.SimpleType, value: String, at path: [PureXML.Validation.PathKey]) {
|
|
let normalized = PureXML.Schema.SimpleType.process(value, whiteSpace: .collapse)
|
|
if type.isID {
|
|
idTracker.recordID(normalized, at: path)
|
|
} else if type.isIDReference {
|
|
idTracker.recordReference(normalized, at: path)
|
|
} else if type.isIDReferenceList {
|
|
for token in normalized.split(separator: " ") {
|
|
idTracker.recordReference(String(token), at: path)
|
|
}
|
|
}
|
|
}
|
|
}
|