cocoa-xml 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +6 -0
- data/Manifest.txt +20 -0
- data/README.rdoc +105 -0
- data/Rakefile +23 -0
- data/lib/cocoa-xml.rb +48 -0
- data/lib/cocoa-xml/nodeset.rb +57 -0
- data/lib/cocoa-xml/nsxmldocument_extras.rb +48 -0
- data/lib/cocoa-xml/nsxmlnode_extras.rb +106 -0
- data/lib/cocoa-xml/version.rb +3 -0
- data/lib/nokogiri/css.rb +27 -0
- data/lib/nokogiri/css/generated_parser.rb +646 -0
- data/lib/nokogiri/css/generated_tokenizer.rb +143 -0
- data/lib/nokogiri/css/node.rb +100 -0
- data/lib/nokogiri/css/parser.rb +83 -0
- data/lib/nokogiri/css/parser.y +230 -0
- data/lib/nokogiri/css/syntax_error.rb +7 -0
- data/lib/nokogiri/css/tokenizer.rb +8 -0
- data/lib/nokogiri/css/tokenizer.rex +55 -0
- data/lib/nokogiri/css/xpath_visitor.rb +165 -0
- data/lib/nokogiri/syntax_error.rb +4 -0
- metadata +123 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module CSS
|
3
|
+
class GeneratedTokenizer < GeneratedParser
|
4
|
+
|
5
|
+
macro
|
6
|
+
nl \n|\r\n|\r|\f
|
7
|
+
w [\s\r\n\f]*
|
8
|
+
nonascii [^\0-\177]
|
9
|
+
num -?([0-9]+|[0-9]*\.[0-9]+)
|
10
|
+
unicode \\[0-9A-Fa-f]{1,6}(\r\n|[\s\n\r\t\f])?
|
11
|
+
|
12
|
+
escape {unicode}|\\[^\n\r\f0-9A-Fa-f]
|
13
|
+
nmchar [_A-Za-z0-9-]|{nonascii}|{escape}
|
14
|
+
nmstart [_A-Za-z]|{nonascii}|{escape}
|
15
|
+
ident [-@]?({nmstart})({nmchar})*
|
16
|
+
name ({nmchar})+
|
17
|
+
string1 "([^\n\r\f"]|{nl}|{nonascii}|{escape})*"
|
18
|
+
string2 '([^\n\r\f']|{nl}|{nonascii}|{escape})*'
|
19
|
+
string {string1}|{string2}
|
20
|
+
|
21
|
+
rule
|
22
|
+
|
23
|
+
# [:state] pattern [actions]
|
24
|
+
|
25
|
+
has\({w} { [:HAS, text] }
|
26
|
+
{ident}\({w} { [:FUNCTION, text] }
|
27
|
+
{ident} { [:IDENT, text] }
|
28
|
+
\#{name} { [:HASH, text] }
|
29
|
+
{w}~={w} { [:INCLUDES, text] }
|
30
|
+
{w}\|={w} { [:DASHMATCH, text] }
|
31
|
+
{w}\^={w} { [:PREFIXMATCH, text] }
|
32
|
+
{w}\$={w} { [:SUFFIXMATCH, text] }
|
33
|
+
{w}\*={w} { [:SUBSTRINGMATCH, text] }
|
34
|
+
{w}!={w} { [:NOT_EQUAL, text] }
|
35
|
+
{w}={w} { [:EQUAL, text] }
|
36
|
+
{w}\) { [:RPAREN, text] }
|
37
|
+
{w}\[{w} { [:LSQUARE, text] }
|
38
|
+
{w}\] { [:RSQUARE, text] }
|
39
|
+
{w}\+{w} { [:PLUS, text] }
|
40
|
+
{w}>{w} { [:GREATER, text] }
|
41
|
+
{w},{w} { [:COMMA, text] }
|
42
|
+
{w}~{w} { [:TILDE, text] }
|
43
|
+
\:not\({w} { [:NOT, text] }
|
44
|
+
{num} { [:NUMBER, text] }
|
45
|
+
{w}\/\/{w} { [:DOUBLESLASH, text] }
|
46
|
+
{w}\/{w} { [:SLASH, text] }
|
47
|
+
|
48
|
+
U\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})? {[:UNICODE_RANGE, text] }
|
49
|
+
|
50
|
+
[\s\t\r\n\f]+ { [:S, text] }
|
51
|
+
{string} { [:STRING, text] }
|
52
|
+
. { [text, text] }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module CSS
|
3
|
+
# @private
|
4
|
+
class XPathVisitor
|
5
|
+
def visit_function node
|
6
|
+
# note that nth-child and nth-last-child are preprocessed in css/node.rb.
|
7
|
+
msg = :"visit_function_#{node.value.first.gsub(/[(]/, '')}"
|
8
|
+
return self.send(msg, node) if self.respond_to?(msg)
|
9
|
+
|
10
|
+
case node.value.first
|
11
|
+
when /^text\(/
|
12
|
+
'child::text()'
|
13
|
+
when /^self\(/
|
14
|
+
"self::#{node.value[1]}"
|
15
|
+
when /^(eq|nth|nth-of-type|nth-child)\(/
|
16
|
+
if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :AN_PLUS_B
|
17
|
+
an_plus_b(node.value[1])
|
18
|
+
else
|
19
|
+
"position() = " + node.value[1]
|
20
|
+
end
|
21
|
+
when /^(first|first-of-type)\(/
|
22
|
+
"position() = 1"
|
23
|
+
when /^(last|last-of-type)\(/
|
24
|
+
"position() = last()"
|
25
|
+
when /^(nth-last-child|nth-last-of-type)\(/
|
26
|
+
"position() = last() - #{node.value[1]}"
|
27
|
+
when /^contains\(/
|
28
|
+
"contains(., #{node.value[1]})"
|
29
|
+
when /^gt\(/
|
30
|
+
"position() > #{node.value[1]}"
|
31
|
+
when /^only-child\(/
|
32
|
+
"last() = 1"
|
33
|
+
when /^comment\(/
|
34
|
+
"comment()"
|
35
|
+
when /^has\(/
|
36
|
+
node.value[1].accept(self)
|
37
|
+
else
|
38
|
+
args = ['.'] + node.value[1..-1]
|
39
|
+
"#{node.value.first}#{args.join(', ')})"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_not node
|
44
|
+
'not(' + node.value.first.accept(self) + ')'
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_preceding_selector node
|
48
|
+
node.value.last.accept(self) +
|
49
|
+
'[preceding-sibling::' +
|
50
|
+
node.value.first.accept(self) +
|
51
|
+
']'
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_id node
|
55
|
+
node.value.first =~ /^#(.*)$/
|
56
|
+
"@id = '#{$1}'"
|
57
|
+
end
|
58
|
+
|
59
|
+
def visit_attribute_condition node
|
60
|
+
attribute = if (node.value.first.type == :FUNCTION) or (node.value.first.value.first =~ /::/)
|
61
|
+
''
|
62
|
+
else
|
63
|
+
'@'
|
64
|
+
end
|
65
|
+
attribute += node.value.first.accept(self)
|
66
|
+
|
67
|
+
# Support non-standard css
|
68
|
+
attribute.gsub!(/^@@/, '@')
|
69
|
+
|
70
|
+
return attribute unless node.value.length == 3
|
71
|
+
|
72
|
+
value = node.value.last
|
73
|
+
value = "'#{value}'" if value !~ /^['"]/
|
74
|
+
|
75
|
+
case node.value[1]
|
76
|
+
when :equal
|
77
|
+
attribute + " = " + "#{value}"
|
78
|
+
when :not_equal
|
79
|
+
attribute + " != " + "#{value}"
|
80
|
+
when :substring_match
|
81
|
+
"contains(#{attribute}, #{value})"
|
82
|
+
when :prefix_match
|
83
|
+
"starts-with(#{attribute}, #{value})"
|
84
|
+
when :dash_match
|
85
|
+
"#{attribute} = #{value} or starts-with(#{attribute}, concat(#{value}, '-'))"
|
86
|
+
when :includes
|
87
|
+
"contains(concat(\" \", #{attribute}, \" \"),concat(\" \", #{value}, \" \"))"
|
88
|
+
when :suffix_match
|
89
|
+
"substring(#{attribute}, string-length(#{attribute}) - " +
|
90
|
+
"string-length(#{value}) + 1, string-length(#{value})) = #{value}"
|
91
|
+
else
|
92
|
+
attribute + " #{node.value[1]} " + "#{value}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def visit_pseudo_class node
|
97
|
+
if node.value.first.is_a?(Nokogiri::CSS::Node) and node.value.first.type == :FUNCTION
|
98
|
+
node.value.first.accept(self)
|
99
|
+
else
|
100
|
+
msg = :"visit_pseudo_class_#{node.value.first.gsub(/[(]/, '')}"
|
101
|
+
return self.send(msg, node) if self.respond_to?(msg)
|
102
|
+
|
103
|
+
case node.value.first
|
104
|
+
when "first" then "position() = 1"
|
105
|
+
when "last" then "position() = last()"
|
106
|
+
when "first-of-type" then "position() = 1"
|
107
|
+
when "last-of-type" then "position() = last()"
|
108
|
+
when "only-of-type" then "last() = 1"
|
109
|
+
when "empty" then "not(node())"
|
110
|
+
when "parent" then "node()"
|
111
|
+
when "root" then "not(parent::*)"
|
112
|
+
else
|
113
|
+
node.value.first + "(.)"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def visit_class_condition node
|
119
|
+
"contains(concat(' ', @class, ' '), ' #{node.value.first} ')"
|
120
|
+
end
|
121
|
+
|
122
|
+
{
|
123
|
+
'combinator' => ' and ',
|
124
|
+
'direct_adjacent_selector' => "/following-sibling::*[1]/self::",
|
125
|
+
'descendant_selector' => '//',
|
126
|
+
'child_selector' => '/',
|
127
|
+
}.each do |k,v|
|
128
|
+
class_eval %{
|
129
|
+
def visit_#{k} node
|
130
|
+
"\#{node.value.first.accept(self)}#{v}\#{node.value.last.accept(self)}"
|
131
|
+
end
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def visit_conditional_selector node
|
136
|
+
node.value.first.accept(self) + '[' +
|
137
|
+
node.value.last.accept(self) + ']'
|
138
|
+
end
|
139
|
+
|
140
|
+
def visit_element_name node
|
141
|
+
node.value.first
|
142
|
+
end
|
143
|
+
|
144
|
+
def accept node
|
145
|
+
node.accept(self)
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
def an_plus_b node
|
150
|
+
raise ArgumentError, "expected an+b node to contain 4 tokens, but is #{node.value.inspect}" unless node.value.size == 4
|
151
|
+
|
152
|
+
a = node.value[0].to_i
|
153
|
+
b = node.value[3].to_i
|
154
|
+
|
155
|
+
if (b == 0)
|
156
|
+
return "(position() mod #{a}) = 0"
|
157
|
+
else
|
158
|
+
compare = (a < 0) ? "<=" : ">="
|
159
|
+
return "(position() #{compare} #{b}) and (((position()-#{b}) mod #{a.abs}) = 0)"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cocoa-xml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Hoffman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-30 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rubyforge
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: gemcutter
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: hoe-yard
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.1.2
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: hoe
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.5.0
|
54
|
+
version:
|
55
|
+
description: |-
|
56
|
+
Cocoa-xml provides a more ruby like interface to Cocoa's NSXMLDocument
|
57
|
+
and classes that inherit from NSXMLNode. It provides access to XPath,
|
58
|
+
XQuery, and CSS selectors for searching documents.
|
59
|
+
email:
|
60
|
+
- cehoffman@gmail.com
|
61
|
+
executables: []
|
62
|
+
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files:
|
66
|
+
- Manifest.txt
|
67
|
+
- History.rdoc
|
68
|
+
files:
|
69
|
+
- History.rdoc
|
70
|
+
- Manifest.txt
|
71
|
+
- README.rdoc
|
72
|
+
- Rakefile
|
73
|
+
- lib/cocoa-xml.rb
|
74
|
+
- lib/cocoa-xml/nodeset.rb
|
75
|
+
- lib/cocoa-xml/version.rb
|
76
|
+
- lib/cocoa-xml/nsxmlnode_extras.rb
|
77
|
+
- lib/cocoa-xml/nsxmldocument_extras.rb
|
78
|
+
- lib/nokogiri/css.rb
|
79
|
+
- lib/nokogiri/syntax_error.rb
|
80
|
+
- lib/nokogiri/css/generated_parser.rb
|
81
|
+
- lib/nokogiri/css/generated_tokenizer.rb
|
82
|
+
- lib/nokogiri/css/node.rb
|
83
|
+
- lib/nokogiri/css/parser.rb
|
84
|
+
- lib/nokogiri/css/parser.y
|
85
|
+
- lib/nokogiri/css/syntax_error.rb
|
86
|
+
- lib/nokogiri/css/tokenizer.rb
|
87
|
+
- lib/nokogiri/css/tokenizer.rex
|
88
|
+
- lib/nokogiri/css/xpath_visitor.rb
|
89
|
+
has_rdoc: yard
|
90
|
+
homepage: http://github.com/cehoffman/cocoa-xml
|
91
|
+
licenses: []
|
92
|
+
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options:
|
95
|
+
- --no-private
|
96
|
+
- --title
|
97
|
+
- Cocoa-XML
|
98
|
+
- --markup
|
99
|
+
- rdoc
|
100
|
+
- --quiet
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
version:
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project: cocoa-xml
|
118
|
+
rubygems_version: 1.3.5
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Cocoa-xml provides a more ruby like interface to Cocoa's NSXMLDocument and classes that inherit from NSXMLNode
|
122
|
+
test_files: []
|
123
|
+
|