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,159 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by rex 1.0.1
|
4
|
+
# from lexical definition file "lib/nokogiri/css/tokenizer.rex".
|
5
|
+
#
|
6
|
+
|
7
|
+
module Nokogiri
|
8
|
+
module CSS
|
9
|
+
class GeneratedTokenizer < GeneratedParser
|
10
|
+
require 'strscan'
|
11
|
+
|
12
|
+
class ScanError < StandardError ; end
|
13
|
+
|
14
|
+
attr_reader :lineno
|
15
|
+
attr_reader :filename
|
16
|
+
|
17
|
+
def scan_setup ; end
|
18
|
+
|
19
|
+
def action &block
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
|
23
|
+
def scan_str( str )
|
24
|
+
scan_evaluate str
|
25
|
+
do_parse
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_file( filename )
|
29
|
+
@filename = filename
|
30
|
+
open(filename, "r") do |f|
|
31
|
+
scan_evaluate f.read
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def scan_file( filename )
|
36
|
+
load_file filename
|
37
|
+
do_parse
|
38
|
+
end
|
39
|
+
|
40
|
+
def next_token
|
41
|
+
@rex_tokens.shift
|
42
|
+
end
|
43
|
+
|
44
|
+
def scan_evaluate( str )
|
45
|
+
scan_setup
|
46
|
+
@rex_tokens = []
|
47
|
+
@lineno = 1
|
48
|
+
ss = StringScanner.new(str)
|
49
|
+
state = nil
|
50
|
+
until ss.eos?
|
51
|
+
text = ss.peek(1)
|
52
|
+
@lineno += 1 if text == "\n"
|
53
|
+
case state
|
54
|
+
when nil
|
55
|
+
case
|
56
|
+
when (text = ss.scan(/~=/i))
|
57
|
+
@rex_tokens.push action { [:INCLUDES, text] }
|
58
|
+
|
59
|
+
when (text = ss.scan(/\|=/i))
|
60
|
+
@rex_tokens.push action { [:DASHMATCH, text] }
|
61
|
+
|
62
|
+
when (text = ss.scan(/\^=/i))
|
63
|
+
@rex_tokens.push action { [:PREFIXMATCH, text] }
|
64
|
+
|
65
|
+
when (text = ss.scan(/\$=/i))
|
66
|
+
@rex_tokens.push action { [:SUFFIXMATCH, text] }
|
67
|
+
|
68
|
+
when (text = ss.scan(/\*=/i))
|
69
|
+
@rex_tokens.push action { [:SUBSTRINGMATCH, text] }
|
70
|
+
|
71
|
+
when (text = ss.scan(/!=/i))
|
72
|
+
@rex_tokens.push action { [:NOT_EQUAL, text] }
|
73
|
+
|
74
|
+
when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*\(\s*/i))
|
75
|
+
@rex_tokens.push action { [:FUNCTION, text] }
|
76
|
+
|
77
|
+
when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
|
78
|
+
@rex_tokens.push action { [:IDENT, text] }
|
79
|
+
|
80
|
+
when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
|
81
|
+
@rex_tokens.push action { [:IDENT, text] }
|
82
|
+
|
83
|
+
when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)/i))
|
84
|
+
@rex_tokens.push action { [:NUMBER, text] }
|
85
|
+
|
86
|
+
when (text = ss.scan(/\#([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])+/i))
|
87
|
+
@rex_tokens.push action { [:HASH, text] }
|
88
|
+
|
89
|
+
when (text = ss.scan(/[\s\r\n\f]*\+/i))
|
90
|
+
@rex_tokens.push action { [:PLUS, text] }
|
91
|
+
|
92
|
+
when (text = ss.scan(/[\s\r\n\f]*>/i))
|
93
|
+
@rex_tokens.push action { [:GREATER, text] }
|
94
|
+
|
95
|
+
when (text = ss.scan(/[\s\r\n\f]*,/i))
|
96
|
+
@rex_tokens.push action { [:COMMA, text] }
|
97
|
+
|
98
|
+
when (text = ss.scan(/[\s\r\n\f]*~/i))
|
99
|
+
@rex_tokens.push action { [:TILDE, text] }
|
100
|
+
|
101
|
+
when (text = ss.scan(/\:not\(/i))
|
102
|
+
@rex_tokens.push action { [:NOT, text] }
|
103
|
+
|
104
|
+
when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
|
105
|
+
@rex_tokens.push action { [:ATKEYWORD, text] }
|
106
|
+
|
107
|
+
when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)%/i))
|
108
|
+
@rex_tokens.push action { [:PERCENTAGE, text] }
|
109
|
+
|
110
|
+
when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
|
111
|
+
@rex_tokens.push action { [:DIMENSION, text] }
|
112
|
+
|
113
|
+
when (text = ss.scan(/<!--/i))
|
114
|
+
@rex_tokens.push action { [:CDO, text] }
|
115
|
+
|
116
|
+
when (text = ss.scan(/-->/i))
|
117
|
+
@rex_tokens.push action { [:CDC, text] }
|
118
|
+
|
119
|
+
when (text = ss.scan(/[\s\r\n\f]*\/\//i))
|
120
|
+
@rex_tokens.push action { [:DOUBLESLASH, text] }
|
121
|
+
|
122
|
+
when (text = ss.scan(/[\s\r\n\f]*\//i))
|
123
|
+
@rex_tokens.push action { [:SLASH, text] }
|
124
|
+
|
125
|
+
when (text = ss.scan(/U\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?/i))
|
126
|
+
@rex_tokens.push action {[:UNICODE_RANGE, text] }
|
127
|
+
|
128
|
+
when (text = ss.scan(/\/\*(.|[\r\n])*?\*\//i))
|
129
|
+
;
|
130
|
+
|
131
|
+
when (text = ss.scan(/[\s\t\r\n\f]+/i))
|
132
|
+
@rex_tokens.push action { [:S, text] }
|
133
|
+
|
134
|
+
when (text = ss.scan(/[\.*:\[\]=\)]/i))
|
135
|
+
@rex_tokens.push action { [text, text] }
|
136
|
+
|
137
|
+
when (text = ss.scan(/"([^\n\r\f"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*"|'([^\n\r\f']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*'/i))
|
138
|
+
@rex_tokens.push action { [:STRING, text] }
|
139
|
+
|
140
|
+
when (text = ss.scan(/\"([^\n\r\f\"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*|([^\n\r\f\']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
|
141
|
+
@rex_tokens.push action { [:INVALID, text] }
|
142
|
+
|
143
|
+
when (text = ss.scan(/./i))
|
144
|
+
@rex_tokens.push action { [text, text] }
|
145
|
+
|
146
|
+
else
|
147
|
+
text = ss.string[ss.pos .. -1]
|
148
|
+
raise ScanError, "can not match: '" + text + "'"
|
149
|
+
end # if
|
150
|
+
|
151
|
+
else
|
152
|
+
raise ScanError, "undefined state: '" + state.to_s + "'"
|
153
|
+
end # case state
|
154
|
+
end # until ss
|
155
|
+
end # def scan_evaluate
|
156
|
+
|
157
|
+
end # class
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module CSS
|
3
|
+
class Node
|
4
|
+
attr_accessor :type, :value
|
5
|
+
def initialize type, value
|
6
|
+
@type = type
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def accept visitor
|
11
|
+
visitor.send(:"visit_#{type.to_s.downcase}", self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xpath prefix = nil, visitor = nil
|
15
|
+
prefix ||= '//'
|
16
|
+
visitor ||= XPathVisitor.new
|
17
|
+
self.preprocess!
|
18
|
+
prefix + visitor.accept(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def preprocess!
|
22
|
+
### Deal with nth-child
|
23
|
+
matches = find_by_type(
|
24
|
+
[:CONDITIONAL_SELECTOR,
|
25
|
+
[:ELEMENT_NAME],
|
26
|
+
[:PSEUDO_CLASS,
|
27
|
+
[:FUNCTION]
|
28
|
+
]
|
29
|
+
]
|
30
|
+
)
|
31
|
+
matches.each do |match|
|
32
|
+
if match.value[1].value[0].value[0] =~ /^nth-child/
|
33
|
+
tag_name = match.value[0].value.first
|
34
|
+
match.value[0].value = ['*']
|
35
|
+
match.value[1] = Node.new(:COMBINATOR, [
|
36
|
+
match.value[1].value[0],
|
37
|
+
Node.new(:FUNCTION, ['self(', tag_name])
|
38
|
+
])
|
39
|
+
end
|
40
|
+
if match.value[1].value[0].value[0] =~ /^nth-last-child/
|
41
|
+
tag_name = match.value[0].value.first
|
42
|
+
match.value[0].value = ['*']
|
43
|
+
match.value[1] = Node.new(:COMBINATOR, [
|
44
|
+
match.value[1].value[0],
|
45
|
+
Node.new(:FUNCTION, ['self(', tag_name])
|
46
|
+
])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
### Deal with first-child, last-child
|
51
|
+
matches = find_by_type(
|
52
|
+
[:CONDITIONAL_SELECTOR,
|
53
|
+
[:ELEMENT_NAME], [:PSEUDO_CLASS]
|
54
|
+
])
|
55
|
+
matches.each do |match|
|
56
|
+
if ['first-child', 'last-child'].include?(match.value[1].value.first)
|
57
|
+
which = match.value[1].value.first.gsub(/-\w*$/, '')
|
58
|
+
tag_name = match.value[0].value.first
|
59
|
+
match.value[0].value = ['*']
|
60
|
+
match.value[1] = Node.new(:COMBINATOR, [
|
61
|
+
Node.new(:FUNCTION, ["#{which}("]),
|
62
|
+
Node.new(:FUNCTION, ['self(', tag_name])
|
63
|
+
])
|
64
|
+
elsif 'only-child' == match.value[1].value.first
|
65
|
+
tag_name = match.value[0].value.first
|
66
|
+
match.value[0].value = ['*']
|
67
|
+
match.value[1] = Node.new(:COMBINATOR, [
|
68
|
+
Node.new(:FUNCTION, ["#{match.value[1].value.first}("]),
|
69
|
+
Node.new(:FUNCTION, ['self(', tag_name])
|
70
|
+
])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_by_type(types)
|
78
|
+
matches = []
|
79
|
+
matches << self if to_type == types
|
80
|
+
@value.each do |v|
|
81
|
+
matches += v.find_by_type(types) if v.respond_to?(:find_by_type)
|
82
|
+
end
|
83
|
+
matches
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_type
|
87
|
+
[@type] + @value.map { |n|
|
88
|
+
n.to_type if n.respond_to?(:to_type)
|
89
|
+
}.compact
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_a
|
93
|
+
[@type] + @value.map { |n| n.respond_to?(:to_a) ? n.to_a : [n] }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module CSS
|
5
|
+
class Parser < GeneratedTokenizer
|
6
|
+
@cache_on = true
|
7
|
+
@cache = {}
|
8
|
+
@mutex = Mutex.new
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :cache_on
|
12
|
+
alias :cache_on? :cache_on
|
13
|
+
alias :set_cache :cache_on=
|
14
|
+
|
15
|
+
def parse string
|
16
|
+
new.parse(string)
|
17
|
+
end
|
18
|
+
|
19
|
+
def xpath_for string, options={}
|
20
|
+
new.xpath_for(string, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def [] string
|
24
|
+
return unless @cache_on
|
25
|
+
@mutex.synchronize { @cache[string] }
|
26
|
+
end
|
27
|
+
|
28
|
+
def []= string, value
|
29
|
+
return value unless @cache_on
|
30
|
+
@mutex.synchronize { @cache[string] = value }
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear_cache
|
34
|
+
@mutex.synchronize { @cache = {} }
|
35
|
+
end
|
36
|
+
|
37
|
+
def without_cache &block
|
38
|
+
tmp = @cache_on
|
39
|
+
@cache_on = false
|
40
|
+
block.call
|
41
|
+
@cache_on = tmp
|
42
|
+
end
|
43
|
+
end
|
44
|
+
alias :parse :scan_str
|
45
|
+
|
46
|
+
def xpath_for string, options={}
|
47
|
+
v = self.class[string]
|
48
|
+
return v if v
|
49
|
+
|
50
|
+
prefix = options[:prefix] || nil
|
51
|
+
visitor = options[:visitor] || nil
|
52
|
+
args = [prefix, visitor]
|
53
|
+
self.class[string] = parse(string).map { |ast|
|
54
|
+
ast.to_xpath(prefix, visitor)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_error error_token_id, error_value, value_stack
|
59
|
+
after = value_stack.compact.last
|
60
|
+
raise SyntaxError.new("unexpected '#{error_value}' after '#{after}'")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
class Nokogiri::CSS::GeneratedParser
|
2
|
+
|
3
|
+
token FUNCTION INCLUDES DASHMATCH LBRACE HASH PLUS GREATER S STRING IDENT
|
4
|
+
token COMMA URI CDO CDC NUMBER PERCENTAGE LENGTH EMS EXS ANGLE TIME FREQ
|
5
|
+
token IMPORTANT_SYM IMPORT_SYM MEDIA_SYM PAGE_SYM CHARSET_SYM DIMENSION
|
6
|
+
token PREFIXMATCH SUFFIXMATCH SUBSTRINGMATCH TILDE NOT_EQUAL SLASH DOUBLESLASH
|
7
|
+
token NOT
|
8
|
+
|
9
|
+
rule
|
10
|
+
selector
|
11
|
+
: selector COMMA s_0toN simple_selector_1toN {
|
12
|
+
result = [val.first, val.last].flatten
|
13
|
+
}
|
14
|
+
| simple_selector_1toN { result = val.flatten }
|
15
|
+
;
|
16
|
+
combinator
|
17
|
+
: PLUS s_0toN { result = :DIRECT_ADJACENT_SELECTOR }
|
18
|
+
| GREATER s_0toN { result = :CHILD_SELECTOR }
|
19
|
+
| TILDE s_0toN { result = :PRECEDING_SELECTOR }
|
20
|
+
| S { result = :DESCENDANT_SELECTOR }
|
21
|
+
| DOUBLESLASH s_0toN { result = :DESCENDANT_SELECTOR }
|
22
|
+
| SLASH s_0toN { result = :CHILD_SELECTOR }
|
23
|
+
;
|
24
|
+
simple_selector
|
25
|
+
: element_name hcap_0toN {
|
26
|
+
result = if val[1].nil?
|
27
|
+
val.first
|
28
|
+
else
|
29
|
+
Node.new(:CONDITIONAL_SELECTOR, [val.first, val[1]])
|
30
|
+
end
|
31
|
+
}
|
32
|
+
| element_name hcap_1toN negation {
|
33
|
+
result = Node.new(:CONDITIONAL_SELECTOR,
|
34
|
+
[
|
35
|
+
val.first,
|
36
|
+
Node.new(:COMBINATOR, [val[1], val.last])
|
37
|
+
]
|
38
|
+
)
|
39
|
+
}
|
40
|
+
| element_name negation {
|
41
|
+
result = Node.new(:CONDITIONAL_SELECTOR, val)
|
42
|
+
}
|
43
|
+
| function
|
44
|
+
| function attrib {
|
45
|
+
result = Node.new(:CONDITIONAL_SELECTOR, val)
|
46
|
+
}
|
47
|
+
| hcap_1toN negation {
|
48
|
+
result = Node.new(:CONDITIONAL_SELECTOR,
|
49
|
+
[
|
50
|
+
Node.new(:ELEMENT_NAME, ['*']),
|
51
|
+
Node.new(:COMBINATOR, val)
|
52
|
+
]
|
53
|
+
)
|
54
|
+
}
|
55
|
+
| hcap_1toN {
|
56
|
+
result = Node.new(:CONDITIONAL_SELECTOR,
|
57
|
+
[Node.new(:ELEMENT_NAME, ['*']), val.first]
|
58
|
+
)
|
59
|
+
}
|
60
|
+
;
|
61
|
+
simple_selector_1toN
|
62
|
+
: simple_selector combinator simple_selector_1toN {
|
63
|
+
result = Node.new(val[1], [val.first, val.last])
|
64
|
+
}
|
65
|
+
| simple_selector
|
66
|
+
;
|
67
|
+
class
|
68
|
+
: '.' IDENT { result = Node.new(:CLASS_CONDITION, [val[1]]) }
|
69
|
+
;
|
70
|
+
element_name
|
71
|
+
: IDENT { result = Node.new(:ELEMENT_NAME, val) }
|
72
|
+
| '*' { result = Node.new(:ELEMENT_NAME, val) }
|
73
|
+
;
|
74
|
+
attrib
|
75
|
+
: '[' s_0toN IDENT s_0toN attrib_val_0or1 ']' {
|
76
|
+
result = Node.new(:ATTRIBUTE_CONDITION,
|
77
|
+
[Node.new(:ELEMENT_NAME, [val[2]])] + (val[4] || [])
|
78
|
+
)
|
79
|
+
}
|
80
|
+
| '[' s_0toN function s_0toN attrib_val_0or1 ']' {
|
81
|
+
result = Node.new(:ATTRIBUTE_CONDITION,
|
82
|
+
[val[2]] + (val[4] || [])
|
83
|
+
)
|
84
|
+
}
|
85
|
+
| '[' s_0toN NUMBER s_0toN ']' {
|
86
|
+
# Non standard, but hpricot supports it.
|
87
|
+
result = Node.new(:PSEUDO_CLASS,
|
88
|
+
[Node.new(:FUNCTION, ['nth-child(', val[2]])]
|
89
|
+
)
|
90
|
+
}
|
91
|
+
;
|
92
|
+
function
|
93
|
+
: FUNCTION ')' {
|
94
|
+
result = Node.new(:FUNCTION, [val.first.strip])
|
95
|
+
}
|
96
|
+
| FUNCTION expr ')' {
|
97
|
+
result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
|
98
|
+
}
|
99
|
+
| FUNCTION an_plus_b ')' {
|
100
|
+
result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
|
101
|
+
}
|
102
|
+
| NOT expr ')' {
|
103
|
+
result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
|
104
|
+
}
|
105
|
+
;
|
106
|
+
expr
|
107
|
+
: NUMBER COMMA s_0toN expr { result = [val.first, val.last] }
|
108
|
+
| STRING COMMA s_0toN expr { result = [val.first, val.last] }
|
109
|
+
| NUMBER
|
110
|
+
| STRING
|
111
|
+
;
|
112
|
+
an_plus_b
|
113
|
+
: NUMBER IDENT PLUS NUMBER # 5n+3 -5n+3
|
114
|
+
{
|
115
|
+
if val[1] == 'n'
|
116
|
+
result = Node.new(:AN_PLUS_B, val)
|
117
|
+
else
|
118
|
+
raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
|
119
|
+
end
|
120
|
+
}
|
121
|
+
| IDENT PLUS NUMBER { # n+3, -n+3
|
122
|
+
if val[0] == 'n'
|
123
|
+
val.unshift("1")
|
124
|
+
result = Node.new(:AN_PLUS_B, val)
|
125
|
+
elsif val[0] == '-n'
|
126
|
+
val[0] = 'n'
|
127
|
+
val.unshift("-1")
|
128
|
+
result = Node.new(:AN_PLUS_B, val)
|
129
|
+
else
|
130
|
+
raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
|
131
|
+
end
|
132
|
+
}
|
133
|
+
| NUMBER IDENT # 5n, -5n
|
134
|
+
{
|
135
|
+
if val[1] == 'n'
|
136
|
+
val << "+"
|
137
|
+
val << "0"
|
138
|
+
result = Node.new(:AN_PLUS_B, val)
|
139
|
+
else
|
140
|
+
raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
|
141
|
+
end
|
142
|
+
}
|
143
|
+
| IDENT # even, odd
|
144
|
+
{
|
145
|
+
if val[0] == 'even'
|
146
|
+
val = ["2","n","+","0"]
|
147
|
+
result = Node.new(:AN_PLUS_B, val)
|
148
|
+
elsif val[0] == 'odd'
|
149
|
+
val = ["2","n","+","1"]
|
150
|
+
result = Node.new(:AN_PLUS_B, val)
|
151
|
+
else
|
152
|
+
raise Racc::ParseError, "parse error on IDENT '#{val[0]}'"
|
153
|
+
end
|
154
|
+
}
|
155
|
+
;
|
156
|
+
pseudo
|
157
|
+
: ':' function {
|
158
|
+
result = Node.new(:PSEUDO_CLASS, [val[1]])
|
159
|
+
}
|
160
|
+
| ':' IDENT { result = Node.new(:PSEUDO_CLASS, [val[1]]) }
|
161
|
+
;
|
162
|
+
hcap_0toN
|
163
|
+
: hcap_1toN
|
164
|
+
|
|
165
|
+
;
|
166
|
+
hcap_1toN
|
167
|
+
: attribute_id hcap_1toN {
|
168
|
+
result = Node.new(:COMBINATOR, val)
|
169
|
+
}
|
170
|
+
| class hcap_1toN {
|
171
|
+
result = Node.new(:COMBINATOR, val)
|
172
|
+
}
|
173
|
+
| attrib hcap_1toN {
|
174
|
+
result = Node.new(:COMBINATOR, val)
|
175
|
+
}
|
176
|
+
| pseudo hcap_1toN {
|
177
|
+
result = Node.new(:COMBINATOR, val)
|
178
|
+
}
|
179
|
+
| attribute_id
|
180
|
+
| class
|
181
|
+
| attrib
|
182
|
+
| pseudo
|
183
|
+
;
|
184
|
+
attribute_id
|
185
|
+
: HASH { result = Node.new(:ID, val) }
|
186
|
+
;
|
187
|
+
attrib_val_0or1
|
188
|
+
: eql_incl_dash s_0toN IDENT s_0toN { result = [val.first, val[2]] }
|
189
|
+
| eql_incl_dash s_0toN STRING s_0toN { result = [val.first, val[2]] }
|
190
|
+
|
|
191
|
+
;
|
192
|
+
eql_incl_dash
|
193
|
+
: '='
|
194
|
+
| PREFIXMATCH
|
195
|
+
| SUFFIXMATCH
|
196
|
+
| SUBSTRINGMATCH
|
197
|
+
| NOT_EQUAL
|
198
|
+
| INCLUDES
|
199
|
+
| DASHMATCH
|
200
|
+
;
|
201
|
+
negation
|
202
|
+
: NOT s_0toN negation_arg s_0toN ')' {
|
203
|
+
result = Node.new(:NOT, [val[2]])
|
204
|
+
}
|
205
|
+
;
|
206
|
+
negation_arg
|
207
|
+
: hcap_1toN
|
208
|
+
;
|
209
|
+
s_0toN
|
210
|
+
: S s_0toN
|
211
|
+
|
|
212
|
+
;
|
213
|
+
end
|
214
|
+
|
215
|
+
---- header
|
216
|
+
|