diff --git a/CHANGELOG.md b/CHANGELOG.md index 03ef401..29a40eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ Second pre-release. Continues the W3C XSTS schema-validity campaign: **invalid-s ### Fixed +- XSTS invalid-schemas-accepted (#145): an `xsd:notation` declaration is held to its `(annotation?)` content model. A notation may carry only an optional `annotation` child, so any other element child, or any non-whitespace character content, is now rejected (`notatG`). Caught three invalid schemas: invalid-schemas-accepted 214 → 211, no other bucket moved. + - XSTS invalid-schemas-accepted (#145): a `list` simple type must draw its item type from exactly one of an `itemType` attribute or an inline `simpleType` child (neither, or both, is invalid), and a `union` must declare at least one member type through a `memberTypes` attribute or an inline `simpleType` child (an empty `union` declares none), per `src-simple-type.2`/`.3`. Caught one invalid schema: invalid-schemas-accepted 215 → 214, no other bucket moved. - XSTS invalid-schemas-accepted (#145): a simple type without its own `final` attribute now inherits the schema's `finalDefault` as its `{final}` property (XSD 1.0 Schemas §3.14.2), so `finalDefault="list"` or `"union"` blocks the matching list-item or union-member derivation just as an explicit `final` would. An explicit `final=""` still overrides the default back to no restriction. Caught two invalid schemas: invalid-schemas-accepted 217 → 215, no other bucket moved. diff --git a/Sources/Schema/SchemaNotationValidity.swift b/Sources/Schema/SchemaNotationValidity.swift index 5032165..419134e 100644 --- a/Sources/Schema/SchemaNotationValidity.swift +++ b/Sources/Schema/SchemaNotationValidity.swift @@ -21,6 +21,9 @@ extension PureXML.Schema.XSDParser { if PureXML.Schema.XSDNode.attribute(child, "public") == nil, PureXML.Schema.XSDNode.attribute(child, "system") == nil { errors.append("notation '\(name)' must specify at least one of public or system attributes") } + if notationHasForbiddenContent(child) { + errors.append("notation '\(name)' may contain only an optional annotation, no other element or character content") + } let qName = PureXML.Model.QualifiedName(localName: name, namespaceURI: containerNamespace) declaredNotations.insert(qName) } @@ -35,6 +38,20 @@ extension PureXML.Schema.XSDParser { return errors } + /// Whether a `notation` declaration carries content its `(annotation?)` model + /// forbids: any element child other than an `xsd:annotation`, or any + /// non-whitespace character content. Whitespace and a single optional + /// annotation are allowed. + private static func notationHasForbiddenContent(_ node: XSDTree) -> Bool { + let hasForeignElement = PureXML.Schema.XSDNode.elementChildren(node).contains { + $0.name?.namespaceURI != xsdNamespace || PureXML.Schema.XSDNode.localName($0) != "annotation" + } + let hasText = node.children.contains { + ($0.kind == .text || $0.kind == .cdata) && $0.value.contains { !$0.isWhitespace } + } + return hasForeignElement || hasText + } + private static func walkSimpleTypes( _ node: XSDTree, context: PureXML.Schema.XSDContext, diff --git a/Tests/XSTSSuiteTests.swift b/Tests/XSTSSuiteTests.swift index 6cc4897..962fcfb 100644 --- a/Tests/XSTSSuiteTests.swift +++ b/Tests/XSTSSuiteTests.swift @@ -105,8 +105,12 @@ struct XSTSSuiteTests { /// `memberTypes` or an inline simpleType child (src-simple-type.2/.3), then /// caught one more invalid schema: invalid-schemas accepted 215 → 214, no other /// bucket moved. + /// Enforcing the `(annotation?)` content model of an `xsd:notation` declaration + /// (no element child other than an annotation, no non-whitespace character + /// content) then caught three more invalid schemas: invalid-schemas accepted + /// 214 → 211, no other bucket moved. private let knownSchemaValidRejected = 1 - private let knownSchemaInvalidAccepted = 214 + private let knownSchemaInvalidAccepted = 211 private let knownInstanceValidRejected = 3 private let knownInstanceInvalidAccepted = 132