fix(schema): a simpleContent restriction's base must be a complex type (#145)
Restricting a built-in or user simple type through <simpleContent><restriction> is invalid (cos-ct-restricts.1 / src-ct.2): a complex type with simple content is built by extending a simple type, not by restricting one. A unit-test fixture that restricted xs:string directly was spec-invalid and now restricts a complexType with simple content instead. XSTS invalid-schemas-accepted 142 to 137, no other bucket moved.
This commit is contained in:
parent
bdd9e96634
commit
903345e764
@ -22,6 +22,8 @@ Second pre-release. Continues the W3C XSTS schema-validity campaign: **invalid-s
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a `simpleContent` restriction's base must be a complex type. Restricting a built-in (`xs:integer`, `xs:anySimpleType`) or a user `simpleType` through `<simpleContent><restriction>` is rejected (`src-ct.2`); a complex type with simple content is built by extending a simple type, not by restricting one. Caught five invalid schemas: invalid-schemas-accepted 142 → 137, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): Particle Valid (Restriction) now enforces the NameAndTypeOK nillable clause. A restricting element may not be `nillable` unless the base element it restricts is also nillable. Caught two invalid schemas: invalid-schemas-accepted 144 → 142, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): Particle Valid (Restriction) now enforces the NameAndTypeOK fixed-value clause. When the base element has a `fixed` value constraint, the restricting element must also be `fixed` to the same value (compared in the base type's value space, so a value-equal pair in different lexical forms is not wrongly flagged). Caught four invalid schemas: invalid-schemas-accepted 148 → 144, no other bucket moved.
|
||||
|
||||
@ -360,11 +360,12 @@ extension PureXML.Validation.SchemaCompile {
|
||||
/// cos-ct-extends.1.4.2.2: a complexContent extension adding element content
|
||||
/// must have a base with complex (or empty) content, not simpleContent.
|
||||
static var complexExtensionBaseValid: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
|
||||
compileRule("A complexContent extension is consistent with its base type") { document in
|
||||
compileRule("A content-model derivation is consistent with its base type") { document in
|
||||
guard let namedTypes = document.namedTypes else { return [] }
|
||||
return PureXML.Schema.SchemaLocatedFinding.unlocated(
|
||||
PureXML.Schema.XSDParser.simpleContentExtensionBaseErrors(document.schema, document.context, namedTypes)
|
||||
+ PureXML.Schema.XSDParser.extensionMixedAgreementErrors(document.schema, document.context, namedTypes),
|
||||
+ PureXML.Schema.XSDParser.extensionMixedAgreementErrors(document.schema, document.context, namedTypes)
|
||||
+ PureXML.Schema.XSDParser.simpleContentRestrictionBaseErrors(document.schema, document.context, namedTypes),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,6 +113,31 @@ extension PureXML.Schema.XSDParser {
|
||||
return errors
|
||||
}
|
||||
|
||||
/// XSD 1.0 `src-ct.2` / Derivation Valid (Restriction): the base of a
|
||||
/// `simpleContent` RESTRICTION must be a complex type (whose content is simple).
|
||||
/// A built-in (`xs:integer`, `xs:anySimpleType`) or a user `simpleType` base is
|
||||
/// invalid: a complex type with simple content is built by EXTENDING a simple
|
||||
/// type, never by restricting one through `simpleContent`. Self-contained schema
|
||||
/// only; a foreign or unresolved base is left alone.
|
||||
static func simpleContentRestrictionBaseErrors(_ schema: XSDTree, _ context: PureXML.Schema.XSDContext, _ types: [String: PureXML.Schema.ElementType]) -> [String] {
|
||||
guard !skipsCrossDocumentRules(schema, compositionLoaded: context.compositionLoaded) else { return [] }
|
||||
let bindings = context.namespaceBindings
|
||||
var errors: [String] = []
|
||||
for content in descendants(schema, named: "simpleContent") {
|
||||
guard let restriction = ExtAllNode.firstChild(content, named: "restriction"),
|
||||
let base = ExtAllNode.attribute(restriction, "base")
|
||||
else { continue }
|
||||
let namespace = ExtAllNode.referenceNamespace(base, bindings)
|
||||
let baseName = ExtAllNode.stripPrefix(base)
|
||||
if namespace == xsdNamespace {
|
||||
errors.append("a simpleContent restriction's base must be a complex type, not the built-in simple type '\(baseName)'")
|
||||
} else if namespace == context.targetNamespace, case .simple? = types[baseName] {
|
||||
errors.append("a simpleContent restriction's base must be a complex type, not the simple type '\(baseName)'")
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
/// XSD 1.0 `cos-ct-extends.1.4.3.2.2.1`: a `complexContent` extension's mixedness
|
||||
/// must match its base type's. The effective content joins the base content and
|
||||
/// the extension's, so a mixed extension may extend only a mixed base and an
|
||||
|
||||
@ -44,6 +44,11 @@ struct SchemaContentOrderTests {
|
||||
@Test("well-formed simpleContent derivations compile")
|
||||
func test_valid() {
|
||||
#expect(!rejects(simpleContent(#"<xs:extension base="xs:string"><xs:attribute name="a" type="xs:string"/></xs:extension>"#)))
|
||||
#expect(!rejects(simpleContent(#"<xs:restriction base="xs:string"><xs:maxLength value="3"/><xs:attribute name="a"/></xs:restriction>"#)))
|
||||
// A simpleContent restriction's base must be a complex type (src-ct.2), so it
|
||||
// restricts a complexType with simple content, not xs:string directly.
|
||||
#expect(!rejects(#"""
|
||||
<xs:complexType name="base"><xs:simpleContent><xs:extension base="xs:string"><xs:attribute name="a"/></xs:extension></xs:simpleContent></xs:complexType>
|
||||
<xs:complexType name="t"><xs:simpleContent><xs:restriction base="base"><xs:maxLength value="3"/></xs:restriction></xs:simpleContent></xs:complexType>
|
||||
"""#))
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ struct ValidationConfigurationTests {
|
||||
"Element value constraints are valid against their declared types",
|
||||
"Complex types extending xs:all groups satisfy XSD placement rules",
|
||||
"Anonymous complex-type restrictions accept a subset of their base's",
|
||||
"A complexContent extension is consistent with its base type",
|
||||
"A content-model derivation is consistent with its base type",
|
||||
"Attribute restrictions are faithful to their bases",
|
||||
"Simple types do not derive from complex types",
|
||||
"Simple-type varieties are declared consistently",
|
||||
|
||||
@ -102,8 +102,11 @@ struct XSTSSuiteTests {
|
||||
/// Enforcing the NameAndTypeOK nillable clause (a restriction may not be nillable
|
||||
/// unless the base element is) then caught two more invalid schemas:
|
||||
/// invalid-schemas accepted 144 → 142, no other bucket moved.
|
||||
/// Requiring a `simpleContent` restriction's base to be a complex type, not a
|
||||
/// built-in or user simple type (src-ct.2), then caught five more invalid
|
||||
/// schemas: invalid-schemas accepted 142 → 137, no other bucket moved.
|
||||
private let knownSchemaValidRejected = 1
|
||||
private let knownSchemaInvalidAccepted = 142
|
||||
private let knownSchemaInvalidAccepted = 137
|
||||
private let knownInstanceValidRejected = 3
|
||||
private let knownInstanceInvalidAccepted = 132
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user