Consolidates the in-progress #146 work; valid-instances-rejected reaches 4 on the 2006-11-06 XSTS archive (buckets now 1/262/4/147). Regex: match Unicode scalars rather than grapheme clusters; the empty pattern matches only the empty string; pin the category repertoire to Unicode 3.2, the version the corpus is consistent at, so code points added in 3.2 (Tagalog, Cyrillic Komi) are word characters while later additions (the Tamil digit zero) stay unassigned and match \D. New XSDCategory and a 3.2 assignment table derived from DerivedAge, replacing the old Unicode31 files. Content model: assess each child against the particle the content automaton matched, not a by-name lookup (#180). Two same-named particles keep their own fixed values, and an element matching a skip wildcard is no longer validated against its global declaration. Selection is made reproducible when an ambiguous schema slips past the UPA check. XSTS runner: compile and merge every schemaDocument in a schemaTest, not just the first; this also surfaced one previously-masked invalid-instance acceptance (recorded in the baselines). Also folds in attribute-group anyAttribute inheritance, extension wildcard union, namespace-qualified type tables for multi-document xsi:schemaLocation, per-container elementFormDefault, strict and lax attribute wildcard validation, built-in type resolution, and xs:redefine simpleType overrides.
65 lines
3.1 KiB
Swift
65 lines
3.1 KiB
Swift
extension PureXML.Schema.ComplexValidator {
|
|
/// The error when an element's declared type is an abstract complex type and
|
|
/// the element supplies no `xsi:type` to name a concrete derived type. An
|
|
/// abstract type cannot itself be the type of an instance element.
|
|
func abstractTypeError(
|
|
named name: String,
|
|
child: PureXML.Model.Element,
|
|
at path: [PureXML.Validation.PathKey],
|
|
) -> PureXML.Validation.ValidationError? {
|
|
guard abstractTypes.contains(PureXML.Schema.XSDParser.bareTypeLocalName(name)),
|
|
Self.xsiTypeName(child) == nil
|
|
else { return nil }
|
|
let bare = PureXML.Schema.XSDParser.bareTypeLocalName(name)
|
|
return PureXML.Validation.ValidationError(
|
|
reason: "element '\(child.name.localName)' has abstract type '\(bare)' and requires an xsi:type naming a concrete derived type",
|
|
at: path,
|
|
)
|
|
}
|
|
|
|
/// The error when an `xsi:type` substitution is forbidden by `block` on the
|
|
/// declared type: the substituted type reaches the declared type by a method
|
|
/// the declared type lists in `block`. Returns nil when there is no named
|
|
/// declared type, no `block`, or the substitution is permitted.
|
|
func blockedSubstitutionError(
|
|
declared: PureXML.Schema.ElementType,
|
|
child: PureXML.Model.Element,
|
|
at path: [PureXML.Validation.PathKey],
|
|
) -> PureXML.Validation.ValidationError? {
|
|
guard case let .typeReference(reference) = declared,
|
|
let substitute = Self.xsiTypeName(child),
|
|
Self.resolveNamedType(substitute, in: types) != nil
|
|
else {
|
|
return nil
|
|
}
|
|
// A ref'd child carries its type as an element-ref key (`element:foo`)
|
|
// that resolves through `types` to the concrete type; follow that chain
|
|
// to the declared type name the derivation backbone and `block` use.
|
|
var declaredKey = reference
|
|
var declaredName = PureXML.Schema.XSDParser.bareTypeLocalName(reference)
|
|
var steps = 0
|
|
while steps <= types.count {
|
|
guard let resolved = types[declaredKey] ?? Self.resolveNamedType(declaredKey, in: types),
|
|
case let .typeReference(next) = resolved
|
|
else { break }
|
|
declaredKey = next
|
|
declaredName = PureXML.Schema.XSDParser.bareTypeLocalName(next)
|
|
steps += 1
|
|
}
|
|
guard let methods = PureXML.Schema.XSDParser.derivationMethods(from: substitute, to: declaredName, typeDerivation) else {
|
|
return nil
|
|
}
|
|
// The substitution is blocked when the derivation method is disallowed by
|
|
// either the declared type's `block` or the element declaration's own
|
|
// `block` (keyed by the element's name).
|
|
let blocked = (typeBlock[declaredName] ?? []).union(elementBlock[child.name.localName] ?? [])
|
|
guard !methods.isDisjoint(with: blocked) else {
|
|
return nil
|
|
}
|
|
return PureXML.Validation.ValidationError(
|
|
reason: "xsi:type '\(substitute)' is blocked: substitution by this derivation is disallowed",
|
|
at: path,
|
|
)
|
|
}
|
|
}
|