fix(schema): a ref resolving to the XSD namespace is undeclared
isUndeclaredReferenceRef fell through to a lenient accept when a ref or substitutionGroup resolved to the XSD namespace but the schema did not target it. The XSD namespace declares no referenceable user component (element, group, attribute, attribute group), so such a reference is undeclared, the asymmetry isUndeclaredReferenceType already handled for type/base. This is reached when an unprefixed reference picks up a default xmlns of the XSD namespace, so it is not in the target namespace where the schema's own components live: xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="foo" with <element ref="root"/> resolves to {XSD}root, not {foo}root (XSTS xsd013/xsd014). A schema that itself targets the XSD namespace is the inTargetNamespace case, and a genuinely loaded XSD-namespace document is the foreignPools case before this branch, so both are unaffected. Verified against the full W3C XSTS 2006-11-06 suite: invalid-schemas-accepted 29 -> 27, valid-schemas-rejected held at 0, no other bucket moved. Adds reference tests for both reject cases and a qualified-ref guard.
This commit is contained in:
parent
0a76658a28
commit
7efc64479b
@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- A schema reference (`ref`/`substitutionGroup`) that resolves to the XSD namespace is now rejected as undeclared. The XSD namespace declares no referenceable user component, so `isUndeclaredReferenceType` already rejected a `type`/`base` in it, but `isUndeclaredReferenceRef` fell through to a lenient accept. This is reached when an unprefixed reference picks up a default `xmlns` of the XSD namespace, so it is not in the target namespace where the schema's own components live: e.g. `xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="foo"` with `<element ref="root"/>` resolves to `{XSD}root`, not `{foo}root`, and is undeclared. A schema that itself targets the XSD namespace, and a genuinely loaded XSD-namespace document, are unaffected. XSTS invalid-schemas-accepted 29 → 27 (xsd013/xsd014), valid-schemas-rejected held at 0.
|
||||
- Unique Particle Attribution now checks a `complexContent` extension against its EFFECTIVE content model (the base type's content followed by the extension's), not just the extension's own particles. A base whose trailing particle can recur or end optionally competes with the extension's leading particles, so an element could match either across the extension boundary; that cross-boundary non-determinism was missed and the schema wrongly accepted. The base content is resolved and prepended only for a local (target-namespace), non-cyclic base chain; a foreign, built-in (`xs:anyType`), unresolved, or cyclic base leaves the check on the extension's own content, so no valid schema is newly rejected. XSTS invalid-schemas-accepted 31 → 29 (particlesZ022 and one more), valid-schemas-rejected held at 0.
|
||||
- Unique Particle Attribution now detects overlapping `xs:any` wildcards involving `##other`. `wildcardsOverlap` returned false for any pair involving `##other`, so two competing wildcards whose namespaces actually intersect, two `##other` constraints (which always share infinitely many namespaces) or `##other` against an enumerated set naming a non-target, non-absent namespace, were not flagged as non-deterministic, and the schema was wrongly accepted. The overlap is now computed correctly: `##other`∩`##other` always overlaps, and `##other`∩enumerated overlaps iff the set names a namespace that is neither absent (`##local`) nor the target. Disjoint cases (`##other` against `##local` or against the target namespace) remain deterministic, so no valid schema is newly rejected. XSTS invalid-schemas-accepted 35 → 31 (wildI009/wildI013/wildI014 and one more), valid-schemas-rejected held at 0.
|
||||
- The content-model matcher no longer blows up on a nested model group with a huge but
|
||||
|
||||
@ -73,6 +73,16 @@ extension PureXML.Schema.XSDParser {
|
||||
if let foreign = context.foreignPools[uri]?[poolName] {
|
||||
return !foreign.contains(localPart)
|
||||
}
|
||||
if uri == xsdNamespace {
|
||||
// The XSD namespace declares no referenceable user component (element,
|
||||
// group, attribute, attribute group), so a reference resolving to it is
|
||||
// undeclared. This is reached when an unprefixed reference picks up a
|
||||
// default `xmlns` of the XSD namespace, so it is NOT in the target
|
||||
// namespace (XSTS xsd013/xsd014); the schema that itself targets the XSD
|
||||
// namespace is the `inTargetNamespace` case above, and a genuinely loaded
|
||||
// XSD-namespace document is the `foreignPools` case just before.
|
||||
return true
|
||||
}
|
||||
if uri == nil || uri == "" {
|
||||
if context.chameleonNamespace, context.pools[poolName]?.contains(localPart) == true { return false }
|
||||
if !(context.targetNamespace == nil || context.targetNamespace == "") { return true }
|
||||
|
||||
@ -44,6 +44,33 @@ struct SchemaReferenceTests {
|
||||
try compile("<xs:simpleType name=\"t\"><xs:restriction base=\" xs:string \"/></xs:simpleType>")
|
||||
}
|
||||
|
||||
@Test("a ref resolving to the XSD namespace is undeclared")
|
||||
func test_refResolvingToXSDNamespaceIsUndeclared() throws {
|
||||
// The default xmlns is the XSD namespace, so an unprefixed `ref="root"`
|
||||
// resolves to {XSD}root, not {foo}root, and the XSD namespace declares no
|
||||
// referenceable user element: undeclared (XSTS xsd013/xsd014).
|
||||
let refRoot = """
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:foo="foo" targetNamespace="foo">
|
||||
<element name="root"><complexType><sequence><element ref="root"/></sequence></complexType></element>
|
||||
</schema>
|
||||
"""
|
||||
#expect(throws: (any Error).self) { _ = try PureXML.Schema.Document(refRoot) }
|
||||
let refUndef = """
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:foo="foo" targetNamespace="foo">
|
||||
<element name="root"><complexType><sequence><element ref="undef"/></sequence></complexType></element>
|
||||
</schema>
|
||||
"""
|
||||
#expect(throws: (any Error).self) { _ = try PureXML.Schema.Document(refUndef) }
|
||||
// Guard: the same shape with the ref qualified to the target resolves, so the
|
||||
// XSD-namespace rule does not reject a correctly-namespaced reference.
|
||||
let qualified = """
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:foo="foo" targetNamespace="foo">
|
||||
<element name="root"><complexType><sequence><element ref="foo:root"/></sequence></complexType></element>
|
||||
</schema>
|
||||
"""
|
||||
_ = try PureXML.Schema.Document(qualified)
|
||||
}
|
||||
|
||||
@Test("references are not checked when an import may supply them")
|
||||
func test_importSkipsCheck() throws {
|
||||
// A dangling reference into an imported namespace is tolerated: the default
|
||||
|
||||
@ -146,9 +146,9 @@ struct XSTSSuiteTests {
|
||||
/// model-group occurrence, identity-constraint content, derivation base kind, attribute/simple-type,
|
||||
/// composition, simpleContent inline-type, complexContent mixedness, and substitution-group anySimpleType checks.
|
||||
/// src-resolve (#185) 43->39; xsi:Not-Allowed (#183) 39->37; NameAndTypeOK restriction-only + cos-all-limited group-ref (#158) 37->35.
|
||||
/// UPA: `##other` overlap 35->31 (wildI009/I013/I014+1); effective extension content model 31->29 (particlesZ022+1); valid-rejected held at 0.
|
||||
/// UPA `##other` overlap 35->31; UPA effective extension model 31->29; ref to XSD namespace is undeclared 29->27 (xsd013/xsd014); valid-rejected held at 0.
|
||||
private let knownSchemaValidRejected = 0
|
||||
private let knownSchemaInvalidAccepted = 29
|
||||
private let knownSchemaInvalidAccepted = 27
|
||||
private let knownInstanceValidRejected = 0
|
||||
/// Instance bucket (133 -> 26), per-step deltas in CHANGELOG.md: xsi:type must derive from the
|
||||
/// declared type (complex/atomic/list/union via the element-ref chain); anyType cannot stand in
|
||||
|
||||
Loading…
Reference in New Issue
Block a user