fix(schema): compare simpleContent fixed value in value space
A fixed value on an element whose type is a complex type with simpleContent was compared as a raw string, so value-space-equal content was wrongly rejected (e.g. "05" against an xs:int fixed "5"). The complex-element fixed check on both the tree path (validate(_:against:)) and the streaming path passed no value type to elementFixedErrors, falling through to a string compare; both now pass the simpleContent simple type as the value type, in lockstep, so the comparison is in value space (cvc-elt.5.2.2.1) as the simple-typed-element path already does. XSTS gate held at 0/37/0/26 across all 14383 groups.
This commit is contained in:
parent
aeff7869f9
commit
f6159191db
@ -28,6 +28,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- A `fixed` value on an element whose type is a complex type with `simpleContent` is
|
||||
now compared in the simple type's value space (cvc-elt.5.2.2.1), not as a raw string
|
||||
(#202), so `05` satisfies an `xs:int` `fixed="5"`. The complex-element fixed check on
|
||||
both the tree and streaming paths now passes the `simpleContent` type as the value
|
||||
type, in lockstep, as the simple-typed-element path already does.
|
||||
|
||||
- The streaming XSD validator now applies an element's `default`/`fixed` value
|
||||
constraint to its simple content (#200): an empty element takes its constraint
|
||||
value, and that value (not the empty string) is validated against the type
|
||||
|
||||
@ -82,7 +82,10 @@ public extension PureXML.Schema {
|
||||
return errors + nilErrors
|
||||
}
|
||||
validateContent(element, type.content, at: path, namespaceBindings: namespaceBindings, into: &errors)
|
||||
errors += elementFixedErrors(element, at: path)
|
||||
// A simpleContent fixed value is compared in its simple type's value space
|
||||
// (cvc-elt.5.2.2.1), e.g. "05" equals an xs:int fixed "5".
|
||||
let simpleContentType: SimpleType? = if case let .simpleContent(simple) = type.content { simple } else { nil }
|
||||
errors += elementFixedErrors(element, valueType: simpleContentType, at: path)
|
||||
return errors
|
||||
}
|
||||
|
||||
|
||||
@ -168,7 +168,10 @@ public extension PureXML.Schema.ComplexValidator {
|
||||
validateAttributes(element, complex, at: path, into: &errors)
|
||||
if let nilErrors = nilErrors(element, at: path) { return errors + nilErrors }
|
||||
shallowContent(element, complex.content, at: path, into: &errors)
|
||||
errors += elementFixedErrors(element, at: path)
|
||||
// A simpleContent fixed value is compared in its simple type's value space
|
||||
// (cvc-elt.5.2.2.1), matching the tree path's validate(_:against:).
|
||||
let simpleContentType: PureXML.Schema.SimpleType? = if case let .simpleContent(simple) = complex.content { simple } else { nil }
|
||||
errors += elementFixedErrors(element, valueType: simpleContentType, at: path)
|
||||
case .typeReference:
|
||||
// The shared resolver also guards a circular chain, which would
|
||||
// otherwise recurse here without terminating.
|
||||
|
||||
38
Tests/SchemaSimpleContentFixedTests.swift
Normal file
38
Tests/SchemaSimpleContentFixedTests.swift
Normal file
@ -0,0 +1,38 @@
|
||||
import Testing
|
||||
@testable import PureXML
|
||||
|
||||
/// A `fixed` value on an element whose type is a complex type with `simpleContent`
|
||||
/// must be compared in the simple type's value space (cvc-elt.5.2.2.1), not as a raw
|
||||
/// string (#202). Both the tree and streaming paths must agree, so "05" satisfies an
|
||||
/// xs:int `fixed="5"` and is not falsely rejected.
|
||||
@Suite("XSD simpleContent fixed value-space (#202)")
|
||||
struct SchemaSimpleContentFixedTests {
|
||||
private let schema = """
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:t" xmlns:t="urn:t">
|
||||
<xs:element name="r" type="t:R" fixed="5"/>
|
||||
<xs:complexType name="R">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:int"><xs:attribute name="u" type="xs:string"/></xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
"""
|
||||
|
||||
private func agreement(_ instance: String) throws -> [String] {
|
||||
let document = try PureXML.Schema.Document(schema)
|
||||
let tree = try document.validate(instance).map(\.reason).sorted()
|
||||
let streamed = try document.validate(streaming: instance).map(\.reason).sorted()
|
||||
#expect(tree == streamed, "streaming disagreed with tree:\n tree: \(tree)\n stream: \(streamed)")
|
||||
return streamed
|
||||
}
|
||||
|
||||
@Test("a value-space-equal fixed simpleContent value is accepted on both paths")
|
||||
func test_valueSpaceEqualAccepted() throws {
|
||||
#expect(try agreement("<t:r xmlns:t=\"urn:t\" u=\"x\">05</t:r>").isEmpty)
|
||||
}
|
||||
|
||||
@Test("a value-space-different fixed simpleContent value is rejected on both paths")
|
||||
func test_valueSpaceDifferentRejected() throws {
|
||||
#expect(try !agreement("<t:r xmlns:t=\"urn:t\" u=\"x\">6</t:r>").isEmpty)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user