An xsi:type value is a QName: a prefix binds through that prefix, an unprefixed
name through the in-scope default namespace, and with no default namespace an
unprefixed name is in no namespace. PureXML stores each named type under both its
namespaced key and a bare local-name alias (for lenient lookup), so an unprefixed
xsi:type="Test" matched a {targetNS}Test through the alias even when the instance
had no default namespace, wrongly typing an otherwise-undeclared root and
accepting the document (W3C XSTS targetNS00101m; libxml2 rejects it identically).
xsiTypeReference now keys an unprefixed xsi:type to the in-scope default namespace
(none here) rather than returning the bare local name, so xsi:type="Test" names
no-namespace Test, which does not exist; the root then has neither a declaration
nor a usable type and the instance is invalid. A prefixed xsi:type and an
unprefixed one under a default namespace equal to the target namespace are
unaffected, and the child-element builtin-substitution path keeps its bare-name
fallback (xsiTypeName), so an unprefixed builtin still substitutes where valid.
Verified over the full W3C XSTS corpus in release: invalid-instances-accepted
6 -> 5, valid-instances-rejected held at 0 across all 14383 groups, full suite
(1840 tests) and wasm green. An adversarial critic traced every resolveNamedType
branch, including the unprefixed-builtin-via-key case, and confirmed the only
path that no longer resolves corresponds to a spec-invalid reference, so no valid
instance is newly rejected.
58 lines
2.8 KiB
Swift
58 lines
2.8 KiB
Swift
import Testing
|
|
@testable import PureXML
|
|
|
|
/// An `xsi:type` value is a QName resolved in the instance's namespace context:
|
|
/// an unprefixed name uses the in-scope default namespace, and with none it is in
|
|
/// no namespace, so it does not name a namespaced type of the same local name.
|
|
/// Mirrors W3C XSTS targetNS00101m (CType): a schema with a `targetNamespace`
|
|
/// declares a type but no element, and a root with `xsi:type` but no element
|
|
/// declaration is valid only when the `xsi:type` QName resolves to that type.
|
|
@Suite("xsi:type QName resolves in the instance namespace context")
|
|
struct SchemaXSITypeNamespaceTests {
|
|
private func schema() throws -> PureXML.Schema.Document {
|
|
try PureXML.Schema.Document("""
|
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="targetNS" targetNamespace="targetNS">
|
|
<xsd:complexType name="Test"><xsd:sequence>
|
|
<xsd:element name="abc" type="xsd:string"/>
|
|
</xsd:sequence></xsd:complexType>
|
|
</xsd:schema>
|
|
""")
|
|
}
|
|
|
|
@Test("an unprefixed xsi:type with no default namespace does not name a namespaced type")
|
|
func test_unprefixedNoDefault() throws {
|
|
// xsi:type="Test" with no default namespace in scope -> no-namespace Test,
|
|
// which does not exist; the root `test` has no declaration -> invalid.
|
|
let xml = """
|
|
<t:test xmlns:t="targetNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Test"><abc>1</abc></t:test>
|
|
"""
|
|
#expect(try !schema().validate(xml).isEmpty)
|
|
}
|
|
|
|
@Test("a prefixed xsi:type resolves through its prefix's namespace")
|
|
func test_prefixedResolves() throws {
|
|
let xml = """
|
|
<t:test xmlns:t="targetNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="t:Test"><abc>1</abc></t:test>
|
|
"""
|
|
#expect(try schema().validate(xml).isEmpty)
|
|
}
|
|
|
|
@Test("an unprefixed xsi:type resolves through the in-scope default namespace")
|
|
func test_unprefixedDefaultNamespace() throws {
|
|
// A simpleContent type and a default namespace equal to the target namespace:
|
|
// unprefixed "T" names {targetNS}T and the text content validates, with no
|
|
// child-element qualification to confound the resolution under test.
|
|
let schema = try PureXML.Schema.Document("""
|
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="targetNS" targetNamespace="targetNS">
|
|
<xsd:complexType name="T"><xsd:simpleContent>
|
|
<xsd:extension base="xsd:string"/>
|
|
</xsd:simpleContent></xsd:complexType>
|
|
</xsd:schema>
|
|
""")
|
|
let xml = """
|
|
<e xmlns="targetNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="T">hello</e>
|
|
"""
|
|
#expect(try schema.validate(xml).isEmpty)
|
|
}
|
|
}
|