fix(schema): apply cos-st-derived-ok to NameAndTypeOK over a union base (#359)
A particle restriction whose restricting element has a union-typed base element was checked by structural member subsetting: PureXML accepted a separately declared union whenever its members were a subset of the base union's. That is not the spec's derivation relation. The NameAndTypeOK type clause (XSD 1.0 section 3.9.6) requires the restricting element's type to be validly derived from the base element's type per Type Derivation OK (Simple), cos-st-derived-ok. The restricting type is now valid over a union base only if it is the base type, derives from it through a declared restriction chain, or (clause 2.2.4) validly derives from one of the union's member types. Scoped to the element-restriction path, so no attribute or simple-type derivation check moved. Catches particlesIk011 (a fresh union(integer) is not a restriction of union(integer, string)): XSTS invalid-schemas-accepted 9 to 8, valid-schemas- rejected held at 0 over the full corpus (the cardinal no-over-rejection check). Disclosed: particlesIk025/Ik027, where the restricting type derives from a union member, are accepted per cos-st-derived-ok 2.2.4, a contested reading their XSTS invalid expectation does not share. An in-repo test that asserted the old structural-subset behavior is corrected.
This commit is contained in:
parent
fef8520d68
commit
0af92bcf8d
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a particle restriction whose restricting element has a union-typed base element now applies Type Derivation OK (Simple) (`cos-st-derived-ok`) rather than structural member subsetting. The NameAndTypeOK type clause (§3.9.6) requires the restricting element's type to be validly derived from the base element's type; PureXML accepted a *separately declared* union whenever its member types were a subset of the base union's members, which is not the spec's derivation relation. The restricting type is now valid over a union base only if it is the base type, derives from it through a declared restriction chain, or (clause 2.2.4) validly derives from one of the union's member types. Catches particlesIk011 (a fresh `union(integer)` is not a restriction of `union(integer, string)`): invalid-schemas-accepted 9 to 8, with valid-schemas-rejected held at 0 (verified over the full XSTS; the change is scoped to the element-restriction path, so no attribute or simple-type derivation check moved). Disclosed divergence: particlesIk025/Ik027, where the restricting type derives from a union *member*, are accepted per `cos-st-derived-ok` clause 2.2.4, a contested reading their XSTS `invalid` expectation does not share.
|
||||
|
||||
## [0.4.8] - 2026-06-27
|
||||
|
||||
### Removed
|
||||
|
||||
@ -41,8 +41,17 @@ extension PureXML.Schema.ParticleRestriction {
|
||||
if let baseResolved = resolveType(baseTypeName, types), let derivedResolved = resolveType(restrictedTypeName, types) {
|
||||
switch (derivedResolved, baseResolved) {
|
||||
case let (.simple(derivedSimple), .simple(baseSimple)):
|
||||
if case .union = baseSimple.variety {
|
||||
return PureXML.Schema.XSDParser.isSimpleTypeRestrictionOK(derived: derivedSimple, base: baseSimple)
|
||||
if case let .union(baseMembers) = baseSimple.variety {
|
||||
// cos-st-derived-ok with a union base: the restricting type
|
||||
// validly derives iff it is the base type, derives from it
|
||||
// through a declared restriction chain (typeDerivesByRestriction
|
||||
// returns true for an equal name), or (clause 2.2.4) validly
|
||||
// derives from one of the union's member types. A separately
|
||||
// declared union whose members merely subset the base union's is
|
||||
// NOT a derivation (particlesIk011); structural member subsetting
|
||||
// is not the spec's derivation relation.
|
||||
if typeDerivesByRestriction(restrictedTypeName, baseTypeName, derivation, types) { return true }
|
||||
return baseMembers.contains { PureXML.Schema.XSDParser.isSimpleTypeRestrictionOK(derived: derivedSimple, base: $0) }
|
||||
}
|
||||
case (.complex, .simple):
|
||||
return false
|
||||
|
||||
@ -303,14 +303,18 @@ struct XSDParticleRestrictionTests {
|
||||
// a union member (xs:string) validly restricts the union-typed base element.
|
||||
#expect(doc("xs:string", base: "u", types: userTypes) != nil)
|
||||
|
||||
// a union restricting another union (subset members): valid.
|
||||
let unions = """
|
||||
<xs:simpleType name="U1"><xs:union memberTypes="xs:integer xs:string"/></xs:simpleType>
|
||||
<xs:simpleType name="U2"><xs:union memberTypes="xs:integer xs:string xs:boolean"/></xs:simpleType>
|
||||
<xs:simpleType name="L1"><xs:list itemType="xs:string"/></xs:simpleType>
|
||||
"""
|
||||
#expect(doc("U1", base: "U2", types: unions) != nil)
|
||||
// a union restricting another union but adding/having unmatching members: invalid.
|
||||
// A separately-declared union whose members merely subset the base union's
|
||||
// is NOT a valid derivation: cos-st-derived-ok requires the restricting
|
||||
// type to be the base, derive from it through a declared restriction chain,
|
||||
// or derive from one of its members. Structural member subsetting is not
|
||||
// the spec's derivation relation (cf. XSTS particlesIk011).
|
||||
#expect(doc("U1", base: "U2", types: unions) == nil)
|
||||
// The reverse (U2 has a member U1 lacks) is invalid for the same reason.
|
||||
#expect(doc("U2", base: "U1", types: unions) == nil)
|
||||
// a list type restricting a union type: invalid.
|
||||
#expect(doc("L1", base: "U1", types: unions) == nil)
|
||||
|
||||
@ -44,7 +44,13 @@ struct XSTSSuiteTests {
|
||||
/// a base `required` attribute may not become `optional`) now also runs over a
|
||||
/// `simpleContent` restriction, not only `complexContent` (particlesZ030_d,
|
||||
/// which libxml2 also rejects).
|
||||
private let knownSchemaInvalidAccepted = 9
|
||||
/// 9 -> 8, NameAndTypeOK over a union base now applies cos-st-derived-ok: a
|
||||
/// separately-declared union whose members merely subset the base union's is
|
||||
/// not a valid derivation (particlesIk011); a genuine restriction of the union
|
||||
/// or of one of its members still passes. (Ik025/Ik027, where the restricting
|
||||
/// type derives from a union member, are accepted per cos-st-derived-ok 2.2.4,
|
||||
/// a disclosed divergence from their contested XSTS `invalid` expectation.)
|
||||
private let knownSchemaInvalidAccepted = 8
|
||||
private let knownInstanceValidRejected = 0
|
||||
/// Instance bucket (133 -> 22), per-step deltas in CHANGELOG.md: xsi:type must derive from the declared
|
||||
/// type; anyType cannot stand in for anySimpleType; an untyped substitutionGroup member inherits its head's
|
||||
|
||||
Loading…
Reference in New Issue
Block a user