Add PureXML.XPath: a compiled location-path query engine reimplemented from the XPath 1.0 specification; no upstream code copied. - Compiler parses a path into steps; Evaluator walks the tree returning a Selection node-set (node or attribute) in document order. - Forward axes only (child, descendant //, self ., attribute @), since the value model has no parent pointers. Node tests: name, *, text(), node(), comment(). Predicates: [n], [@a], [@a='v'], [child], [child='v']. - Public surface: XPath.Query (init compiles, evaluate/elements/strings), the Selection enum (element / stringValue), QueryError, and the one-shot PureXML.xpath(_:over:). Upward/sibling axes and the full expression language are explicitly out of scope. - 12 XPath tests; 61 total.
27 lines
1.1 KiB
Swift
27 lines
1.1 KiB
Swift
public extension PureXML.XPath {
|
|
/// An error compiling or evaluating an XPath query in the supported subset.
|
|
enum QueryError: Swift.Error, Equatable, Sendable, CustomStringConvertible {
|
|
case empty
|
|
case unexpectedToken(String)
|
|
case expectedNodeTest
|
|
case unterminatedPredicate
|
|
case unsupportedPredicate(String)
|
|
/// An upward or sibling axis was used; only forward axes are supported.
|
|
case unsupportedAxis(String)
|
|
/// An attribute step appeared before the end of the path.
|
|
case attributeStepNotLast
|
|
|
|
public var description: String {
|
|
switch self {
|
|
case .empty: "the XPath expression is empty"
|
|
case let .unexpectedToken(token): "unexpected token '\(token)'"
|
|
case .expectedNodeTest: "expected a node test"
|
|
case .unterminatedPredicate: "unterminated predicate"
|
|
case let .unsupportedPredicate(detail): "unsupported predicate: \(detail)"
|
|
case let .unsupportedAxis(axis): "unsupported axis: \(axis)"
|
|
case .attributeStepNotLast: "an attribute step must be the last step"
|
|
}
|
|
}
|
|
}
|
|
}
|