Compile and evaluate full XPath 1.0 expressions, not just location paths. Add the four-type Value (node-set, boolean, number, string) with the spec's coercion rules and canonical number formatting, a recursive-descent parser for the operator grammar (or/and, equality, relational, additive, multiplicative, unary minus, union) whose grammatical position disambiguates * and the operator keywords, function calls, variable references, and filter expressions. Predicates are now arbitrary expressions (a numeric predicate is a position test). Comparison follows the node-set quantification rules. Query gains value/number/string/boolean accessors and a $variable binding map; the core functions last, position, count, not, true, false, boolean, number, and string ship with it. Closes #42
33 lines
1.5 KiB
Swift
33 lines
1.5 KiB
Swift
public extension PureXML.XPath {
|
|
/// An error compiling or evaluating an XPath query.
|
|
enum QueryError: Swift.Error, Equatable, Sendable, CustomStringConvertible {
|
|
case empty
|
|
case unexpectedToken(String)
|
|
case expectedNodeTest
|
|
case unterminatedPredicate
|
|
case unsupportedPredicate(String)
|
|
/// An axis name was not one of the thirteen XPath axes.
|
|
case unsupportedAxis(String)
|
|
/// A function was called that is not in the library.
|
|
case unknownFunction(String)
|
|
/// A `$name` reference had no binding in the evaluation context.
|
|
case undefinedVariable(String)
|
|
/// A function received the wrong number or type of arguments.
|
|
case invalidArguments(String)
|
|
|
|
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 let .unknownFunction(name): "unknown function '\(name)()'"
|
|
case let .undefinedVariable(name): "variable '$\(name)' is not bound"
|
|
case let .invalidArguments(detail): "invalid arguments: \(detail)"
|
|
}
|
|
}
|
|
}
|
|
}
|