wgibbs-xpath 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -0
- data/lib/xpath.rb +68 -0
- data/lib/xpath/expression.rb +310 -0
- data/lib/xpath/html.rb +114 -0
- data/lib/xpath/union.rb +27 -0
- data/lib/xpath/version.rb +3 -0
- data/spec/fixtures/form.html +87 -0
- data/spec/fixtures/simple.html +32 -0
- data/spec/fixtures/stuff.html +43 -0
- data/spec/html_spec.rb +187 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/union_spec.rb +63 -0
- data/spec/xpath_spec.rb +353 -0
- metadata +129 -0
data/lib/xpath/union.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module XPath
|
2
|
+
class Union
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :expressions
|
6
|
+
|
7
|
+
def initialize(*expressions)
|
8
|
+
@expressions = expressions
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
expressions.each(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xpath(predicate=nil)
|
16
|
+
expressions.map { |e| e.to_xpath(predicate) }.join(' | ')
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_xpaths
|
20
|
+
[to_xpath(:exact), to_xpath(:fuzzy)].uniq
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(*args)
|
24
|
+
XPath::Union.new(*expressions.map { |e| e.send(*args) })
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
<h1>Form</h1>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<a id="awesome-link" data="link-text" href="#link">An awesome link</a>
|
5
|
+
<a id="some-id" data="link-id" href="#id">With id</a>
|
6
|
+
<a title="My title" data="link-title" href="#title">A cool title</a>
|
7
|
+
<a href="#image" data="link-img"><img src="foo.png" alt="Alt link"/></a>
|
8
|
+
<a title="This title is too long" data="link-fuzzy" href="#bar">A link at a time</a>
|
9
|
+
<a title="This title" data="link-exact" href="#foo">A link</a>
|
10
|
+
<a href="#bar" data="link-img-fuzzy"><img src="foo.png" alt="An image that is beautiful"/></a>
|
11
|
+
<a href="#foo" data="link-img-exact"><img src="foo.ong" alt="An image"/></a>
|
12
|
+
<a href="http://www.example.com" data="link-href">Href-ed link</a>
|
13
|
+
<a>Wrong Link</a>
|
14
|
+
<a href="#spacey" data="link-whitespace"> My
|
15
|
+
|
16
|
+
whitespaced
|
17
|
+
link</a>
|
18
|
+
<a href="#has-children" data="link-children">
|
19
|
+
An <em>emphatic</em> link with some children
|
20
|
+
</a>
|
21
|
+
</p>
|
22
|
+
|
23
|
+
<p>
|
24
|
+
<input type="submit" id="submit-with-id" data="id-submit" value="Has ID"/>
|
25
|
+
<input type="submit" value="submit-with-value" data="value-submit"/>
|
26
|
+
<input type="submit" value="not exact value submit" data="not-exact-value-submit"/>
|
27
|
+
<input type="submit" value="exact value submit" data="exact-value-submit"/>
|
28
|
+
|
29
|
+
<input type="button" id="button-with-id" data="id-button" value="Has ID"/>
|
30
|
+
<input type="button" value="button-with-value" data="value-button"/>
|
31
|
+
<input type="button" value="not exact value button" data="not-exact-value-button"/>
|
32
|
+
<input type="button" value="exact value button" data="exact-value-button"/>
|
33
|
+
|
34
|
+
<input type="image" id="imgbut-with-id" data="id-imgbut" value="Has ID"/>
|
35
|
+
<input type="image" value="imgbut-with-value" data="value-imgbut"/>
|
36
|
+
<input type="image" alt="imgbut-with-alt" data="alt-imgbut"/>
|
37
|
+
<input type="image" value="not exact value imgbut" data="not-exact-value-imgbut"/>
|
38
|
+
<input type="image" value="exact value imgbut" data="exact-value-imgbut"/>
|
39
|
+
|
40
|
+
<button id="btag-with-id" data="id-btag" value="Has ID"/>
|
41
|
+
<button value="btag-with-value" data="value-btag"/>
|
42
|
+
<button value="not exact value btag" data="not-exact-value-btag"/>
|
43
|
+
<button value="exact value btag" data="exact-value-btag"/>
|
44
|
+
|
45
|
+
<button data="text-btag">btag-with-text</button>
|
46
|
+
<button data="not-exact-text-btag">not exact text btag</button>
|
47
|
+
<button data="exact-text-btag">exact text btag</button>
|
48
|
+
|
49
|
+
<button data="btag-with-whitespace"> My
|
50
|
+
|
51
|
+
whitespaced
|
52
|
+
button</button>
|
53
|
+
<button data="btag-with-children">
|
54
|
+
An <em>emphatic</em> button with some children
|
55
|
+
</button>
|
56
|
+
|
57
|
+
<input type="schmoo" value="schmoo button" data="schmoo"/>
|
58
|
+
<label for="text-with-id">Label text <input type="text" id="text-with-id" data="id-text" value="monkey"/></label>
|
59
|
+
<input type="text" id="text-with-placeholder" data="placeholder-text" value="monkey" placeholder="Placeholder text"/>
|
60
|
+
<label for="problem-text-with-id">Label text's got an apostrophe <input type="text" id="problem-text-with-id" data="id-problem-text" value="monkey"/></label>
|
61
|
+
</p>
|
62
|
+
|
63
|
+
<p>
|
64
|
+
<fieldset id="some-fieldset-id" data="fieldset-id"></fieldset>
|
65
|
+
<fieldset data="fieldset-legend"><legend>Some Legend</legend></fieldset>
|
66
|
+
<fieldset data="fieldset-legend-span"><legend><span>Span Legend</span></legend></fieldset>
|
67
|
+
<fieldset data="fieldset-fuzzy"><legend>Long legend yo</legend></fieldset>
|
68
|
+
<fieldset data="fieldset-exact"><legend>Long legend</legend></fieldset>
|
69
|
+
</p>
|
70
|
+
|
71
|
+
<p>
|
72
|
+
<select>
|
73
|
+
<optgroup label="Group A" data="optgroup-a"></optgroup>
|
74
|
+
<optgroup label="Group B" data="optgroup-b"></optgroup>
|
75
|
+
</select>
|
76
|
+
</p>
|
77
|
+
|
78
|
+
<p>
|
79
|
+
<table id="whitespaced-table" data="table-with-whitespace">
|
80
|
+
<tr>
|
81
|
+
<td data="cell-whitespaced">I have
|
82
|
+
<span>nested whitespace</span>
|
83
|
+
</td>
|
84
|
+
<td>I don't</td>
|
85
|
+
</tr>
|
86
|
+
</table>
|
87
|
+
</p>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<div id="bar" title="barDiv">
|
2
|
+
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div title="noId"></div>
|
6
|
+
|
7
|
+
<div id="foo" title="fooDiv" data="id">
|
8
|
+
<p id="fooDiv">Blah</p>
|
9
|
+
<p>Bax</p>
|
10
|
+
<p title="monkey">Bax</p>
|
11
|
+
<ul><li>A list</li></ul>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div id="baz" title="bazDiv"></div>
|
15
|
+
|
16
|
+
<div id="preference">
|
17
|
+
<p id="is-fuzzy">allamas</p>
|
18
|
+
<p id="is-exact">llama</p>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<p id="whitespace">
|
22
|
+
A lot
|
23
|
+
|
24
|
+
of
|
25
|
+
whitespace
|
26
|
+
</p>
|
27
|
+
|
28
|
+
<div id="moar">
|
29
|
+
<p id="impchay">chimp</p>
|
30
|
+
<div id="elephantay">elephant</div>
|
31
|
+
<p id="amingoflay">flamingo</p>
|
32
|
+
</div>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<h1>This is a test</h1>
|
2
|
+
|
3
|
+
<p id="first">
|
4
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
5
|
+
tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple">labore</a>
|
6
|
+
et dolore magna aliqua. Ut enim ad minim veniam,
|
7
|
+
quis nostrud exercitation <a href="/foo" id="foo">ullamco</a> laboris nisi
|
8
|
+
ut aliquip ex ea commodo consequat.
|
9
|
+
<a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="awesome image" /></a>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<p id="second">
|
13
|
+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
14
|
+
dolore eu fugiat <a href="/redirect" id="red">Redirect</a> pariatur. Excepteur sint occaecat cupidatat non proident,
|
15
|
+
sunt in culpa qui officia
|
16
|
+
text with
|
17
|
+
whitespace
|
18
|
+
id est laborum.
|
19
|
+
</p>
|
20
|
+
|
21
|
+
<p>
|
22
|
+
<input type="text" id="test_field" value="monkey"/>
|
23
|
+
<textarea>banana</textarea>
|
24
|
+
<a href="/redirect_back">BackToMyself</a>
|
25
|
+
<a title="twas a fine link" href="/redirect">A link came first</a>
|
26
|
+
<a title="a fine link" href="/with_simple_html">A link</a>
|
27
|
+
<a title="a fine link with data method" data-method="delete" href="/delete">A link with data-method</a>
|
28
|
+
<a>No Href</a>
|
29
|
+
<a href="">Blank Href</a>
|
30
|
+
<a href="#">Blank Anchor</a>
|
31
|
+
<a href="#anchor">Anchor</a>
|
32
|
+
<a href="/with_simple_html#anchor">Anchor on different page</a>
|
33
|
+
<a href="/with_html#anchor">Anchor on same page</a>
|
34
|
+
<input type="text" value="" id="test_field">
|
35
|
+
<input type="text" checked="checked" id="checked_field">
|
36
|
+
<a href="/redirect"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="very fine image" /></a>
|
37
|
+
<a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="fine image" /></a>
|
38
|
+
</p>
|
39
|
+
|
40
|
+
<div id="hidden" style="display: none;">
|
41
|
+
<div id="hidden_via_ancestor">Inside element with hidden ancestor</div>
|
42
|
+
<a href="/with_simple_html" title="awesome title" class="simple">hidden link</a>
|
43
|
+
</div>
|
data/spec/html_spec.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
describe XPath::HTML do
|
5
|
+
let(:template) { 'form' }
|
6
|
+
let(:template_path) { File.read(File.expand_path("fixtures/#{template}.html", File.dirname(__FILE__))) }
|
7
|
+
let(:doc) { Nokogiri::HTML(template_path) }
|
8
|
+
|
9
|
+
def get(*args)
|
10
|
+
all(*args).first
|
11
|
+
end
|
12
|
+
|
13
|
+
def all(*args)
|
14
|
+
XPath::HTML.send(subject, *args).to_xpaths.map do |xpath|
|
15
|
+
doc.xpath(xpath)
|
16
|
+
end.flatten.uniq.map { |node| node[:data] }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#link' do
|
20
|
+
subject { :link }
|
21
|
+
|
22
|
+
it("finds links by id") { get('some-id').should == 'link-id' }
|
23
|
+
it("finds links by content") { get('An awesome link').should == 'link-text' }
|
24
|
+
it("finds links by content regardless of whitespace") { get('My whitespaced link').should == 'link-whitespace' }
|
25
|
+
it("finds links with child tags by content") { get('An emphatic link').should == 'link-children' }
|
26
|
+
it("finds links by the content of theur child tags") { get('emphatic').should == 'link-children' }
|
27
|
+
it("finds links by approximate content") { get('awesome').should == 'link-text' }
|
28
|
+
it("prefers exact matches of content") { all('A link').should == ['link-exact', 'link-fuzzy'] }
|
29
|
+
it("finds links by title") { get('My title').should == 'link-title' }
|
30
|
+
it("finds links by approximate title") { get('title').should == 'link-title' }
|
31
|
+
it("prefers exact matches of title") { all('This title').should == ['link-exact', 'link-fuzzy'] }
|
32
|
+
it("finds links by image's alt attribute") { get('Alt link').should == 'link-img' }
|
33
|
+
it("finds links by image's approximate alt attribute") { get('Alt').should == 'link-img' }
|
34
|
+
it("prefers exact matches of image's alt attribute") { all('An image').should == ['link-img-exact', 'link-img-fuzzy'] }
|
35
|
+
it("does not find links without href attriutes") { get('Wrong Link').should be_nil }
|
36
|
+
it("finds links with an href") { get("Href-ed link", :href => 'http://www.example.com').should == 'link-href' }
|
37
|
+
it("does not find links with an incorrect href") { get("Href-ed link", :href => 'http://www.somewhere.com').should be_nil }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#button' do
|
41
|
+
subject { :button }
|
42
|
+
|
43
|
+
context "with submit type" do
|
44
|
+
it("finds buttons by id") { get('submit-with-id').should == 'id-submit' }
|
45
|
+
it("finds buttons by value") { get('submit-with-value').should == 'value-submit' }
|
46
|
+
it("finds buttons by approximate value") { get('mit-with-val').should == 'value-submit' }
|
47
|
+
it("prefers buttons with exact value") { all('exact value submit').should == ['exact-value-submit', 'not-exact-value-submit'] }
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with button type" do
|
51
|
+
it("finds buttons by id") { get('button-with-id').should == 'id-button' }
|
52
|
+
it("finds buttons by value") { get('button-with-value').should == 'value-button' }
|
53
|
+
it("finds buttons by approximate value") { get('ton-with-val').should == 'value-button' }
|
54
|
+
it("prefers buttons with exact value") { all('exact value button').should == ['exact-value-button', 'not-exact-value-button'] }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with image type" do
|
58
|
+
it("finds buttons by id") { get('imgbut-with-id').should == 'id-imgbut' }
|
59
|
+
it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' }
|
60
|
+
it("finds buttons by approximate value") { get('gbut-with-val').should == 'value-imgbut' }
|
61
|
+
it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' }
|
62
|
+
it("prefers buttons with exact value") { all('exact value imgbut').should == ['exact-value-imgbut', 'not-exact-value-imgbut'] }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with button tag" do
|
66
|
+
it("finds buttons by id") { get('btag-with-id').should == 'id-btag' }
|
67
|
+
it("finds buttons by value") { get('btag-with-value').should == 'value-btag' }
|
68
|
+
it("finds buttons by approximate value") { get('tag-with-val').should == 'value-btag' }
|
69
|
+
it("finds prefers buttons with exact value") { all('exact value btag').should == ['exact-value-btag', 'not-exact-value-btag'] }
|
70
|
+
it("finds buttons by text") { get('btag-with-text').should == 'text-btag' }
|
71
|
+
it("finds buttons by text ignoring whitespace") { get('My whitespaced button').should == 'btag-with-whitespace' }
|
72
|
+
it("finds buttons by approximate text ") { get('tag-with-tex').should == 'text-btag' }
|
73
|
+
it("finds buttons with child tags by text") { get('An emphatic button').should == 'btag-with-children' }
|
74
|
+
it("finds buttons by text of their children") { get('emphatic').should == 'btag-with-children' }
|
75
|
+
it("prefers buttons with exact text") { all('exact text btag').should == ['exact-text-btag', 'not-exact-text-btag'] }
|
76
|
+
end
|
77
|
+
|
78
|
+
context "with unkown type" do
|
79
|
+
it("does not find the button") { get('schmoo button').should be_nil }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#fieldset' do
|
84
|
+
subject { :fieldset }
|
85
|
+
|
86
|
+
it("finds fieldsets by id") { get('some-fieldset-id').should == 'fieldset-id' }
|
87
|
+
it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' }
|
88
|
+
it("finds fieldsets by legend child tags") { get('Span Legend').should == 'fieldset-legend-span' }
|
89
|
+
it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' }
|
90
|
+
it("prefers exact legend") { all('Long legend').should == ['fieldset-exact', 'fieldset-fuzzy'] }
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#field' do
|
94
|
+
subject { :field }
|
95
|
+
|
96
|
+
context "by id" do
|
97
|
+
it("finds inputs with text type") {}
|
98
|
+
it("finds inputs with password type") {}
|
99
|
+
it("finds inputs with custom type") {}
|
100
|
+
it("finds textareas") {}
|
101
|
+
it("finds select boxes") {}
|
102
|
+
it("does not find submit buttons") {}
|
103
|
+
it("does not find image buttons") {}
|
104
|
+
it("does not find hidden fields") {}
|
105
|
+
end
|
106
|
+
|
107
|
+
context "by name" do
|
108
|
+
it("finds inputs with text type") {}
|
109
|
+
it("finds inputs with password type") {}
|
110
|
+
it("finds inputs with custom type") {}
|
111
|
+
it("finds textareas") {}
|
112
|
+
it("finds select boxes") {}
|
113
|
+
it("does not find submit buttons") {}
|
114
|
+
it("does not find image buttons") {}
|
115
|
+
it("does not find hidden fields") {}
|
116
|
+
end
|
117
|
+
|
118
|
+
context "by referenced label" do
|
119
|
+
it("finds inputs with text type") {}
|
120
|
+
it("finds inputs with password type") {}
|
121
|
+
it("finds inputs with custom type") {}
|
122
|
+
it("finds textareas") {}
|
123
|
+
it("finds select boxes") {}
|
124
|
+
it("does not find submit buttons") {}
|
125
|
+
it("does not find image buttons") {}
|
126
|
+
it("does not find hidden fields") {}
|
127
|
+
end
|
128
|
+
|
129
|
+
context "by parent label" do
|
130
|
+
it("finds inputs with text type") { get('Label text').should == 'id-text' }
|
131
|
+
it("finds inputs where label has problem chars") { get("Label text's got an apostrophe").should == 'id-problem-text' }
|
132
|
+
it("finds inputs with password type") {}
|
133
|
+
it("finds inputs with custom type") {}
|
134
|
+
it("finds textareas") {}
|
135
|
+
it("finds select boxes") {}
|
136
|
+
it("does not find submit buttons") {}
|
137
|
+
it("does not find image buttons") {}
|
138
|
+
it("does not find hidden fields") {}
|
139
|
+
end
|
140
|
+
|
141
|
+
context "with :with option" do
|
142
|
+
it("finds inputs that match option") {}
|
143
|
+
it("omits inputs that don't match option") {}
|
144
|
+
it("finds textareas that match option") {}
|
145
|
+
it("omits textareas that don't match option") {}
|
146
|
+
end
|
147
|
+
|
148
|
+
context "with :checked option" do
|
149
|
+
context "when true" do
|
150
|
+
it("finds checked fields") {}
|
151
|
+
it("omits unchecked fields") {}
|
152
|
+
end
|
153
|
+
context "when false" do
|
154
|
+
it("finds unchecked fields") {}
|
155
|
+
it("omits checked fields") {}
|
156
|
+
end
|
157
|
+
context "when ommitted" do
|
158
|
+
it("finds unchecked fields") {}
|
159
|
+
it("finds checked fields") {}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#fillable_field' do
|
165
|
+
subject{ :fillable_field }
|
166
|
+
context "by parent label" do
|
167
|
+
it("finds inputs with text type") { get('Label text').should == 'id-text' }
|
168
|
+
it("finds inputs where label has problem chars") { get("Label text's got an apostrophe").should == 'id-problem-text' }
|
169
|
+
end
|
170
|
+
context "by placeholder" do
|
171
|
+
it("finds inputs with placeholder text") { get('Placeholder text').should == 'placeholder-text' }
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#optgroup" do
|
177
|
+
subject { :optgroup }
|
178
|
+
|
179
|
+
it("finds optgroups by label") { get('Group A').should == 'optgroup-a' }
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "#table" do
|
183
|
+
subject {:table}
|
184
|
+
|
185
|
+
it("finds cell content regardless of whitespace") {get('whitespaced-table', :rows => [["I have nested whitespace", "I don't"]]).should == 'table-with-whitespace'}
|
186
|
+
end
|
187
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/union_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe XPath::Union do
|
4
|
+
let(:template) { File.read(File.expand_path('fixtures/simple.html', File.dirname(__FILE__))) }
|
5
|
+
let(:doc) { Nokogiri::HTML(template) }
|
6
|
+
|
7
|
+
describe '#expressions' do
|
8
|
+
it "should return the expressions" do
|
9
|
+
@expr1 = XPath.generate { |x| x.descendant(:p) }
|
10
|
+
@expr2 = XPath.generate { |x| x.descendant(:div) }
|
11
|
+
@collection = XPath::Union.new(@expr1, @expr2)
|
12
|
+
@collection.expressions.should == [@expr1, @expr2]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#each' do
|
17
|
+
it "should iterate through the expressions" do
|
18
|
+
@expr1 = XPath.generate { |x| x.descendant(:p) }
|
19
|
+
@expr2 = XPath.generate { |x| x.descendant(:div) }
|
20
|
+
@collection = XPath::Union.new(@expr1, @expr2)
|
21
|
+
exprs = []
|
22
|
+
@collection.each { |expr| exprs << expr }
|
23
|
+
exprs.should == [@expr1, @expr2]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#map' do
|
28
|
+
it "should map the expressions" do
|
29
|
+
@expr1 = XPath.generate { |x| x.descendant(:p) }
|
30
|
+
@expr2 = XPath.generate { |x| x.descendant(:div) }
|
31
|
+
@collection = XPath::Union.new(@expr1, @expr2)
|
32
|
+
@collection.map { |expr| expr.class }.should == [XPath::Expression::Descendant, XPath::Expression::Descendant]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#to_xpath' do
|
37
|
+
it "should create a valid xpath expression" do
|
38
|
+
@expr1 = XPath.generate { |x| x.descendant(:p) }
|
39
|
+
@expr2 = XPath.generate { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }
|
40
|
+
@collection = XPath::Union.new(@expr1, @expr2)
|
41
|
+
@results = doc.xpath(@collection.to_xpath)
|
42
|
+
@results[0][:title].should == 'fooDiv'
|
43
|
+
@results[1].text.should == 'Blah'
|
44
|
+
@results[2].text.should == 'Bax'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#where, #apply and others' do
|
49
|
+
it "should be delegated to the individual expressions" do
|
50
|
+
@expr1 = XPath.generate { |x| x.descendant(:p) }
|
51
|
+
@expr2 = XPath.generate { |x| x.descendant(:div) }
|
52
|
+
@collection = XPath::Union.new(@expr1, @expr2)
|
53
|
+
@xpath1 = @collection.where(XPath.attr(:id) == 'foo').to_xpath
|
54
|
+
@xpath2 = @collection.where(XPath.attr(:id) == XPath.varstring(:id)).apply(:id => 'fooDiv').to_xpath
|
55
|
+
@results = doc.xpath(@xpath1)
|
56
|
+
@results[0][:title].should == 'fooDiv'
|
57
|
+
@results = doc.xpath(@xpath2)
|
58
|
+
@results[0][:id].should == 'fooDiv'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|