Class: Moxml::XPath::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/moxml/xpath/parser.rb

Overview

XPath expression parser

Implements a recursive descent parser for XPath 1.0 expressions. Builds an Abstract Syntax Tree (AST) from tokenized input.

Grammar (simplified XPath 1.0):

expr        ::= or_expr
or_expr     ::= and_expr ('or' and_expr)*
and_expr    ::= equality ('and' equality)*
equality    ::= relational (('=' | '!=') relational)*
relational  ::= additive (('<' | '>' | '<=' | '>=') additive)*
additive    ::= multiplicative (('+' | '-') multiplicative)*
multiplicative ::= unary (('*' | 'div' | 'mod') unary)*
unary       ::= ('-')? union
union       ::= path_expr ('|' path_expr)*
path_expr   ::= filter_expr | location_path
filter_expr ::= primary_expr predicate*
primary     ::= variable | '(' expr ')' | literal | number | function
location_path ::= absolute_path | relative_path

Examples:

ast = Parser.parse("//book[@id='123']")
ast = Parser.parse_with_cache("//book[@id='123']")

Constant Summary collapse

CACHE =

Parse cache for compiled expressions

Cache.new(100)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(expression) ⇒ Parser

Initialize parser with expression

Parameters:

  • expression (String)

    XPath expression



52
53
54
55
56
57
# File 'lib/moxml/xpath/parser.rb', line 52

def initialize(expression)
  @expression = expression.to_s
  @lexer = Lexer.new(@expression)
  @tokens = @lexer.tokenize
  @position = 0
end

Class Method Details

.parse(expression) ⇒ AST::Node

Parse an XPath expression

Parameters:

  • expression (String)

    XPath expression to parse

Returns:

Raises:



37
38
39
# File 'lib/moxml/xpath/parser.rb', line 37

def self.parse(expression)
  new(expression).parse
end

.parse_with_cache(expression) ⇒ AST::Node

Parse with caching

Parameters:

  • expression (String)

    XPath expression to parse

Returns:

  • (AST::Node)

    Root node of AST (possibly cached)



45
46
47
# File 'lib/moxml/xpath/parser.rb', line 45

def self.parse_with_cache(expression)
  CACHE.get_or_set(expression) { parse(expression) }
end

Instance Method Details

#parseAST::Node

Parse the expression into an AST

Returns:

Raises:



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/moxml/xpath/parser.rb', line 63

def parse
  return AST::Node.new(:empty) if @tokens.empty?

  result = parse_expr

  unless at_end?
    raise_syntax_error("Unexpected token after expression: #{current_token}")
  end

  result
end