PureXML/Sources/Schema/RelaxNGPattern.swift
Mihaela Mihaljevic b19e48a6eb feat(schema): RELAX NG pattern model, parser, and derivative validation
Add the RELAX NG pattern algebra (Pattern, NameClass), a parser for the XML
syntax into a grammar of start plus named defines, and James Clark's
derivative validation algorithm. The pattern is derived through each
start-tag, attribute, text, and end-tag event with simplifying constructors;
the document is valid when the residual pattern is nullable. Supports
element, attribute, text, empty, notAllowed, group, choice, interleave,
optional, zeroOrMore, oneOrMore, mixed, list, ref/define, data, value, and
the name classes; handles interleave and recursive grammars, reusing the XSD
datatype library for data and value.

Closes #11
Closes #12
2026-06-08 06:49:37 +02:00

43 lines
1.6 KiB
Swift

public extension PureXML.Schema {
/// A RELAX NG name class: which element or attribute names a pattern matches.
indirect enum NameClass: Sendable {
case anyName
case anyNameExcept(NameClass)
case name(namespace: String, localName: String)
case nsName(String)
case choice(NameClass, NameClass)
/// Whether `name` is in this class.
func contains(_ name: PureXML.Model.QualifiedName) -> Bool {
let namespace = name.namespaceURI ?? ""
switch self {
case .anyName: return true
case let .anyNameExcept(except): return !except.contains(name)
case let .name(wantedNamespace, wantedLocal): return namespace == wantedNamespace && name.localName == wantedLocal
case let .nsName(wantedNamespace): return namespace == wantedNamespace
case let .choice(left, right): return left.contains(name) || right.contains(name)
}
}
}
/// A RELAX NG pattern (the simplified algebra used by the derivative
/// algorithm). `optional`, `zeroOrMore`, and `mixed` are expressed through
/// these constructors; `after` is internal to derivation.
indirect enum Pattern: Sendable {
case empty
case notAllowed
case text
case choice(Pattern, Pattern)
case interleave(Pattern, Pattern)
case group(Pattern, Pattern)
case oneOrMore(Pattern)
case element(NameClass, Pattern)
case attribute(NameClass, Pattern)
case data(BuiltinType)
case value(String)
case list(Pattern)
case ref(String)
case after(Pattern, Pattern)
}
}