Trimmed the XPath AST even further.

The excessive use of (path) nodes has been dropped and all parsing conflicts
have been dealt with.
This commit is contained in:
Yorick Peterse 2014-07-12 00:13:25 +02:00
parent aeb4eba260
commit be4f4ad744
8 changed files with 201 additions and 254 deletions

View File

@ -29,24 +29,10 @@ preclow
rule rule
xpath xpath
: paths { val[0] } : expression { val[0] }
| /* none */ { nil } | /* none */ { nil }
; ;
paths
: T_SLASH path { s(:absolute, val[1]) }
| path { val[0] }
;
path
: expressions { s(:path, *val[0]) }
;
expressions
: expression { val }
| expression T_SLASH expressions { [val[0], *val[2]] }
;
expression expression
: node_test : node_test
| operator | operator
@ -54,6 +40,30 @@ rule
| string | string
| number | number
| call | call
| path
| absolute_path
;
path_member
: node_test
| axis
| call
;
path_members
: path_member T_SLASH path_member { [val[0], val[2]] }
| path_member T_SLASH path_members { [val[0], *val[2]] }
;
# A and A/B
path
: path_members { s(:path, *val[0]) }
;
# /A and /A/B
absolute_path
: T_SLASH path_members { s(:absolute_path, *val[1]) }
| T_SLASH path_member { s(:absolute_path, val[1]) }
; ;
node_test node_test
@ -70,24 +80,24 @@ rule
; ;
predicate predicate
: T_LBRACK paths T_RBRACK { val[1] } : T_LBRACK expression T_RBRACK { val[1] }
; ;
operator operator
: paths T_PIPE paths { s(:pipe, val[0], val[2]) } : expression T_PIPE expression { s(:pipe, val[0], val[2]) }
| paths T_AND paths { s(:and, val[0], val[2]) } | expression T_AND expression { s(:and, val[0], val[2]) }
| paths T_OR paths { s(:or, val[0], val[2]) } | expression T_OR expression { s(:or, val[0], val[2]) }
| paths T_ADD paths { s(:add, val[0], val[2]) } | expression T_ADD expression { s(:add, val[0], val[2]) }
| paths T_DIV paths { s(:div, val[0], val[2]) } | expression T_DIV expression { s(:div, val[0], val[2]) }
| paths T_MOD paths { s(:mod, val[0], val[2]) } | expression T_MOD expression { s(:mod, val[0], val[2]) }
| paths T_EQ paths { s(:eq, val[0], val[2]) } | expression T_EQ expression { s(:eq, val[0], val[2]) }
| paths T_NEQ paths { s(:neq, val[0], val[2]) } | expression T_NEQ expression { s(:neq, val[0], val[2]) }
| paths T_LT paths { s(:lt, val[0], val[2]) } | expression T_LT expression { s(:lt, val[0], val[2]) }
| paths T_GT paths { s(:gt, val[0], val[2]) } | expression T_GT expression { s(:gt, val[0], val[2]) }
| paths T_LTE paths { s(:lte, val[0], val[2]) } | expression T_LTE expression { s(:lte, val[0], val[2]) }
| paths T_GTE paths { s(:gte, val[0], val[2]) } | expression T_GTE expression { s(:gte, val[0], val[2]) }
| paths T_MUL paths { s(:mul, val[0], val[2]) } | expression T_MUL expression { s(:mul, val[0], val[2]) }
| paths T_SUB paths { s(:sub, val[0], val[2]) } | expression T_SUB expression { s(:sub, val[0], val[2]) }
; ;
axis axis
@ -106,8 +116,8 @@ rule
; ;
call_args call_args
: paths { val } : expression { val }
| paths T_COMMA call_args { val[2].unshift(val[0]) } | expression T_COMMA call_args { val[2].unshift(val[0]) }
; ;
string string

View File

