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.
53 lines
2.0 KiB
Swift
53 lines
2.0 KiB
Swift
@testable import PureXML
|
|
import Testing
|
|
|
|
/// Document-scoped xs:ID/xs:IDREF validation (#147, XSTS idConstrDefs set):
|
|
/// every xs:ID value is unique across the document, and every xs:IDREF/xs:IDREFS
|
|
/// item matches some ID. These had been checked only lexically (as NCNames).
|
|
@Suite("ID and IDREF document constraints")
|
|
struct SchemaIDIDREFTests {
|
|
private var schema: PureXML.Schema.Document {
|
|
get throws {
|
|
try PureXML.Schema.Document("""
|
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
<xs:element name="root">
|
|
<xs:complexType>
|
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
<xs:element name="id" type="xs:ID"/>
|
|
<xs:element name="ref" type="xs:IDREF"/>
|
|
<xs:element name="refs" type="xs:IDREFS"/>
|
|
</xs:choice>
|
|
</xs:complexType>
|
|
</xs:element>
|
|
</xs:schema>
|
|
""")
|
|
}
|
|
}
|
|
|
|
@Test("Unique IDs and a resolving reference validate")
|
|
func test_valid() throws {
|
|
#expect(try schema.validate("<root><id>a</id><id>b</id><ref>a</ref></root>").isEmpty)
|
|
}
|
|
|
|
@Test("A forward IDREF resolves against an ID declared later")
|
|
func test_forwardReference() throws {
|
|
#expect(try schema.validate("<root><ref>a</ref><id>a</id></root>").isEmpty)
|
|
}
|
|
|
|
@Test("A duplicate ID is rejected")
|
|
func test_duplicateID() throws {
|
|
#expect(try !schema.validate("<root><id>a</id><id>a</id></root>").isEmpty)
|
|
}
|
|
|
|
@Test("An IDREF with no matching ID is rejected")
|
|
func test_unresolvedReference() throws {
|
|
#expect(try !schema.validate("<root><id>a</id><ref>x</ref></root>").isEmpty)
|
|
}
|
|
|
|
@Test("IDREFS resolves each item; one unmatched item fails")
|
|
func test_idrefs() throws {
|
|
#expect(try schema.validate("<root><id>a</id><id>b</id><refs>a b</refs></root>").isEmpty)
|
|
#expect(try !schema.validate("<root><id>a</id><refs>a x</refs></root>").isEmpty)
|
|
}
|
|
}
|