nokogiri 1.1.1-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- data/History.ja.txt +99 -0
- data/History.txt +99 -0
- data/Manifest.txt +141 -0
- data/README.ja.txt +100 -0
- data/README.txt +109 -0
- data/Rakefile +354 -0
- data/ext/nokogiri/extconf.rb +93 -0
- data/ext/nokogiri/html_document.c +86 -0
- data/ext/nokogiri/html_document.h +10 -0
- data/ext/nokogiri/html_sax_parser.c +36 -0
- data/ext/nokogiri/html_sax_parser.h +11 -0
- data/ext/nokogiri/native.c +41 -0
- data/ext/nokogiri/native.h +50 -0
- data/ext/nokogiri/xml_cdata.c +44 -0
- data/ext/nokogiri/xml_cdata.h +9 -0
- data/ext/nokogiri/xml_comment.c +42 -0
- data/ext/nokogiri/xml_comment.h +9 -0
- data/ext/nokogiri/xml_document.c +206 -0
- data/ext/nokogiri/xml_document.h +10 -0
- data/ext/nokogiri/xml_dtd.c +121 -0
- data/ext/nokogiri/xml_dtd.h +8 -0
- data/ext/nokogiri/xml_io.c +17 -0
- data/ext/nokogiri/xml_io.h +9 -0
- data/ext/nokogiri/xml_node.c +727 -0
- data/ext/nokogiri/xml_node.h +13 -0
- data/ext/nokogiri/xml_node_set.c +118 -0
- data/ext/nokogiri/xml_node_set.h +9 -0
- data/ext/nokogiri/xml_reader.c +465 -0
- data/ext/nokogiri/xml_reader.h +10 -0
- data/ext/nokogiri/xml_sax_parser.c +201 -0
- data/ext/nokogiri/xml_sax_parser.h +10 -0
- data/ext/nokogiri/xml_syntax_error.c +199 -0
- data/ext/nokogiri/xml_syntax_error.h +11 -0
- data/ext/nokogiri/xml_text.c +40 -0
- data/ext/nokogiri/xml_text.h +9 -0
- data/ext/nokogiri/xml_xpath.c +53 -0
- data/ext/nokogiri/xml_xpath.h +11 -0
- data/ext/nokogiri/xml_xpath_context.c +214 -0
- data/ext/nokogiri/xml_xpath_context.h +9 -0
- data/ext/nokogiri/xslt_stylesheet.c +123 -0
- data/ext/nokogiri/xslt_stylesheet.h +9 -0
- data/lib/action-nokogiri.rb +30 -0
- data/lib/nokogiri.rb +72 -0
- data/lib/nokogiri/css.rb +25 -0
- data/lib/nokogiri/css/generated_parser.rb +721 -0
- data/lib/nokogiri/css/generated_tokenizer.rb +159 -0
- data/lib/nokogiri/css/node.rb +97 -0
- data/lib/nokogiri/css/parser.rb +64 -0
- data/lib/nokogiri/css/parser.y +216 -0
- data/lib/nokogiri/css/syntax_error.rb +6 -0
- data/lib/nokogiri/css/tokenizer.rb +9 -0
- data/lib/nokogiri/css/tokenizer.rex +63 -0
- data/lib/nokogiri/css/xpath_visitor.rb +168 -0
- data/lib/nokogiri/decorators.rb +2 -0
- data/lib/nokogiri/decorators/hpricot.rb +3 -0
- data/lib/nokogiri/decorators/hpricot/node.rb +56 -0
- data/lib/nokogiri/decorators/hpricot/node_set.rb +54 -0
- data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +28 -0
- data/lib/nokogiri/decorators/slop.rb +31 -0
- data/lib/nokogiri/hpricot.rb +51 -0
- data/lib/nokogiri/html.rb +105 -0
- data/lib/nokogiri/html/builder.rb +9 -0
- data/lib/nokogiri/html/document.rb +9 -0
- data/lib/nokogiri/html/sax/parser.rb +21 -0
- data/lib/nokogiri/version.rb +3 -0
- data/lib/nokogiri/xml.rb +83 -0
- data/lib/nokogiri/xml/after_handler.rb +18 -0
- data/lib/nokogiri/xml/attr.rb +10 -0
- data/lib/nokogiri/xml/before_handler.rb +33 -0
- data/lib/nokogiri/xml/builder.rb +84 -0
- data/lib/nokogiri/xml/cdata.rb +9 -0
- data/lib/nokogiri/xml/comment.rb +6 -0
- data/lib/nokogiri/xml/document.rb +55 -0
- data/lib/nokogiri/xml/dtd.rb +6 -0
- data/lib/nokogiri/xml/element.rb +6 -0
- data/lib/nokogiri/xml/entity_declaration.rb +9 -0
- data/lib/nokogiri/xml/node.rb +333 -0
- data/lib/nokogiri/xml/node_set.rb +197 -0
- data/lib/nokogiri/xml/notation.rb +6 -0
- data/lib/nokogiri/xml/reader.rb +20 -0
- data/lib/nokogiri/xml/sax.rb +9 -0
- data/lib/nokogiri/xml/sax/document.rb +59 -0
- data/lib/nokogiri/xml/sax/parser.rb +37 -0
- data/lib/nokogiri/xml/syntax_error.rb +21 -0
- data/lib/nokogiri/xml/text.rb +6 -0
- data/lib/nokogiri/xml/xpath.rb +10 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
- data/lib/nokogiri/xml/xpath_context.rb +14 -0
- data/lib/nokogiri/xslt.rb +28 -0
- data/lib/nokogiri/xslt/stylesheet.rb +6 -0
- data/test/css/test_nthiness.rb +159 -0
- data/test/css/test_parser.rb +237 -0
- data/test/css/test_tokenizer.rb +162 -0
- data/test/css/test_xpath_visitor.rb +64 -0
- data/test/files/dont_hurt_em_why.xml +422 -0
- data/test/files/exslt.xml +8 -0
- data/test/files/exslt.xslt +35 -0
- data/test/files/staff.xml +59 -0
- data/test/files/staff.xslt +32 -0
- data/test/files/tlm.html +850 -0
- data/test/helper.rb +78 -0
- data/test/hpricot/files/basic.xhtml +17 -0
- data/test/hpricot/files/boingboing.html +2266 -0
- data/test/hpricot/files/cy0.html +3653 -0
- data/test/hpricot/files/immob.html +400 -0
- data/test/hpricot/files/pace_application.html +1320 -0
- data/test/hpricot/files/tenderlove.html +16 -0
- data/test/hpricot/files/uswebgen.html +220 -0
- data/test/hpricot/files/utf8.html +1054 -0
- data/test/hpricot/files/week9.html +1723 -0
- data/test/hpricot/files/why.xml +19 -0
- data/test/hpricot/load_files.rb +11 -0
- data/test/hpricot/test_alter.rb +67 -0
- data/test/hpricot/test_builder.rb +27 -0
- data/test/hpricot/test_parser.rb +426 -0
- data/test/hpricot/test_paths.rb +15 -0
- data/test/hpricot/test_preserved.rb +77 -0
- data/test/hpricot/test_xml.rb +30 -0
- data/test/html/sax/test_parser.rb +27 -0
- data/test/html/test_builder.rb +89 -0
- data/test/html/test_document.rb +150 -0
- data/test/html/test_node.rb +21 -0
- data/test/test_convert_xpath.rb +185 -0
- data/test/test_css_cache.rb +57 -0
- data/test/test_gc.rb +15 -0
- data/test/test_memory_leak.rb +38 -0
- data/test/test_nokogiri.rb +97 -0
- data/test/test_reader.rb +222 -0
- data/test/test_xslt_transforms.rb +93 -0
- data/test/xml/sax/test_parser.rb +95 -0
- data/test/xml/test_attr.rb +15 -0
- data/test/xml/test_builder.rb +16 -0
- data/test/xml/test_cdata.rb +18 -0
- data/test/xml/test_comment.rb +16 -0
- data/test/xml/test_document.rb +195 -0
- data/test/xml/test_dtd.rb +43 -0
- data/test/xml/test_node.rb +394 -0
- data/test/xml/test_node_set.rb +143 -0
- data/test/xml/test_text.rb +13 -0
- data/test/xml/test_xpath.rb +105 -0
- data/vendor/hoe.rb +1020 -0
- metadata +233 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module XML
|
3
|
+
class Reader
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def attributes
|
7
|
+
Hash[*(attribute_nodes.map { |node|
|
8
|
+
[node.name, node.to_s]
|
9
|
+
}.flatten)].merge(namespaces || {})
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(&block)
|
13
|
+
while node = self.read
|
14
|
+
block.call(node)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
private :initialize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module XML
|
3
|
+
module SAX
|
4
|
+
class Document
|
5
|
+
###
|
6
|
+
# Called when document starts parsing
|
7
|
+
def start_document
|
8
|
+
end
|
9
|
+
|
10
|
+
###
|
11
|
+
# Called when document ends parsing
|
12
|
+
def end_document
|
13
|
+
end
|
14
|
+
|
15
|
+
###
|
16
|
+
# Called at the beginning of an element
|
17
|
+
# +name+ is the name of the tag with +attrs+ as attributes
|
18
|
+
def start_element name, attrs = []
|
19
|
+
end
|
20
|
+
|
21
|
+
###
|
22
|
+
# Called at the end of an element
|
23
|
+
# +name+ is the tag name
|
24
|
+
def end_element name
|
25
|
+
end
|
26
|
+
|
27
|
+
###
|
28
|
+
# Characters read between a tag
|
29
|
+
# +string+ contains the character data
|
30
|
+
def characters string
|
31
|
+
end
|
32
|
+
|
33
|
+
###
|
34
|
+
# Called when comments are encountered
|
35
|
+
# +string+ contains the comment data
|
36
|
+
def comment string
|
37
|
+
end
|
38
|
+
|
39
|
+
###
|
40
|
+
# Called on document warnings
|
41
|
+
# +string+ contains the warning
|
42
|
+
def warning string
|
43
|
+
end
|
44
|
+
|
45
|
+
###
|
46
|
+
# Called on document errors
|
47
|
+
# +string+ contains the error
|
48
|
+
def error string
|
49
|
+
end
|
50
|
+
|
51
|
+
###
|
52
|
+
# Called when cdata blocks are found
|
53
|
+
# +string+ contains the cdata content
|
54
|
+
def cdata_block string
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module XML
|
3
|
+
module SAX
|
4
|
+
class Parser
|
5
|
+
attr_accessor :document
|
6
|
+
def initialize(doc = XML::SAX::Document.new)
|
7
|
+
@document = doc
|
8
|
+
end
|
9
|
+
|
10
|
+
###
|
11
|
+
# Parse given +thing+ which may be a string containing xml, or an
|
12
|
+
# IO object.
|
13
|
+
def parse thing
|
14
|
+
if thing.respond_to?(:read) && thing.respond_to?(:close)
|
15
|
+
parse_io(thing)
|
16
|
+
else
|
17
|
+
parse_memory(thing)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
###
|
22
|
+
# Parse given +io+
|
23
|
+
def parse_io io, encoding = 0
|
24
|
+
native_parse_io io, encoding
|
25
|
+
end
|
26
|
+
|
27
|
+
###
|
28
|
+
# Parse a file with +filename+
|
29
|
+
def parse_file filename
|
30
|
+
raise Errno::ENOENT unless File.exists?(filename)
|
31
|
+
raise Errno::EISDIR if File.directory?(filename)
|
32
|
+
native_parse_file filename
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'nokogiri/xslt/stylesheet'
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module XSLT
|
5
|
+
class << self
|
6
|
+
def parse(string)
|
7
|
+
Stylesheet.parse_stylesheet_doc(XML.parse(string))
|
8
|
+
end
|
9
|
+
|
10
|
+
def quote_params params
|
11
|
+
parray = (params.instance_of?(Hash) ? params.to_a.flatten : params).dup
|
12
|
+
parray.each_with_index do |v,i|
|
13
|
+
if i % 2 > 0
|
14
|
+
parray[i]=
|
15
|
+
if v =~ /'/
|
16
|
+
"concat('#{ v.gsub(/'/, %q{', "'", '}) }')"
|
17
|
+
else
|
18
|
+
"'#{v}'";
|
19
|
+
end
|
20
|
+
else
|
21
|
+
parray[i] = v.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
parray.flatten
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module CSS
|
5
|
+
class TestNthiness < Nokogiri::TestCase
|
6
|
+
def setup
|
7
|
+
doc = <<EOF
|
8
|
+
<html>
|
9
|
+
<table>
|
10
|
+
<tr><td>row1 </td></tr>
|
11
|
+
<tr><td>row2 </td></tr>
|
12
|
+
<tr><td>row3 </td></tr>
|
13
|
+
<tr><td>row4 </td></tr>
|
14
|
+
<tr><td>row5 </td></tr>
|
15
|
+
<tr><td>row6 </td></tr>
|
16
|
+
<tr><td>row7 </td></tr>
|
17
|
+
<tr><td>row8 </td></tr>
|
18
|
+
<tr><td>row9 </td></tr>
|
19
|
+
<tr><td>row10 </td></tr>
|
20
|
+
<tr><td>row11 </td></tr>
|
21
|
+
<tr><td>row12 </td></tr>
|
22
|
+
<tr><td>row13 </td></tr>
|
23
|
+
<tr><td>row14 </td></tr>
|
24
|
+
</table>
|
25
|
+
<div>
|
26
|
+
<b>bold1 </b>
|
27
|
+
<i>italic1 </i>
|
28
|
+
<b>bold2 </b>
|
29
|
+
<i>italic2 </i>
|
30
|
+
<p>para1 </p>
|
31
|
+
<b>bold3 </b>
|
32
|
+
</div>
|
33
|
+
<div>
|
34
|
+
<p>para2 </p>
|
35
|
+
<p>para3 </p>
|
36
|
+
</div>
|
37
|
+
<div>
|
38
|
+
<p>para4 </p>
|
39
|
+
</div>
|
40
|
+
<p class='empty'></p>
|
41
|
+
<p class='not-empty'><b></b></p>
|
42
|
+
</html>
|
43
|
+
EOF
|
44
|
+
@parser = Nokogiri.Hpricot doc
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def test_even
|
49
|
+
assert_result_rows [2,4,6,8,10,12,14], @parser.search("table/tr:nth(even)")
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_odd
|
53
|
+
assert_result_rows [1,3,5,7,9,11,13], @parser.search("table/tr:nth(odd)")
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_2n
|
57
|
+
assert_equal @parser.search("table/tr:nth(even)").inner_text, @parser.search("table/tr:nth(2n)").inner_text
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_2np1
|
61
|
+
assert_equal @parser.search("table/tr:nth(odd)").inner_text, @parser.search("table/tr:nth(2n+1)").inner_text
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_4np3
|
65
|
+
assert_result_rows [3,7,11], @parser.search("table/tr:nth(4n+3)")
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_3np4
|
69
|
+
assert_result_rows [4,7,10,13], @parser.search("table/tr:nth(3n+4)")
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_mnp3
|
73
|
+
assert_result_rows [1,2,3], @parser.search("table/tr:nth(-n+3)")
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_np3
|
77
|
+
assert_result_rows [3,4,5,6,7,8,9,10,11,12,13,14], @parser.search("table/tr:nth(n+3)")
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_first
|
81
|
+
assert_result_rows [1], @parser.search("table/tr:first")
|
82
|
+
assert_result_rows [1], @parser.search("table/tr:first()")
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_last
|
86
|
+
assert_result_rows [14], @parser.search("table/tr:last")
|
87
|
+
assert_result_rows [14], @parser.search("table/tr:last()")
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_first_child
|
91
|
+
assert_result_rows [1], @parser.search("div/b:first-child"), "bold"
|
92
|
+
assert_result_rows [1], @parser.search("table/tr:first-child")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_last_child
|
96
|
+
assert_result_rows [3], @parser.search("div/b:last-child"), "bold"
|
97
|
+
assert_result_rows [14], @parser.search("table/tr:last-child")
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_first_of_type
|
101
|
+
assert_result_rows [1], @parser.search("table/tr:first-of-type")
|
102
|
+
assert_result_rows [1], @parser.search("div/b:first-of-type"), "bold"
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_last_of_type
|
106
|
+
assert_result_rows [14], @parser.search("table/tr:last-of-type")
|
107
|
+
assert_result_rows [3], @parser.search("div/b:last-of-type"), "bold"
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_only_of_type
|
111
|
+
assert_result_rows [1,4], @parser.search("div/p:only-of-type"), "para"
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_only_child
|
115
|
+
assert_result_rows [4], @parser.search("div/p:only-child"), "para"
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_empty
|
119
|
+
result = @parser.search("p:empty")
|
120
|
+
assert_equal 1, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
|
121
|
+
assert_equal 'empty', result.first['class']
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_parent
|
125
|
+
result = @parser.search("p:parent")
|
126
|
+
assert_equal 5, result.size
|
127
|
+
0.upto(3) do |j|
|
128
|
+
assert_equal "para#{j+1} ", result[j].inner_text
|
129
|
+
end
|
130
|
+
assert_equal "not-empty", result[4]['class']
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_siblings
|
134
|
+
doc = <<-EOF
|
135
|
+
<html><body><div>
|
136
|
+
<p id="1">p1 </p>
|
137
|
+
<p id="2">p2 </p>
|
138
|
+
<p id="3">p3 </p>
|
139
|
+
<p id="4">p4 </p>
|
140
|
+
<p id="5">p5 </p>
|
141
|
+
EOF
|
142
|
+
parser = Nokogiri.Hpricot doc
|
143
|
+
|
144
|
+
assert_equal 2, parser.search("#3 ~ p").size
|
145
|
+
assert_equal "p4 p5 ", parser.search("#3 ~ p").inner_text
|
146
|
+
assert_equal 0, parser.search("#5 ~ p").size
|
147
|
+
|
148
|
+
assert_equal 1, parser.search("#3 + p").size
|
149
|
+
assert_equal "p4 ", parser.search("#3 + p").inner_text
|
150
|
+
assert_equal 0, parser.search("#5 + p").size
|
151
|
+
end
|
152
|
+
|
153
|
+
def assert_result_rows intarray, result, word="row"
|
154
|
+
assert_equal intarray.size, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
|
155
|
+
assert_equal intarray.map{|j| "#{word}#{j}"}.join(' '), result.inner_text.strip, result.inner_text
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module CSS
|
5
|
+
class TestParser < Nokogiri::TestCase
|
6
|
+
def setup
|
7
|
+
@parser = Nokogiri::CSS::Parser.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_syntax_error_raised
|
11
|
+
assert_raises(CSS::SyntaxError) { @parser.parse("a[x=]") }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_find_by_type
|
15
|
+
ast = @parser.parse("a:nth-child(2)").first
|
16
|
+
matches = ast.find_by_type(
|
17
|
+
[:CONDITIONAL_SELECTOR,
|
18
|
+
[:ELEMENT_NAME],
|
19
|
+
[:PSEUDO_CLASS,
|
20
|
+
[:FUNCTION]
|
21
|
+
]
|
22
|
+
]
|
23
|
+
)
|
24
|
+
assert_equal(1, matches.length)
|
25
|
+
assert_equal(ast, matches.first)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_to_type
|
29
|
+
ast = @parser.parse("a:nth-child(2)").first
|
30
|
+
assert_equal(
|
31
|
+
[:CONDITIONAL_SELECTOR,
|
32
|
+
[:ELEMENT_NAME],
|
33
|
+
[:PSEUDO_CLASS,
|
34
|
+
[:FUNCTION]
|
35
|
+
]
|
36
|
+
], ast.to_type
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_to_a
|
41
|
+
asts = @parser.parse("a:nth-child(2)")
|
42
|
+
assert_equal(
|
43
|
+
[:CONDITIONAL_SELECTOR,
|
44
|
+
[:ELEMENT_NAME, ["a"]],
|
45
|
+
[:PSEUDO_CLASS,
|
46
|
+
[:FUNCTION, ["nth-child("], ["2"]]
|
47
|
+
]
|
48
|
+
], asts.first.to_a
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_function_with_arguments
|
53
|
+
assert_xpath "//*[position() = 2 and self::a]",
|
54
|
+
@parser.parse("a[2]")
|
55
|
+
assert_xpath "//*[position() = 2 and self::a]",
|
56
|
+
@parser.parse("a:nth-child(2)")
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_carrot
|
60
|
+
assert_xpath "//a[starts-with(@id, 'Boing')]",
|
61
|
+
@parser.parse("a[id^='Boing']")
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_attributes_with_at
|
65
|
+
## This is non standard CSS
|
66
|
+
assert_xpath "//a[@id = 'Boing']",
|
67
|
+
@parser.parse("a[@id='Boing']")
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_not_equal
|
71
|
+
## This is non standard CSS
|
72
|
+
assert_xpath "//a[child::text() != 'Boing']",
|
73
|
+
@parser.parse("a[text()!='Boing']")
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_function
|
77
|
+
## This is non standard CSS
|
78
|
+
assert_xpath "//a[child::text()]",
|
79
|
+
@parser.parse("a[text()]")
|
80
|
+
|
81
|
+
## This is non standard CSS
|
82
|
+
assert_xpath "//child::text()",
|
83
|
+
@parser.parse("text()")
|
84
|
+
|
85
|
+
## This is non standard CSS
|
86
|
+
assert_xpath "//a[contains(child::text(), 'Boing')]",
|
87
|
+
@parser.parse("a[text()*='Boing']")
|
88
|
+
|
89
|
+
## This is non standard CSS
|
90
|
+
assert_xpath "//script//comment()",
|
91
|
+
@parser.parse("script comment()")
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_nonstandard_nth_selectors
|
95
|
+
## These are non standard CSS
|
96
|
+
assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
|
97
|
+
assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
|
98
|
+
assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
|
99
|
+
assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
|
100
|
+
assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
|
101
|
+
assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
|
102
|
+
assert_xpath '//a[node()]', @parser.parse('a:parent')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_standard_nth_selectors
|
106
|
+
assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
|
107
|
+
assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
|
108
|
+
assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
|
109
|
+
assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
|
110
|
+
assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
|
111
|
+
assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
|
112
|
+
assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_nth_child_selectors
|
116
|
+
assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
|
117
|
+
assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
|
118
|
+
assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
|
119
|
+
assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_miscellaneous_selectors
|
123
|
+
assert_xpath '//*[last() = 1 and self::a]',
|
124
|
+
@parser.parse('a:only-child')
|
125
|
+
assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
|
126
|
+
assert_xpath '//a[not(node())]', @parser.parse('a:empty')
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_nth_a_n_plus_b
|
130
|
+
assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(2n)')
|
131
|
+
assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(2n+1)')
|
132
|
+
assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
|
133
|
+
assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
|
134
|
+
assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
|
135
|
+
assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
|
136
|
+
assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
|
137
|
+
assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
|
138
|
+
assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_preceding_selector
|
142
|
+
assert_xpath "//F[preceding-sibling::E]",
|
143
|
+
@parser.parse("E ~ F")
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_direct_preceding_selector
|
147
|
+
assert_xpath "//E/following-sibling::*[1]/self::F",
|
148
|
+
@parser.parse("E + F")
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_attribute
|
152
|
+
assert_xpath "//h1[@a = 'Tender Lovemaking']",
|
153
|
+
@parser.parse("h1[a='Tender Lovemaking']")
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_id
|
157
|
+
assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_pseudo_class_no_ident
|
161
|
+
assert_xpath "//*[link(.)]", @parser.parse(':link')
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_pseudo_class
|
165
|
+
assert_xpath "//a[link(.)]", @parser.parse('a:link')
|
166
|
+
assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
|
167
|
+
assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
|
168
|
+
assert_xpath "//a[active(.)]", @parser.parse('a:active')
|
169
|
+
assert_xpath "//a[active(.) and contains(concat(' ', @class, ' '), ' foo ')]",
|
170
|
+
@parser.parse('a:active.foo')
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_star
|
174
|
+
assert_xpath "//*", @parser.parse('*')
|
175
|
+
assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
|
176
|
+
@parser.parse('*.pastoral')
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_class
|
180
|
+
assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
|
181
|
+
@parser.parse('.a.b')
|
182
|
+
assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
|
183
|
+
@parser.parse('.awesome')
|
184
|
+
assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
|
185
|
+
@parser.parse('foo.awesome')
|
186
|
+
assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
|
187
|
+
@parser.parse('foo .awesome')
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_not_so_simple_not
|
191
|
+
assert_xpath "//*[@id = 'p' and not(contains(concat(' ', @class, ' '), ' a '))]",
|
192
|
+
@parser.parse('#p:not(.a)')
|
193
|
+
assert_xpath "//p[contains(concat(' ', @class, ' '), ' a ') and not(contains(concat(' ', @class, ' '), ' b '))]",
|
194
|
+
@parser.parse('p.a:not(.b)')
|
195
|
+
assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', @class, ' '), ' b '))]",
|
196
|
+
@parser.parse("p[a='foo']:not(.b)")
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_ident
|
200
|
+
assert_xpath '//x', @parser.parse('x')
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_parse_space
|
204
|
+
assert_xpath '//x//y', @parser.parse('x y')
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_parse_descendant
|
208
|
+
assert_xpath '//x/y', @parser.parse('x > y')
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_parse_slash
|
212
|
+
## This is non standard CSS
|
213
|
+
assert_xpath '//x/y', @parser.parse('x/y')
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_parse_doubleslash
|
217
|
+
## This is non standard CSS
|
218
|
+
assert_xpath '//x//y', @parser.parse('x//y')
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_multi_path
|
222
|
+
assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y, y > z')
|
223
|
+
assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y,y > z')
|
224
|
+
###
|
225
|
+
# TODO: should we make this work?
|
226
|
+
# assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
|
227
|
+
end
|
228
|
+
|
229
|
+
def assert_xpath expecteds, asts
|
230
|
+
expecteds = [expecteds].flatten
|
231
|
+
expecteds.zip(asts).each do |expected, actual|
|
232
|
+
assert_equal expected, actual.to_xpath
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|