PureXML/Sources/Schema/RelaxNGPattern.swift
Mihaela Mihaljevic b8fa90ccf5 feat(relaxng): ns inheritance, QNames, include-start, combine, data-except
The compiler implements simplification 4.9-4.10 (ns inheritance across
ancestors and document boundaries; QName resolution against in-scope
xmlns declarations; the attribute name= shorthand stays namespace-less),
include brings in the included grammar's start with overrides (4.7),
multiple starts and defines combine with a single omitted combine
merging by the named method (4.17), data/except lands as a dataExcept
pattern in the derivative engine (4.12), an empty element matches data
whose lexical space admits the empty string, and whitespace-only
attribute values match empty-matching patterns. Spec suite: valid
274/289, invalid 279/291.
2026-06-10 10:24:46 +02:00

48 lines
2.0 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 nsNameExcept(namespace: String, except: NameClass)
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 .nsNameExcept(wantedNamespace, except): return namespace == wantedNamespace && !except.contains(name)
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(SimpleType)
/// `<data>` with an `<except>` child: the type matches but the except
/// pattern must not (4.12).
case dataExcept(SimpleType, Pattern)
case value(SimpleType, String)
case list(Pattern)
case ref(String)
case after(Pattern, Pattern)
}
}