fix(schema): an attribute's type must be a simple type (au-props-correct); invalid-schemas-accepted 96 to 95 (#145)
The {type definition} of an attribute is a simple type (au-props-correct /
src-attribute). An attribute whose type resolves to a complex type, or to the
complex ur-type xs:anyType, is now rejected; a built-in or user simple type,
an inline simpleType, or no type (anySimpleType) stays valid. A locally-
declared type takes precedence over the built-in reading, consistent with the
src-ct rules.
Strictly zero false positive: an attribute can never carry a complex type, so
no valid schema is affected. XSTS: invalid-schemas-accepted 96 to 95 (attD002),
valid-schemas-rejected held at 0, no other bucket moved. Differential:
PureXML-stricter unchanged at 87 over 9618 schemas.
This commit is contained in:
parent
a2047956cb
commit
615f668fc2
@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): an attribute's type must be a simple type (`au-props-correct` / `src-attribute`). An `attribute` whose `type` resolves to a complex type, or to the complex ur-type `xs:anyType`, is rejected; a built-in or user simple type, an inline `simpleType`, or no type (`anySimpleType`) stays valid. A locally-declared type takes precedence over the built-in reading. invalid-schemas-accepted 96 → 95, no false positive (valid-schemas-rejected held at 0; differential PureXML-stricter unchanged at 87 over 9618 schemas), no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): an element's `default`/`fixed` value constraint requires a content type that admits character data (`cos-valid-default`). An element whose type is, or whose inline complex type has, element-only or empty content may not carry a value constraint; a simple type, mixed content, the ur-type `xs:anyType`, and an untyped element (also `anyType`) stay valid. The check flags only a content type that is certainly element-only or empty, so it cannot over-reject. invalid-schemas-accepted 99 → 96, no false positive (valid-schemas-rejected held at 0; differential PureXML-stricter unchanged at 87 over 9618 schemas), no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): the base-type kind of a content-model derivation is enforced. A `complexContent` restriction or extension base must be a complex type (`src-ct.1`), so a `simpleType` or a built-in simple type such as `xs:string` is rejected (the ur-type `xs:anyType` is complex and stays valid). A `simpleContent` extension base must be a simple type or a complex type with simple content (`src-ct.2`), so a complex type with element-only, mixed, or empty content, including `xs:anyType`, is rejected. A locally-declared type takes precedence over the built-in reading, so a schema that targets the XSD namespace and extends its own complex types (the schema-for-schemas) is not rejected. invalid-schemas-accepted 104 → 99, no false positive (valid-schemas-rejected held at 0, corroborated by the differential: PureXML-stricter unchanged at 87 over 9618 schemas), no other bucket moved.
|
||||
|
||||
@ -10,6 +10,32 @@ private struct ReachedAttribute {
|
||||
}
|
||||
|
||||
extension PureXML.Schema.XSDParser {
|
||||
/// XSD 1.0 `au-props-correct` / `src-attribute`: the {type definition} of an
|
||||
/// attribute is a SIMPLE type. An `attribute` whose `type` resolves to a complex
|
||||
/// type, or to the complex ur-type `xs:anyType`, is invalid; a built-in or user
|
||||
/// simple type, an inline `simpleType`, or no type (`anySimpleType`) is valid. A
|
||||
/// locally-declared type takes precedence over the built-in reading (a schema may
|
||||
/// target the XSD namespace and define its own components there), so resolve
|
||||
/// `types` first. Self-contained schema; a foreign or unresolved type is left
|
||||
/// alone. Strictly zero false positive: an attribute can never carry a complex
|
||||
/// type, so no valid schema is affected.
|
||||
static func attributeTypeMustBeSimpleErrors(_ 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 attribute in descendants(schema, named: "attribute") where attribute.name?.namespaceURI == xsdNamespace {
|
||||
guard let typeName = AttrNode.attribute(attribute, "type") else { continue }
|
||||
let namespace = AttrNode.referenceNamespace(typeName, bindings)
|
||||
let local = AttrNode.stripPrefix(typeName)
|
||||
if namespace == context.targetNamespace, case .complex? = types[local] {
|
||||
errors.append("an attribute's type must be a simple type, not the complex type '\(local)'")
|
||||
} else if namespace == xsdNamespace, types[local] == nil, local == "anyType" {
|
||||
errors.append("an attribute's type must be a simple type, not 'anyType'")
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
/// Schema-validity findings for attribute-use uniqueness (XSD 1.0
|
||||
/// `ct-props-correct.4` / `ag-props-correct.2`) and the single-ID rule
|
||||
/// (`ct-props-correct.5`): a complex type's or attribute group's complete
|
||||
|
||||
@ -262,7 +262,7 @@ extension PureXML.Validation {
|
||||
static func postCompileValidator() -> Validator<PureXML.Schema.SchemaCompileContext> {
|
||||
Validator<PureXML.Schema.SchemaCompileContext>.defaults(
|
||||
nonReference: [
|
||||
AnyValidation(attributeUsesValid),
|
||||
AnyValidation(attributeUsesValid), AnyValidation(attributeTypesSimple),
|
||||
AnyValidation(idValueConstraintsValid),
|
||||
AnyValidation(userTypeValueConstraintsValid),
|
||||
AnyValidation(extensionAllGroupsValid),
|
||||
@ -341,6 +341,16 @@ extension PureXML.Validation {
|
||||
}
|
||||
|
||||
extension PureXML.Validation.SchemaCompile {
|
||||
/// au-props-correct: an attribute's type is a simple type, never complex.
|
||||
static var attributeTypesSimple: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
|
||||
compileRule("An attribute's type is a simple type") { document in
|
||||
guard let namedTypes = document.namedTypes else { return [] }
|
||||
return PureXML.Schema.SchemaLocatedFinding.unlocated(
|
||||
PureXML.Schema.XSDParser.attributeTypeMustBeSimpleErrors(document.schema, document.context, namedTypes),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Particle Valid (Restriction) for anonymous (inline) complex types, which the
|
||||
/// name-keyed `restrictionsAreSubsets` rule never sees.
|
||||
static var anonymousRestrictionsValid: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
|
||||
|
||||
@ -44,4 +44,18 @@ struct SchemaTopLevelAttributeTests {
|
||||
+ "</xs:complexType></xs:element>",
|
||||
))
|
||||
}
|
||||
|
||||
/// au-props-correct: an attribute's type must be a simple type. A complex type
|
||||
/// (here one with simple content) is rejected; a built-in or user simple type,
|
||||
/// an inline simpleType, or no type (anySimpleType) is valid.
|
||||
@Test("an attribute's type must be a simple type")
|
||||
func test_attributeTypeMustBeSimple() {
|
||||
let complexT = "<xs:complexType name=\"ct\"><xs:simpleContent><xs:extension base=\"xs:integer\"/></xs:simpleContent></xs:complexType>"
|
||||
#expect(!compiles(complexT + "<xs:attribute name=\"a\" type=\"ct\"/>"))
|
||||
#expect(!compiles("<xs:attribute name=\"a\" type=\"xs:anyType\"/>"))
|
||||
let simpleT = "<xs:simpleType name=\"st\"><xs:restriction base=\"xs:string\"/></xs:simpleType>"
|
||||
#expect(compiles(simpleT + "<xs:attribute name=\"a\" type=\"st\"/>"))
|
||||
#expect(compiles("<xs:attribute name=\"a\"><xs:simpleType><xs:restriction base=\"xs:string\"/></xs:simpleType></xs:attribute>"))
|
||||
#expect(compiles("<xs:attribute name=\"a\"/>"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,6 +97,7 @@ struct ValidationConfigurationTests {
|
||||
])
|
||||
#expect(PureXML.Validation.SchemaCompile.postCompileValidator().validationDescriptions == [
|
||||
"Attribute uses are unique and declare at most one ID attribute",
|
||||
"An attribute's type is a simple type",
|
||||
"ID-typed value constraints are valid",
|
||||
"Element value constraints are valid against their declared types",
|
||||
"Complex types extending xs:all groups satisfy XSD placement rules",
|
||||
|
||||
@ -151,9 +151,10 @@ struct XSTSSuiteTests {
|
||||
/// a local type takes precedence over the built-in reading so the schema-for-
|
||||
/// schemas, which targets the XSD namespace, is not rejected) 104 -> 99; and the
|
||||
/// element value-constraint content type (cos-valid-default: a default/fixed needs
|
||||
/// simple or mixed content, not element-only) 99 -> 96.
|
||||
/// simple or mixed content, not element-only) 99 -> 96; and an attribute's type
|
||||
/// must be a simple type, never a complex type (au-props-correct) 96 -> 95.
|
||||
private let knownSchemaValidRejected = 0
|
||||
private let knownSchemaInvalidAccepted = 96
|
||||
private let knownSchemaInvalidAccepted = 95
|
||||
private let knownInstanceValidRejected = 0
|
||||
private let knownInstanceInvalidAccepted = 133
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user