@ -4,92 +4,92 @@ describe Oga::XPath::Parser do
context 'full axes' do context 'full axes' do
example 'parse the ancestor axis' do example 'parse the ancestor axis' do
parse_xpath('/ancestor::A').should == s( parse_xpath('/ancestor::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'ancestor', s(:test, nil, 'A'))) s(:axis, 'ancestor', s(:test, nil, 'A'))
) )
end end
example 'parse the ancestor-or-self axis' do example 'parse the ancestor-or-self axis' do
parse_xpath('/ancestor-or-self::A').should == s( parse_xpath('/ancestor-or-self::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'ancestor-or-self', s(:test, nil, 'A'))) s(:axis, 'ancestor-or-self', s(:test, nil, 'A'))
) )
end end
example 'parse the attribute axis' do example 'parse the attribute axis' do
parse_xpath('/attribute::A').should == s( parse_xpath('/attribute::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'attribute', s(:test, nil, 'A'))) s(:axis, 'attribute', s(:test, nil, 'A'))
) )
end end
example 'parse the child axis' do example 'parse the child axis' do
parse_xpath('/child::A').should == s( parse_xpath('/child::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'child', s(:test, nil, 'A'))) s(:axis, 'child', s(:test, nil, 'A'))
) )
end end
example 'parse the descendant axis' do example 'parse the descendant axis' do
parse_xpath('/descendant::A').should == s( parse_xpath('/descendant::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'descendant', s(:test, nil, 'A'))) s(:axis, 'descendant', s(:test, nil, 'A'))
) )
end end
example 'parse the descendant-or-self axis' do example 'parse the descendant-or-self axis' do
parse_xpath('/descendant-or-self::A').should == s( parse_xpath('/descendant-or-self::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'descendant-or-self', s(:test, nil, 'A'))) s(:axis, 'descendant-or-self', s(:test, nil, 'A'))
) )
end end
example 'parse the following axis' do example 'parse the following axis' do
parse_xpath('/following::A').should == s( parse_xpath('/following::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'following', s(:test, nil, 'A'))) s(:axis, 'following', s(:test, nil, 'A'))
) )
end end
example 'parse the following-sibling axis' do example 'parse the following-sibling axis' do
parse_xpath('/following-sibling::A').should == s( parse_xpath('/following-sibling::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'following-sibling', s(:test, nil, 'A'))) s(:axis, 'following-sibling', s(:test, nil, 'A'))
) )
end end
example 'parse the namespace axis' do example 'parse the namespace axis' do
parse_xpath('/namespace::A').should == s( parse_xpath('/namespace::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'namespace', s(:test, nil, 'A'))) s(:axis, 'namespace', s(:test, nil, 'A'))
) )
end end
example 'parse the parent axis' do example 'parse the parent axis' do
parse_xpath('/parent::A').should == s( parse_xpath('/parent::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'parent', s(:test, nil, 'A'))) s(:axis, 'parent', s(:test, nil, 'A'))
) )
end end
example 'parse the preceding axis' do example 'parse the preceding axis' do
parse_xpath('/preceding::A').should == s( parse_xpath('/preceding::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'preceding', s(:test, nil, 'A'))) s(:axis, 'preceding', s(:test, nil, 'A'))
) )
end end
example 'parse the preceding-sibling axis' do example 'parse the preceding-sibling axis' do
parse_xpath('/preceding-sibling::A').should == s( parse_xpath('/preceding-sibling::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'preceding-sibling', s(:test, nil, 'A'))) s(:axis, 'preceding-sibling', s(:test, nil, 'A'))
) )
end end
example 'parse the self axis' do example 'parse the self axis' do
parse_xpath('/self::A').should == s( parse_xpath('/self::A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'self', s(:test, nil, 'A'))) s(:axis, 'self', s(:test, nil, 'A'))
) )
end end
end end
@ -97,30 +97,24 @@ describe Oga::XPath::Parser do
context 'short axes' do context 'short axes' do
example 'parse the @attribute axis' do example 'parse the @attribute axis' do
parse_xpath('/@A').should == s( parse_xpath('/@A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'attribute', s(:test, nil, 'A'))) s(:axis, 'attribute', s(:test, nil, 'A'))
) )
end end
example 'parse the // axis' do example 'parse the // axis' do
parse_xpath('//A').should == s( parse_xpath('//A').should == s(
:absolute, :absolute_path,
s(:path, s(:axis, 'descendant-or-self', s(:test, nil, 'A'))) s(:axis, 'descendant-or-self', s(:test, nil, 'A'))
) )
end end
example 'parse the .. axis' do example 'parse the .. axis' do
parse_xpath('/..').should == s( parse_xpath('/..').should == s(:absolute_path, s(:axis, 'parent'))
:absolute,
s(:path, s(:axis, 'parent'))
)
end end
example 'parse the . axis' do example 'parse the . axis' do
parse_xpath('/.').should == s( parse_xpath('/.').should == s(:absolute_path, s(:axis, 'self'))
:absolute,
s(:path, s(:axis, 'self'))
)
end end
end end
end end

View File

