fix(schema): an unprefixed type ref to a target-namespace type is undeclared
isUndeclaredReferenceType matched a no-namespace type/base/itemType/memberTypes
reference by local name, ignoring that an unprefixed QName with no default
xmlns resolves to the absent namespace: type="t" is {}t, not {urn:x}t where the
type is declared, so the reference does not resolve (XSD 1.0 §3.15.3). It now
mirrors isUndeclaredReferenceRef's nil-namespace branch: a no-namespace
reference is undeclared when the schema has a non-empty target namespace; a
chameleon-included global and an imported no-namespace type (via the foreign
pools, checked first) remain accepted.
This corrects an asymmetry where the ref side already rejected the pattern but
the type side did not. The existing SchemaXSIAttributeTests case that asserted
this very pattern compiles used an invalid schema (the same shape as XSTS
addB009/test66059); its type reference is now qualified (tns:attRef), which
preserves the test's xsi:Not-Allowed intent while being valid.
Verified against the full W3C XSTS 2006-11-06 suite: invalid-schemas-accepted
27 -> 25 (addB009/test66059 and one more), valid-schemas-rejected held at 0,
no other bucket moved. Adds a reference test for the type-side rule.
This commit is contained in:
parent
7efc64479b
commit
6e7f1b7bfc
@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- An unprefixed `type`/`base`/`itemType`/`memberTypes` reference to a type declared in a non-empty target namespace is now rejected as undeclared. With no default `xmlns`, an unprefixed QName resolves to the absent namespace, so `type="t"` is `{}t`, not `{urn:x}t` where the type lives; `isUndeclaredReferenceType` matched the type by local name and accepted it. It now mirrors `isUndeclaredReferenceRef`: a no-namespace reference is undeclared when the schema has a non-empty target namespace (a chameleon-included global, and an imported no-namespace type via the foreign pools, remain accepted). XSTS invalid-schemas-accepted 27 → 25 (addB009/test66059 and one more), valid-schemas-rejected held at 0.
|
||||
- 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.
|
||||
|
||||
@ -54,6 +54,14 @@ extension PureXML.Schema.XSDParser {
|
||||
return !foreignTypes.contains(localPart)
|
||||
}
|
||||
if uri == nil || uri == "" {
|
||||
// A no-namespace (unprefixed, no default `xmlns`) reference resolves to
|
||||
// the absent namespace. It matches a chameleon-included global adopting
|
||||
// the includer's namespace; otherwise, when the schema has a non-empty
|
||||
// target namespace, it cannot name a type that lives there, so it is
|
||||
// undeclared (XSTS addB009 / test66059). This mirrors the same branch in
|
||||
// `isUndeclaredReferenceRef`.
|
||||
if context.chameleonNamespace, context.types.contains(localPart) { return false }
|
||||
if !(context.targetNamespace == nil || context.targetNamespace == "") { return true }
|
||||
return !context.types.contains(localPart)
|
||||
}
|
||||
return false
|
||||
|
||||
@ -71,6 +71,27 @@ struct SchemaReferenceTests {
|
||||
_ = try PureXML.Schema.Document(qualified)
|
||||
}
|
||||
|
||||
@Test("an unprefixed type reference to a target-namespace type is undeclared")
|
||||
func test_unprefixedTypeRefToTargetNamespace() throws {
|
||||
// No default xmlns, so `type="t"` resolves to {}t, not {urn:x}t where the
|
||||
// type is declared: undeclared (XSTS addB009 / test66059).
|
||||
let unprefixed = """
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:x">
|
||||
<xsd:complexType name="t"><xsd:sequence/></xsd:complexType>
|
||||
<xsd:element name="e" type="t"/>
|
||||
</xsd:schema>
|
||||
"""
|
||||
#expect(throws: (any Error).self) { _ = try PureXML.Schema.Document(unprefixed) }
|
||||
// Guard: qualifying the reference to the target namespace resolves.
|
||||
let qualified = """
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:x="urn:x" targetNamespace="urn:x">
|
||||
<xsd:complexType name="t"><xsd:sequence/></xsd:complexType>
|
||||
<xsd:element name="e" type="x:t"/>
|
||||
</xsd: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
|
||||
|
||||
@ -80,13 +80,16 @@ struct SchemaXSIAttributeTests {
|
||||
|
||||
@Test("the same qualified attribute targeting a non-XSI namespace is valid")
|
||||
func test_qualifiedAttributeOutsideXSIValid() {
|
||||
// The type reference is qualified to the target namespace (`tns:attRef`); an
|
||||
// unprefixed `attRef` with no default xmlns would resolve to {}attRef, not
|
||||
// {urn:ok}attRef, and is itself invalid (see SchemaReferenceTests).
|
||||
let schema = """
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="urn:ok"
|
||||
targetNamespace="urn:ok" attributeFormDefault="qualified">
|
||||
<xsd:complexType name="attRef">
|
||||
<xsd:attribute name="ca1"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="doc" type="attRef"/>
|
||||
<xsd:element name="doc" type="tns:attRef"/>
|
||||
</xsd:schema>
|
||||
"""
|
||||
#expect(compiles(schema), "qualifying into a non-XSI namespace is fine")
|
||||
|
||||
@ -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; UPA effective extension model 31->29; ref to XSD namespace is undeclared 29->27 (xsd013/xsd014); valid-rejected held at 0.
|
||||
/// UPA `##other` 35->31; UPA effective-extension model 31->29; ref to XSD ns undeclared 29->27; unprefixed type-ref to target ns undeclared 27->25; valid-rejected 0.
|
||||
private let knownSchemaValidRejected = 0
|
||||
private let knownSchemaInvalidAccepted = 27
|
||||
private let knownSchemaInvalidAccepted = 25
|
||||
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