PureXML/Sources/Schema/RelaxNGPattern.swift
Mihaela Mihaljevic c628682086 feat(relaxng): QName values with dual-context resolution, instance level clean
A value of type QName compiles to its (namespace, local) pair via the
schema's xmlns/ns scope; the derivative engine threads the instance
element's in-scope bindings to value comparison in both the tree walk
and the streaming state (frames carry their bindings), so instance
prefixes and the default namespace resolve against the instance
document and unbound prefixes match nothing. Streaming also gains the
tree walk's empty-element rule. The spec suite's instance level is
fully clean: valid 289/289, invalid 291/291; only the asserted
schema-correctness class remains.
2026-06-10 10:57:14 +02:00

52 lines
2.3 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)
/// A `<value type="QName">`, compiled to its (namespace, local) value
/// pair via the schema's xmlns scope; the instance side resolves its
/// text against the instance element's in-scope namespaces.
case valueQName(namespace: String, localName: String)
case list(Pattern)
case ref(String)
case after(Pattern, Pattern)
}
}