@ -3,25 +3,23 @@ require 'spec_helper'
describe Oga::XPath::Parser do describe Oga::XPath::Parser do
context 'function calls' do context 'function calls' do
example 'parse a function call without arguments' do example 'parse a function call without arguments' do
parse_xpath('count()').should == s(:path, s(:call, 'count')) parse_xpath('count()').should == s(:call, 'count')
end end
example 'parse a function call with a single argument' do example 'parse a function call with a single argument' do
parse_xpath('count(/foo)').should == s( parse_xpath('count(/foo)').should == s(
:path, :call,
s(:call, 'count', s(:absolute, s(:path, s(:test, nil, 'foo')))) 'count',
s(:absolute_path, s(:test, nil, 'foo'))
) )
end end
example 'parse a function call with two arguments' do example 'parse a function call with two arguments' do
parse_xpath('count(/foo, "bar")').should == s( parse_xpath('count(/foo, "bar")').should == s(
:path,
s(
:call, :call,
'count', 'count',
s(:absolute, s(:path, s(:test, nil, 'foo'))), s(:absolute_path, s(:test, nil, 'foo')),
s(:path, s(:string, 'bar')) s(:string, 'bar')
)
) )
end end
@ -29,14 +27,14 @@ describe Oga::XPath::Parser do
parse_xpath('foo/bar()').should == s( parse_xpath('foo/bar()').should == s(
:path, :path,
s(:test, nil, 'foo'), s(:test, nil, 'foo'),
s(:path, s(:call, 'bar')) s(:call, 'bar')
) )
end end
example 'parse an absolute path with a function call' do example 'parse an absolute path with a function call' do
parse_xpath('/foo/bar()').should == s( parse_xpath('/foo/bar()').should == s(
:absolute, :absolute_path,
s(:path, s(:test, nil, 'foo'), s(:path, s(:call, 'bar'))) s(:test, nil, 'foo'), s(:call, 'bar')
) )
end end
@ -47,37 +45,22 @@ describe Oga::XPath::Parser do
:test, :test,
nil, nil,
'div', 'div',
s(
:path,
s( s(
:eq, :eq,
s(:axis, 'attribute', s(:test, nil, 'class')), s(:axis, 'attribute', s(:test, nil, 'class')),
s(:string, 'foo') s(:string, 'foo')
) )
)
), ),
s(:path, s(:call, 'bar')) s(:call, 'bar')
) )
end end
example 'parse two predicates followed by a function call' do example 'parse two predicates followed by a function call' do
parse_xpath('A[@class]/B[@class]/bar()').should == s( parse_xpath('A[@x]/B[@x]/bar()').should == s(
:path, :path,
s( s(:test, nil, 'A', s(:axis, 'attribute', s(:test, nil, 'x'))),
:test, s(:test, nil, 'B', s(:axis, 'attribute', s(:test, nil, 'x'))),
nil, s(:call, 'bar')
'A',
s(:path, s(:axis, 'attribute', s(:test, nil, 'class')))),
s(
:path,
s(
:test,
nil,
'B',
s(:path, s(:axis, 'attribute', s(:test, nil, 'class')))
),
s(:path, s(:call, 'bar'))
)
) )
end end
end end

View File

