Closes #75, on the validation framework. XSD instance-level features: - nillable elements: an xsi:nil="true" element is accepted (its content model is not checked) only when the element is declared nillable and carries no content; xsi:nil on a non-nillable element, or a nilled element with content, is a located error. - fixed value constraints: a present fixed attribute must equal its fixed value, and a fixed element's text must match. - default/fixed are parsed onto AttributeUse (per use) and collected per element name (nillable set + value constraints), threaded through XSDContext to the ComplexValidator. All findings are located ValidationErrors. Collection and helper methods move to same-file extensions to stay within type-body limits.
123 lines
4.0 KiB
Swift
123 lines
4.0 KiB
Swift
public extension PureXML.Schema {
|
|
/// A model-group compositor.
|
|
enum Compositor: Sendable {
|
|
/// An ordered list (`xs:sequence`).
|
|
case sequence
|
|
/// One of the alternatives (`xs:choice`).
|
|
case choice
|
|
/// Each member once, in any order (`xs:all`).
|
|
case all
|
|
}
|
|
|
|
/// An element wildcard (`xs:any`). The minimal namespace constraint: any
|
|
/// element matches.
|
|
struct Wildcard: Sendable {
|
|
public init() {}
|
|
}
|
|
|
|
/// The term of a particle: an element declaration, a nested model group, or a
|
|
/// wildcard.
|
|
indirect enum Term: Sendable {
|
|
case element(name: PureXML.Model.QualifiedName, type: ElementType?)
|
|
case group(Group)
|
|
case wildcard(Wildcard)
|
|
}
|
|
|
|
/// A particle: a term with an occurrence range. `maxOccurs` nil means
|
|
/// unbounded.
|
|
struct Particle: Sendable {
|
|
public var minOccurs: Int
|
|
public var maxOccurs: Int?
|
|
public var term: Term
|
|
|
|
public init(minOccurs: Int = 1, maxOccurs: Int? = 1, term: Term) {
|
|
self.minOccurs = minOccurs
|
|
self.maxOccurs = maxOccurs
|
|
self.term = term
|
|
}
|
|
}
|
|
|
|
/// A model group: a compositor over particles.
|
|
struct Group: Sendable {
|
|
public var compositor: Compositor
|
|
public var particles: [Particle]
|
|
|
|
public init(compositor: Compositor, particles: [Particle]) {
|
|
self.compositor = compositor
|
|
self.particles = particles
|
|
}
|
|
}
|
|
|
|
/// The declared type of an element: a simple type (text only), a complex one,
|
|
/// or a named reference resolved against the schema's type table (which lets
|
|
/// recursive schemas be represented without an infinite value).
|
|
indirect enum ElementType: Sendable {
|
|
case simple(SimpleType)
|
|
case complex(ComplexType)
|
|
case typeReference(String)
|
|
}
|
|
|
|
/// A value constraint on an attribute or element: a default value supplied
|
|
/// when the item is absent, or a fixed value the item must equal.
|
|
enum ValueConstraint: Sendable, Equatable {
|
|
case `default`(String)
|
|
case fixed(String)
|
|
|
|
/// The fixed value, when this is a `fixed` constraint.
|
|
public var fixedValue: String? {
|
|
if case let .fixed(value) = self { return value }
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// An attribute use on a complex type.
|
|
struct AttributeUse: Sendable {
|
|
public var name: PureXML.Model.QualifiedName
|
|
public var type: SimpleType
|
|
public var required: Bool
|
|
public var valueConstraint: ValueConstraint?
|
|
|
|
public init(
|
|
name: PureXML.Model.QualifiedName,
|
|
type: SimpleType,
|
|
required: Bool = false,
|
|
valueConstraint: ValueConstraint? = nil,
|
|
) {
|
|
self.name = name
|
|
self.type = type
|
|
self.required = required
|
|
self.valueConstraint = valueConstraint
|
|
}
|
|
}
|
|
|
|
/// The content of a complex type.
|
|
indirect enum ContentType: Sendable {
|
|
/// No child elements or non-whitespace text.
|
|
case empty
|
|
/// Character data validated against a simple type, no child elements.
|
|
case simpleContent(SimpleType)
|
|
/// Child elements matching the particle; no non-whitespace text.
|
|
case elementOnly(Particle)
|
|
/// Child elements matching the particle, with text allowed between them.
|
|
case mixed(Particle)
|
|
}
|
|
|
|
/// A complex type: its attribute uses, whether unknown attributes are allowed,
|
|
/// and its content model.
|
|
struct ComplexType: Sendable {
|
|
public var attributes: [AttributeUse]
|
|
public var allowsOtherAttributes: Bool
|
|
public var content: ContentType
|
|
|
|
public init(
|
|
attributes: [AttributeUse] = [],
|
|
allowsOtherAttributes: Bool = false,
|
|
content: ContentType = .empty,
|
|
) {
|
|
self.attributes = attributes
|
|
self.allowsOtherAttributes = allowsOtherAttributes
|
|
self.content = content
|
|
}
|
|
}
|
|
}
|