fix(schema): reject an empty-string namespace value (#145)

A namespace name must be a non-empty anyURI, so <schema targetNamespace=""> and
<import namespace=""> are invalid. Omitting the attribute (no target namespace,
or a no-namespace import) stays valid.

XSTS invalid-schemas-accepted 134 to 132, no other bucket moved.
This commit is contained in:
Mihaela Mihaljevic 2026-06-17 18:06:08 +02:00
parent 30421073a1
commit f61e7d0613
4 changed files with 22 additions and 1 deletions

View File

@ -22,6 +22,8 @@ Second pre-release. Continues the W3C XSTS schema-validity campaign: **invalid-s
### Fixed
- XSTS invalid-schemas-accepted (#145): a namespace value may not be the empty string. `<schema targetNamespace="">` and `<import namespace="">` are rejected, since a namespace name must be a non-empty `anyURI` (omitting the attribute, for no target namespace or a no-namespace import, stays valid). Caught two invalid schemas: invalid-schemas-accepted 134 → 132, no other bucket moved.
- XSTS invalid-schemas-accepted (#145): a wildcard restriction may not weaken `processContents`. When a complex type restricts another, a restricting `xs:any` must have a `processContents` at least as strong as the base wildcard's (`strict` > `lax` > `skip`; Wildcard Subset, §3.10.6), in addition to narrowing the namespace. Caught three invalid schemas: invalid-schemas-accepted 137 → 134, no other bucket moved.
- 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.

View File

@ -66,6 +66,7 @@ extension PureXML.Schema.XSDParser {
append(topLevelDeclarationErrors(schema), at: schema, into: &findings)
append(nestedNamedDefinitionErrors(schema), at: schema, into: &findings)
append(anySimpleTypeRestrictionErrors(schema), at: schema, into: &findings)
append(emptyNamespaceErrors(schema), at: schema, into: &findings)
return findings
}

View File

@ -224,4 +224,19 @@ extension PureXML.Schema.XSDParser {
}
return []
}
/// A namespace value must be a non-empty `anyURI` (or absent): the empty string
/// is not a legal namespace name. So `<schema targetNamespace="">` and
/// `<import namespace="">` are invalid, while omitting the attribute (no target
/// namespace, a no-namespace import) stays valid.
static func emptyNamespaceErrors(_ schema: XSDTree) -> [String] {
var errors: [String] = []
if PureXML.Schema.XSDNode.attribute(schema, "targetNamespace") == "" {
errors.append("the 'targetNamespace' attribute may not be the empty string")
}
for importNode in descendants(schema, named: "import") where PureXML.Schema.XSDNode.attribute(importNode, "namespace") == "" {
errors.append("an 'import' namespace may not be the empty string")
}
return errors
}
}

View File

@ -108,8 +108,11 @@ struct XSTSSuiteTests {
/// Requiring a restricting wildcard's `processContents` to be at least as strong
/// as the base's (strict > lax > skip; Wildcard Subset §3.10.6) then caught three
/// more invalid schemas: invalid-schemas accepted 137 → 134, no other bucket moved.
/// Rejecting an empty-string namespace value (`targetNamespace=""`, `import
/// namespace=""`) then caught two more invalid schemas: invalid-schemas accepted
/// 134 → 132, no other bucket moved.
private let knownSchemaValidRejected = 1
private let knownSchemaInvalidAccepted = 134
private let knownSchemaInvalidAccepted = 132
private let knownInstanceValidRejected = 3
private let knownInstanceInvalidAccepted = 132