@ -4,145 +4,106 @@ describe Oga::XPath::Parser do
context 'operator precedence' do context 'operator precedence' do
example 'parse "A or B or C"' do example 'parse "A or B or C"' do
parse_xpath('A or B or C').should == s( parse_xpath('A or B or C').should == s(
:path,
s(
:or, :or,
s(:or, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:or, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A and B and C"' do example 'parse "A and B and C"' do
parse_xpath('A and B and C').should == s( parse_xpath('A and B and C').should == s(
:path,
s(
:and, :and,
s(:and, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:and, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A = B = C"' do example 'parse "A = B = C"' do
parse_xpath('A = B = C').should == s( parse_xpath('A = B = C').should == s(
:path,
s(
:eq, :eq,
s(:eq, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:eq, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A != B != C"' do example 'parse "A != B != C"' do
parse_xpath('A != B != C').should == s( parse_xpath('A != B != C').should == s(
:path,
s(
:neq, :neq,
s(:neq, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:neq, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A <= B <= C"' do example 'parse "A <= B <= C"' do
parse_xpath('A <= B <= C').should == s( parse_xpath('A <= B <= C').should == s(
:path,
s(
:lte, :lte,
s(:lte, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:lte, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A < B < C"' do example 'parse "A < B < C"' do
parse_xpath('A < B < C').should == s( parse_xpath('A < B < C').should == s(
:path,
s(
:lt, :lt,
s(:lt, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:lt, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A >= B >= C"' do example 'parse "A >= B >= C"' do
parse_xpath('A >= B >= C').should == s( parse_xpath('A >= B >= C').should == s(
:path,
s(
:gte, :gte,
s(:gte, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:gte, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A > B > C"' do example 'parse "A > B > C"' do
parse_xpath('A > B > C').should == s( parse_xpath('A > B > C').should == s(
:path,
s(
:gt, :gt,
s(:gt, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:gt, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
example 'parse "A or B and C"' do example 'parse "A or B and C"' do
parse_xpath('A or B and C').should == s( parse_xpath('A or B and C').should == s(
:path,
s(
:or, :or,
s(:test, nil, 'A'), s(:test, nil, 'A'),
s(:and, s(:test, nil, 'B'), s(:test, nil, 'C')) s(:and, s(:test, nil, 'B'), s(:test, nil, 'C'))
) )
)
end end
example 'parse "A and B = C"' do example 'parse "A and B = C"' do
parse_xpath('A and B = C').should == s( parse_xpath('A and B = C').should == s(
:path,
s(
:and, :and,
s(:test, nil, 'A'), s(:test, nil, 'A'),
s(:eq, s(:test, nil, 'B'), s(:test, nil, 'C')) s(:eq, s(:test, nil, 'B'), s(:test, nil, 'C'))
) )
)
end end
example 'parse "A = B < C"' do example 'parse "A = B < C"' do
parse_xpath('A = B < C').should == s( parse_xpath('A = B < C').should == s(
:path,
s(
:eq, :eq,
s(:test, nil, 'A'), s(:test, nil, 'A'),
s(:lt, s(:test, nil, 'B'), s(:test, nil, 'C')) s(:lt, s(:test, nil, 'B'), s(:test, nil, 'C'))
) )
)
end end
example 'parse "A < B | C"' do example 'parse "A < B | C"' do
parse_xpath('A < B | C').should == s( parse_xpath('A < B | C').should == s(
:path,
s(
:lt, :lt,
s(:test, nil, 'A'), s(:test, nil, 'A'),
s(:pipe, s(:test, nil, 'B'), s(:test, nil, 'C')) s(:pipe, s(:test, nil, 'B'), s(:test, nil, 'C'))
) )
)
end end
example 'parse "A > B or C"' do example 'parse "A > B or C"' do
parse_xpath('A > B or C').should == s( parse_xpath('A > B or C').should == s(
:path,
s(
:or, :or,
s(:gt, s(:test, nil, 'A'), s(:test, nil, 'B')), s(:gt, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:test, nil, 'C') s(:test, nil, 'C')
) )
)
end end
end end
end end

View File

@ -4,99 +4,121 @@ describe Oga::XPath::Parser do
context 'operators' do context 'operators' do
example 'parse the pipe operator' do example 'parse the pipe operator' do
parse_xpath('A | B').should == s( parse_xpath('A | B').should == s(
:path, :pipe,
s(:pipe, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
)
end
example 'parse the pipe operator using two paths' do
parse_xpath('A/B | C/D').should == s(
:pipe,
s(:path, s(:test, nil, 'A'), s(:test, nil, 'B')),
s(:path, s(:test, nil, 'C'), s(:test, nil, 'D'))
) )
end end
example 'parse the and operator' do example 'parse the and operator' do
parse_xpath('A and B').should == s( parse_xpath('A and B').should == s(
:path, :and,
s(:and, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the or operator' do example 'parse the or operator' do
parse_xpath('A or B').should == s( parse_xpath('A or B').should == s(
:path, :or,
s(:or, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the plus operator' do example 'parse the plus operator' do
parse_xpath('A + B').should == s( parse_xpath('A + B').should == s(
:path, :add,
s(:add, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the div operator' do example 'parse the div operator' do
parse_xpath('A div B').should == s( parse_xpath('A div B').should == s(
:path, :div,
s(:div, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the mod operator' do example 'parse the mod operator' do
parse_xpath('A mod B').should == s( parse_xpath('A mod B').should == s(
:path, :mod,
s(:mod, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the equals operator' do example 'parse the equals operator' do
parse_xpath('A = B').should == s( parse_xpath('A = B').should == s(
:path, :eq,
s(:eq, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the not-equals operator' do example 'parse the not-equals operator' do
parse_xpath('A != B').should == s( parse_xpath('A != B').should == s(
:path, :neq,
s(:neq, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the lower-than operator' do example 'parse the lower-than operator' do
parse_xpath('A < B').should == s( parse_xpath('A < B').should == s(
:path, :lt,
s(:lt, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the greater-than operator' do example 'parse the greater-than operator' do
parse_xpath('A > B').should == s( parse_xpath('A > B').should == s(
:path, :gt,
s(:gt, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the lower-or-equal operator' do example 'parse the lower-or-equal operator' do
parse_xpath('A <= B').should == s( parse_xpath('A <= B').should == s(
:path, :lte,
s(:lte, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the greater-or-equal operator' do example 'parse the greater-or-equal operator' do
parse_xpath('A >= B').should == s( parse_xpath('A >= B').should == s(
:path, :gte,
s(:gte, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the mul operator' do example 'parse the mul operator' do
parse_xpath('A * B').should == s( parse_xpath('A * B').should == s(
:path, :mul,
s(:mul, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
example 'parse the subtraction operator' do example 'parse the subtraction operator' do
parse_xpath('A - B').should == s( parse_xpath('A - B').should == s(
:path, :sub,
s(:sub, s(:test, nil, 'A'), s(:test, nil, 'B')) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
end end

View File

@ -3,17 +3,18 @@ require 'spec_helper'
describe Oga::XPath::Parser do describe Oga::XPath::Parser do
context 'paths' do context 'paths' do
example 'parse an absolute path' do example 'parse an absolute path' do
parse_xpath('/A').should == s(:absolute, s(:path, s(:test, nil, 'A'))) parse_xpath('/A').should == s(:absolute_path, s(:test, nil, 'A'))
end end
example 'parse a relative path' do example 'parse a relative path' do
parse_xpath('A').should == s(:path, s(:test, nil, 'A')) parse_xpath('A').should == s(:test, nil, 'A')
end end
example 'parse an expression using two paths' do example 'parse an expression using two paths' do
parse_xpath('/A/B').should == s( parse_xpath('/A/B').should == s(
:absolute, :absolute_path,
s(:path, s(:test, nil, 'A'), s(:path, s(:test, nil, 'B'))) s(:test, nil, 'A'),
s(:test, nil, 'B')
) )
end end
end end

View File

@ -4,46 +4,22 @@ describe Oga::XPath::Parser do
context 'predicates' do context 'predicates' do
example 'parse a single predicate' do example 'parse a single predicate' do
parse_xpath('foo[@class="bar"]').should == s( parse_xpath('foo[@class="bar"]').should == s(
:path,
s(
:test, :test,
nil, nil,
'foo', 'foo',
s( s(:eq, s(:axis, 'attribute', s(:test, nil, 'class')), s(:string, 'bar'))
:path,
s(
:eq,
s(:axis, 'attribute', s(:test, nil, 'class')),
s(:string, 'bar')
)
)
)
) )
end end
example 'parse a predicate using the or operator' do example 'parse a predicate using the or operator' do
parse_xpath('foo[@class="bar" or @class="baz"]').should == s( parse_xpath('foo[@x="bar" or @x="baz"]').should == s(
:path,
s(
:test, :test,
nil, nil,
'foo', 'foo',
s(
:path,
s( s(
:or, :or,
s( s(:eq, s(:axis, 'attribute', s(:test, nil, 'x')), s(:string, 'bar')),
:eq, s(:eq, s(:axis, 'attribute', s(:test, nil, 'x')), s(:string, 'baz')),
s(:axis, 'attribute', s(:test, nil, 'class')),
s(:string, 'bar')
),
s(
:eq,
s(:axis, 'attribute', s(:test, nil, 'class')),
s(:string, 'baz')
)
)
)
) )
) )
end end

View File

@ -3,15 +3,15 @@ require 'spec_helper'
describe Oga::XPath::Parser do describe Oga::XPath::Parser do
context 'wildcards' do context 'wildcards' do
example 'parse a wildcard name test' do example 'parse a wildcard name test' do
parse_xpath('*').should == s(:path, s(:test, nil, '*')) parse_xpath('*').should == s(:test, nil, '*')
end end
example 'parse a wildcard namespace test' do example 'parse a wildcard namespace test' do
parse_xpath('*:A').should == s(:path, s(:test, '*', 'A')) parse_xpath('*:A').should == s(:test, '*', 'A')
end end
example 'parse a wildcard namespace and name test' do example 'parse a wildcard namespace and name test' do
parse_xpath('*:*').should == s(:path, s(:test, '*', '*')) parse_xpath('*:*').should == s(:test, '*', '*')
end end
end end
end end