fix(schema): reject an attribute reference whose fixed value contradicts its global (#145)
An attribute use that references a global attribute carrying a `fixed` value constraint may not contradict it (au-props-correct.2): a `fixed` on the reference whose value differs from the global's, or a `default` on a reference to a fixed attribute, is invalid. A reference that omits its own value constraint inherits the global's and stays valid. The two `fixed` values are compared in the attribute type's value space, so a value-equal pair written in different lexical forms (`01` for `1`) is not flagged. The global is resolved by local name and only checked once its own namespace matches the reference's resolved namespace, so a same-local-name attribute imported from another namespace cannot surface as the wrong global and contradict a valid reference. Caught two invalid schemas: XSTS invalid-schemas-accepted 232 -> 230, no other bucket moved.
This commit is contained in:
parent
a96e5ce3ac
commit
c80a8e06c4
@ -22,6 +22,8 @@ Second pre-release. Continues the W3C XSTS schema-validity campaign: **invalid-s
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): an attribute use that references a global attribute carrying a `fixed` value constraint may not contradict it. A `fixed` on the reference whose value differs from the global's (compared in the attribute type's value space, so `1` and `01` are not wrongly flagged), or a `default` on a reference to a fixed global, is invalid (`au-props-correct.2`). A reference that omits its own value constraint inherits the global's fixed value and stays valid. Caught two invalid schemas: invalid-schemas-accepted 232 → 230, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a `complexContent` extension that adds element content may not extend a base whose whole content is a non-empty `all` group; the base's `all` would be nested in the sequence joining base and extension content (`cos-all-limited`). An empty-`all` base, or an attribute-only extension, stays valid. Caught one invalid schema: invalid-schemas-accepted 233 → 232, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a `complexContent` extension that adds element content (a non-empty model group) may not extend a base whose content is simple (`cos-ct-extends.1.4.2.2`); a simple-content type is extended through `simpleContent`. An attribute-only `complexContent` extension of a simpleContent base stays valid (the `complexContent`-around-`simpleContent` idiom). Caught two invalid schemas: invalid-schemas-accepted 235 → 233, no other bucket moved.
|
||||
|
||||
@ -34,6 +34,41 @@ extension PureXML.Schema.XSDParser {
|
||||
let label = AttrNode.attribute(type, "name").map { "complex type '\($0)'" } ?? "an anonymous complex type"
|
||||
errors += attributeSetErrors(attributeDeclarations(under: attributeContainer(of: type), context), label)
|
||||
}
|
||||
errors += attributeRefValueConstraintErrors(container, context)
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
/// XSD 1.0 `au-props-correct.2`: when an attribute use references a global
|
||||
/// attribute that has a `fixed` value constraint, the use may not contradict
|
||||
/// it: a `fixed` whose value differs, or a `default`, on the reference is
|
||||
/// invalid (the use either inherits the fixed value or restates the same one).
|
||||
/// Compared in the attribute type's value space, so a value-equal pair written
|
||||
/// in different lexical forms (`1` and `01`) is not wrongly flagged.
|
||||
///
|
||||
/// The global declaration is looked up by local name (the only key the global
|
||||
/// pool carries), so a reference is checked against it only once the resolved
|
||||
/// declaration's own namespace matches the reference's resolved namespace. That
|
||||
/// rejects a same-local-name collision across namespaces (an imported `imp:a`
|
||||
/// versus a local `a`), where the local-name pool could otherwise surface the
|
||||
/// wrong global and contradict a valid reference.
|
||||
private static func attributeRefValueConstraintErrors(_ container: XSDTree, _ context: PureXML.Schema.XSDContext) -> [String] {
|
||||
var errors: [String] = []
|
||||
for use in descendants(container, named: "attribute") {
|
||||
guard let ref = AttrNode.attribute(use, "ref"),
|
||||
let declaration = context.globalAttributes[AttrNode.stripPrefix(ref)],
|
||||
let resolved = attributeUse(declaration, context),
|
||||
resolved.name.namespaceURI == AttrNode.referenceNamespace(ref, context.namespaceBindings),
|
||||
let globalFixed = AttrNode.attribute(declaration, "fixed")
|
||||
else { continue }
|
||||
if let useFixed = AttrNode.attribute(use, "fixed") {
|
||||
let equal = resolved.type.valueMatches(useFixed, literal: globalFixed) || useFixed == globalFixed
|
||||
if !equal {
|
||||
errors.append("attribute reference to '\(AttrNode.stripPrefix(ref))' must use its fixed value '\(globalFixed)', not '\(useFixed)'")
|
||||
}
|
||||
} else if AttrNode.attribute(use, "default") != nil {
|
||||
errors.append("attribute reference to '\(AttrNode.stripPrefix(ref))' has a fixed value and may not specify a default")
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
@ -87,8 +87,12 @@ struct XSTSSuiteTests {
|
||||
/// base whose whole content is an `all` group (the all would be nested in the
|
||||
/// joining sequence; cos-all-limited) then caught one more invalid schema:
|
||||
/// invalid-schemas accepted 233 → 232, no other bucket moved.
|
||||
/// Rejecting an attribute use that references a global attribute with a `fixed`
|
||||
/// value constraint but contradicts it (a value-space-differing `fixed`, or a
|
||||
/// `default`; au-props-correct.2) then caught two more invalid schemas:
|
||||
/// invalid-schemas accepted 232 → 230, no other bucket moved.
|
||||
private let knownSchemaValidRejected = 1
|
||||
private let knownSchemaInvalidAccepted = 232
|
||||
private let knownSchemaInvalidAccepted = 230
|
||||
private let knownInstanceValidRejected = 3
|
||||
private let knownInstanceInvalidAccepted = 132
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user