Read and enforce the XSD 1.0 derivation controls that were previously ignored: - abstract elements may not appear in an instance directly, only through a substitution member; an element of an abstract complex type must supply an xsi:type naming a concrete derived type. - block on a type forbids the disallowed xsi:type substitutions; block on an element drops substitution-group members that derive by a blocked method. - final on a type rejects, at compile time, any type that derives from it by a final method. - xs:redefine requires the redefined type to derive from itself. Track each named complex type's base and derivation method as the backbone these checks walk. Also compose complexContent extension and restriction content models, which were previously dropped: an extension now inherits its base's attributes and content (base first, then the extension, in sequence). Complex-type restriction is not verified to be a structurally valid subset of its base (Particle Valid (Restriction)); that limit is documented at its sites. Closes #76
40 lines
1.9 KiB
Swift
40 lines
1.9 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(name), Self.xsiTypeName(child) == nil else { return nil }
|
|
return PureXML.Validation.ValidationError(
|
|
reason: "element '\(child.name.localName)' has abstract type '\(name)' 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(declaredName) = declared,
|
|
let substitute = Self.xsiTypeName(child), types[substitute] != nil,
|
|
let blocked = typeBlock[declaredName],
|
|
let methods = PureXML.Schema.XSDParser.derivationMethods(from: substitute, to: declaredName, typeDerivation),
|
|
!methods.isDisjoint(with: blocked)
|
|
else {
|
|
return nil
|
|
}
|
|
return PureXML.Validation.ValidationError(
|
|
reason: "xsi:type '\(substitute)' is blocked: type '\(declaredName)' disallows substitution by this derivation",
|
|
at: path,
|
|
)
|
|
}
|
|
}
|