rubysl-rexml 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/rexml/attlistdecl.rb +62 -0
  9. data/lib/rexml/attribute.rb +185 -0
  10. data/lib/rexml/cdata.rb +67 -0
  11. data/lib/rexml/child.rb +96 -0
  12. data/lib/rexml/comment.rb +80 -0
  13. data/lib/rexml/doctype.rb +271 -0
  14. data/lib/rexml/document.rb +230 -0
  15. data/lib/rexml/dtd/attlistdecl.rb +10 -0
  16. data/lib/rexml/dtd/dtd.rb +51 -0
  17. data/lib/rexml/dtd/elementdecl.rb +17 -0
  18. data/lib/rexml/dtd/entitydecl.rb +56 -0
  19. data/lib/rexml/dtd/notationdecl.rb +39 -0
  20. data/lib/rexml/element.rb +1227 -0
  21. data/lib/rexml/encoding.rb +71 -0
  22. data/lib/rexml/encodings/CP-1252.rb +103 -0
  23. data/lib/rexml/encodings/EUC-JP.rb +35 -0
  24. data/lib/rexml/encodings/ICONV.rb +22 -0
  25. data/lib/rexml/encodings/ISO-8859-1.rb +7 -0
  26. data/lib/rexml/encodings/ISO-8859-15.rb +72 -0
  27. data/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
  28. data/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
  29. data/lib/rexml/encodings/UNILE.rb +34 -0
  30. data/lib/rexml/encodings/US-ASCII.rb +30 -0
  31. data/lib/rexml/encodings/UTF-16.rb +35 -0
  32. data/lib/rexml/encodings/UTF-8.rb +18 -0
  33. data/lib/rexml/entity.rb +166 -0
  34. data/lib/rexml/formatters/default.rb +109 -0
  35. data/lib/rexml/formatters/pretty.rb +138 -0
  36. data/lib/rexml/formatters/transitive.rb +56 -0
  37. data/lib/rexml/functions.rb +382 -0
  38. data/lib/rexml/instruction.rb +70 -0
  39. data/lib/rexml/light/node.rb +196 -0
  40. data/lib/rexml/namespace.rb +47 -0
  41. data/lib/rexml/node.rb +75 -0
  42. data/lib/rexml/output.rb +24 -0
  43. data/lib/rexml/parent.rb +166 -0
  44. data/lib/rexml/parseexception.rb +51 -0
  45. data/lib/rexml/parsers/baseparser.rb +503 -0
  46. data/lib/rexml/parsers/lightparser.rb +60 -0
  47. data/lib/rexml/parsers/pullparser.rb +196 -0
  48. data/lib/rexml/parsers/sax2parser.rb +238 -0
  49. data/lib/rexml/parsers/streamparser.rb +46 -0
  50. data/lib/rexml/parsers/treeparser.rb +97 -0
  51. data/lib/rexml/parsers/ultralightparser.rb +56 -0
  52. data/lib/rexml/parsers/xpathparser.rb +698 -0
  53. data/lib/rexml/quickpath.rb +266 -0
  54. data/lib/rexml/rexml.rb +32 -0
  55. data/lib/rexml/sax2listener.rb +97 -0
  56. data/lib/rexml/source.rb +251 -0
  57. data/lib/rexml/streamlistener.rb +92 -0
  58. data/lib/rexml/syncenumerator.rb +33 -0
  59. data/lib/rexml/text.rb +344 -0
  60. data/lib/rexml/undefinednamespaceexception.rb +8 -0
  61. data/lib/rexml/validation/relaxng.rb +559 -0
  62. data/lib/rexml/validation/validation.rb +155 -0
  63. data/lib/rexml/validation/validationexception.rb +9 -0
  64. data/lib/rexml/xmldecl.rb +119 -0
  65. data/lib/rexml/xmltokens.rb +18 -0
  66. data/lib/rexml/xpath.rb +66 -0
  67. data/lib/rexml/xpath_parser.rb +792 -0
  68. data/lib/rubysl/rexml.rb +1 -0
  69. data/lib/rubysl/rexml/version.rb +5 -0
  70. data/rubysl-rexml.gemspec +23 -0
  71. data/spec/attribute/clone_spec.rb +10 -0
  72. data/spec/attribute/element_spec.rb +22 -0
  73. data/spec/attribute/equal_value_spec.rb +17 -0
  74. data/spec/attribute/hash_spec.rb +12 -0
  75. data/spec/attribute/initialize_spec.rb +28 -0
  76. data/spec/attribute/inspect_spec.rb +19 -0
  77. data/spec/attribute/namespace_spec.rb +23 -0
  78. data/spec/attribute/node_type_spec.rb +9 -0
  79. data/spec/attribute/prefix_spec.rb +17 -0
  80. data/spec/attribute/remove_spec.rb +19 -0
  81. data/spec/attribute/to_s_spec.rb +13 -0
  82. data/spec/attribute/to_string_spec.rb +14 -0
  83. data/spec/attribute/value_spec.rb +14 -0
  84. data/spec/attribute/write_spec.rb +22 -0
  85. data/spec/attribute/xpath_spec.rb +19 -0
  86. data/spec/attributes/add_spec.rb +6 -0
  87. data/spec/attributes/append_spec.rb +6 -0
  88. data/spec/attributes/delete_all_spec.rb +30 -0
  89. data/spec/attributes/delete_spec.rb +26 -0
  90. data/spec/attributes/each_attribute_spec.rb +24 -0
  91. data/spec/attributes/each_spec.rb +24 -0
  92. data/spec/attributes/element_reference_spec.rb +18 -0
  93. data/spec/attributes/element_set_spec.rb +25 -0
  94. data/spec/attributes/get_attribute_ns_spec.rb +13 -0
  95. data/spec/attributes/get_attribute_spec.rb +28 -0
  96. data/spec/attributes/initialize_spec.rb +18 -0
  97. data/spec/attributes/length_spec.rb +6 -0
  98. data/spec/attributes/namespaces_spec.rb +5 -0
  99. data/spec/attributes/prefixes_spec.rb +23 -0
  100. data/spec/attributes/shared/add.rb +17 -0
  101. data/spec/attributes/shared/length.rb +12 -0
  102. data/spec/attributes/size_spec.rb +6 -0
  103. data/spec/attributes/to_a_spec.rb +20 -0
  104. data/spec/cdata/clone_spec.rb +9 -0
  105. data/spec/cdata/initialize_spec.rb +24 -0
  106. data/spec/cdata/shared/to_s.rb +11 -0
  107. data/spec/cdata/to_s_spec.rb +6 -0
  108. data/spec/cdata/value_spec.rb +6 -0
  109. data/spec/document/add_element_spec.rb +30 -0
  110. data/spec/document/add_spec.rb +60 -0
  111. data/spec/document/clone_spec.rb +19 -0
  112. data/spec/document/doctype_spec.rb +14 -0
  113. data/spec/document/encoding_spec.rb +21 -0
  114. data/spec/document/expanded_name_spec.rb +15 -0
  115. data/spec/document/new_spec.rb +37 -0
  116. data/spec/document/node_type_spec.rb +7 -0
  117. data/spec/document/root_spec.rb +11 -0
  118. data/spec/document/stand_alone_spec.rb +18 -0
  119. data/spec/document/version_spec.rb +13 -0
  120. data/spec/document/write_spec.rb +38 -0
  121. data/spec/document/xml_decl_spec.rb +14 -0
  122. data/spec/element/add_attribute_spec.rb +40 -0
  123. data/spec/element/add_attributes_spec.rb +21 -0
  124. data/spec/element/add_element_spec.rb +38 -0
  125. data/spec/element/add_namespace_spec.rb +23 -0
  126. data/spec/element/add_text_spec.rb +23 -0
  127. data/spec/element/attribute_spec.rb +16 -0
  128. data/spec/element/attributes_spec.rb +18 -0
  129. data/spec/element/cdatas_spec.rb +23 -0
  130. data/spec/element/clone_spec.rb +28 -0
  131. data/spec/element/comments_spec.rb +20 -0
  132. data/spec/element/delete_attribute_spec.rb +38 -0
  133. data/spec/element/delete_element_spec.rb +50 -0
  134. data/spec/element/delete_namespace_spec.rb +24 -0
  135. data/spec/element/document_spec.rb +17 -0
  136. data/spec/element/each_element_with_attribute_spec.rb +34 -0
  137. data/spec/element/each_element_with_text_spec.rb +30 -0
  138. data/spec/element/get_text_spec.rb +17 -0
  139. data/spec/element/has_attributes_spec.rb +16 -0
  140. data/spec/element/has_elements_spec.rb +17 -0
  141. data/spec/element/has_text_spec.rb +15 -0
  142. data/spec/element/inspect_spec.rb +26 -0
  143. data/spec/element/instructions_spec.rb +20 -0
  144. data/spec/element/namespace_spec.rb +26 -0
  145. data/spec/element/namespaces_spec.rb +31 -0
  146. data/spec/element/new_spec.rb +34 -0
  147. data/spec/element/next_element_spec.rb +18 -0
  148. data/spec/element/node_type_spec.rb +7 -0
  149. data/spec/element/prefixes_spec.rb +22 -0
  150. data/spec/element/previous_element_spec.rb +19 -0
  151. data/spec/element/raw_spec.rb +23 -0
  152. data/spec/element/root_spec.rb +27 -0
  153. data/spec/element/text_spec.rb +45 -0
  154. data/spec/element/texts_spec.rb +15 -0
  155. data/spec/element/whitespace_spec.rb +22 -0
  156. data/spec/node/each_recursive_spec.rb +20 -0
  157. data/spec/node/find_first_recursive_spec.rb +24 -0
  158. data/spec/node/index_in_parent_spec.rb +14 -0
  159. data/spec/node/next_sibling_node_spec.rb +20 -0
  160. data/spec/node/parent_spec.rb +20 -0
  161. data/spec/node/previous_sibling_node_spec.rb +20 -0
  162. data/spec/shared/each_element.rb +35 -0
  163. data/spec/shared/elements_to_a.rb +35 -0
  164. data/spec/text/append_spec.rb +9 -0
  165. data/spec/text/clone_spec.rb +9 -0
  166. data/spec/text/comparison_spec.rb +24 -0
  167. data/spec/text/empty_spec.rb +11 -0
  168. data/spec/text/indent_text_spec.rb +23 -0
  169. data/spec/text/inspect_spec.rb +7 -0
  170. data/spec/text/new_spec.rb +48 -0
  171. data/spec/text/node_type_spec.rb +7 -0
  172. data/spec/text/normalize_spec.rb +7 -0
  173. data/spec/text/read_with_substitution_spec.rb +12 -0
  174. data/spec/text/to_s_spec.rb +17 -0
  175. data/spec/text/unnormalize_spec.rb +7 -0
  176. data/spec/text/value_spec.rb +36 -0
  177. data/spec/text/wrap_spec.rb +20 -0
  178. data/spec/text/write_with_substitution_spec.rb +32 -0
  179. metadata +385 -0
@@ -0,0 +1,46 @@
1
+ module REXML
2
+ module Parsers
3
+ class StreamParser
4
+ def initialize source, listener
5
+ @listener = listener
6
+ @parser = BaseParser.new( source )
7
+ end
8
+
9
+ def add_listener( listener )
10
+ @parser.add_listener( listener )
11
+ end
12
+
13
+ def parse
14
+ # entity string
15
+ while true
16
+ event = @parser.pull
17
+ case event[0]
18
+ when :end_document
19
+ return
20
+ when :start_element
21
+ attrs = event[2].each do |n, v|
22
+ event[2][n] = @parser.unnormalize( v )
23
+ end
24
+ @listener.tag_start( event[1], attrs )
25
+ when :end_element
26
+ @listener.tag_end( event[1] )
27
+ when :text
28
+ normalized = @parser.unnormalize( event[1] )
29
+ @listener.text( normalized )
30
+ when :processing_instruction
31
+ @listener.instruction( *event[1,2] )
32
+ when :start_doctype
33
+ @listener.doctype( *event[1..-1] )
34
+ when :end_doctype
35
+ # FIXME: remove this condition for milestone:3.2
36
+ @listener.doctype_end if @listener.respond_to? :doctype_end
37
+ when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
38
+ @listener.send( event[0].to_s, *event[1..-1] )
39
+ when :entitydecl, :notationdecl
40
+ @listener.send( event[0].to_s, event[1..-1] )
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,97 @@
1
+ require 'rexml/validation/validationexception'
2
+ require 'rexml/undefinednamespaceexception'
3
+
4
+ module REXML
5
+ module Parsers
6
+ class TreeParser
7
+ def initialize( source, build_context = Document.new )
8
+ @build_context = build_context
9
+ @parser = Parsers::BaseParser.new( source )
10
+ end
11
+
12
+ def add_listener( listener )
13
+ @parser.add_listener( listener )
14
+ end
15
+
16
+ def parse
17
+ tag_stack = []
18
+ in_doctype = false
19
+ entities = nil
20
+ begin
21
+ while true
22
+ event = @parser.pull
23
+ #STDERR.puts "TREEPARSER GOT #{event.inspect}"
24
+ case event[0]
25
+ when :end_document
26
+ unless tag_stack.empty?
27
+ #raise ParseException.new("No close tag for #{tag_stack.inspect}")
28
+ raise ParseException.new("No close tag for #{@build_context.xpath}")
29
+ end
30
+ return
31
+ when :start_element
32
+ tag_stack.push(event[1])
33
+ el = @build_context = @build_context.add_element( event[1], event[2] )
34
+ when :end_element
35
+ tag_stack.pop
36
+ @build_context = @build_context.parent
37
+ when :text
38
+ if not in_doctype
39
+ if @build_context[-1].instance_of? Text
40
+ @build_context[-1] << event[1]
41
+ else
42
+ @build_context.add(
43
+ Text.new(event[1], @build_context.whitespace, nil, true)
44
+ ) unless (
45
+ @build_context.ignore_whitespace_nodes and
46
+ event[1].strip.size==0
47
+ )
48
+ end
49
+ end
50
+ when :comment
51
+ c = Comment.new( event[1] )
52
+ @build_context.add( c )
53
+ when :cdata
54
+ c = CData.new( event[1] )
55
+ @build_context.add( c )
56
+ when :processing_instruction
57
+ @build_context.add( Instruction.new( event[1], event[2] ) )
58
+ when :end_doctype
59
+ in_doctype = false
60
+ entities.each { |k,v| entities[k] = @build_context.entities[k].value }
61
+ @build_context = @build_context.parent
62
+ when :start_doctype
63
+ doctype = DocType.new( event[1..-1], @build_context )
64
+ @build_context = doctype
65
+ entities = {}
66
+ in_doctype = true
67
+ when :attlistdecl
68
+ n = AttlistDecl.new( event[1..-1] )
69
+ @build_context.add( n )
70
+ when :externalentity
71
+ n = ExternalEntity.new( event[1] )
72
+ @build_context.add( n )
73
+ when :elementdecl
74
+ n = ElementDecl.new( event[1] )
75
+ @build_context.add(n)
76
+ when :entitydecl
77
+ entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
78
+ @build_context.add(Entity.new(event))
79
+ when :notationdecl
80
+ n = NotationDecl.new( *event[1..-1] )
81
+ @build_context.add( n )
82
+ when :xmldecl
83
+ x = XMLDecl.new( event[1], event[2], event[3] )
84
+ @build_context.add( x )
85
+ end
86
+ end
87
+ rescue REXML::Validation::ValidationException
88
+ raise
89
+ rescue REXML::UndefinedNamespaceException
90
+ raise
91
+ rescue
92
+ raise ParseException.new( $!.message, @parser.source, @parser, $! )
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,56 @@
1
+ require 'rexml/parsers/streamparser'
2
+ require 'rexml/parsers/baseparser'
3
+
4
+ module REXML
5
+ module Parsers
6
+ class UltraLightParser
7
+ def initialize stream
8
+ @stream = stream
9
+ @parser = REXML::Parsers::BaseParser.new( stream )
10
+ end
11
+
12
+ def add_listener( listener )
13
+ @parser.add_listener( listener )
14
+ end
15
+
16
+ def rewind
17
+ @stream.rewind
18
+ @parser.stream = @stream
19
+ end
20
+
21
+ def parse
22
+ root = context = []
23
+ while true
24
+ event = @parser.pull
25
+ case event[0]
26
+ when :end_document
27
+ break
28
+ when :end_doctype
29
+ context = context[1]
30
+ when :start_element, :doctype
31
+ context << event
32
+ event[1,0] = [context]
33
+ context = event
34
+ when :end_element
35
+ context = context[1]
36
+ else
37
+ context << event
38
+ end
39
+ end
40
+ root
41
+ end
42
+ end
43
+
44
+ # An element is an array. The array contains:
45
+ # 0 The parent element
46
+ # 1 The tag name
47
+ # 2 A hash of attributes
48
+ # 3..-1 The child elements
49
+ # An element is an array of size > 3
50
+ # Text is a String
51
+ # PIs are [ :processing_instruction, target, data ]
52
+ # Comments are [ :comment, data ]
53
+ # DocTypes are DocType structs
54
+ # The root is an array with XMLDecls, Text, DocType, Array, Text
55
+ end
56
+ end
@@ -0,0 +1,698 @@
1
+ require 'rexml/namespace'
2
+ require 'rexml/xmltokens'
3
+
4
+ module REXML
5
+ module Parsers
6
+ # You don't want to use this class. Really. Use XPath, which is a wrapper
7
+ # for this class. Believe me. You don't want to poke around in here.
8
+ # There is strange, dark magic at work in this code. Beware. Go back! Go
9
+ # back while you still can!
10
+ class XPathParser
11
+ include XMLTokens
12
+ LITERAL = /^'([^']*)'|^"([^"]*)"/u
13
+
14
+ def namespaces=( namespaces )
15
+ Functions::namespace_context = namespaces
16
+ @namespaces = namespaces
17
+ end
18
+
19
+ def parse path
20
+ path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
21
+ path.gsub!( /\s+([\]\)])/, '\1' )
22
+ parsed = []
23
+ path = OrExpr(path, parsed)
24
+ parsed
25
+ end
26
+
27
+ def predicate path
28
+ parsed = []
29
+ Predicate( "[#{path}]", parsed )
30
+ parsed
31
+ end
32
+
33
+ def abbreviate( path )
34
+ path = path.kind_of?(String) ? parse( path ) : path
35
+ string = ""
36
+ document = false
37
+ while path.size > 0
38
+ op = path.shift
39
+ case op
40
+ when :node
41
+ when :attribute
42
+ string << "/" if string.size > 0
43
+ string << "@"
44
+ when :child
45
+ string << "/" if string.size > 0
46
+ when :descendant_or_self
47
+ string << "/"
48
+ when :self
49
+ string << "."
50
+ when :parent
51
+ string << ".."
52
+ when :any
53
+ string << "*"
54
+ when :text
55
+ string << "text()"
56
+ when :following, :following_sibling,
57
+ :ancestor, :ancestor_or_self, :descendant,
58
+ :namespace, :preceding, :preceding_sibling
59
+ string << "/" unless string.size == 0
60
+ string << op.to_s.tr("_", "-")
61
+ string << "::"
62
+ when :qname
63
+ prefix = path.shift
64
+ name = path.shift
65
+ string << prefix+":" if prefix.size > 0
66
+ string << name
67
+ when :predicate
68
+ string << '['
69
+ string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
70
+ string << ']'
71
+ when :document
72
+ document = true
73
+ when :function
74
+ string << path.shift
75
+ string << "( "
76
+ string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
77
+ string << " )"
78
+ when :literal
79
+ string << %Q{ "#{path.shift}" }
80
+ else
81
+ string << "/" unless string.size == 0
82
+ string << "UNKNOWN("
83
+ string << op.inspect
84
+ string << ")"
85
+ end
86
+ end
87
+ string = "/"+string if document
88
+ return string
89
+ end
90
+
91
+ def expand( path )
92
+ path = path.kind_of?(String) ? parse( path ) : path
93
+ string = ""
94
+ document = false
95
+ while path.size > 0
96
+ op = path.shift
97
+ case op
98
+ when :node
99
+ string << "node()"
100
+ when :attribute, :child, :following, :following_sibling,
101
+ :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
102
+ :namespace, :preceding, :preceding_sibling, :self, :parent
103
+ string << "/" unless string.size == 0
104
+ string << op.to_s.tr("_", "-")
105
+ string << "::"
106
+ when :any
107
+ string << "*"
108
+ when :qname
109
+ prefix = path.shift
110
+ name = path.shift
111
+ string << prefix+":" if prefix.size > 0
112
+ string << name
113
+ when :predicate
114
+ string << '['
115
+ string << predicate_to_string( path.shift ) { |x| expand(x) }
116
+ string << ']'
117
+ when :document
118
+ document = true
119
+ else
120
+ string << "/" unless string.size == 0
121
+ string << "UNKNOWN("
122
+ string << op.inspect
123
+ string << ")"
124
+ end
125
+ end
126
+ string = "/"+string if document
127
+ return string
128
+ end
129
+
130
+ def predicate_to_string( path, &block )
131
+ string = ""
132
+ case path[0]
133
+ when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
134
+ op = path.shift
135
+ case op
136
+ when :eq
137
+ op = "="
138
+ when :lt
139
+ op = "<"
140
+ when :gt
141
+ op = ">"
142
+ when :lteq
143
+ op = "<="
144
+ when :gteq
145
+ op = ">="
146
+ when :neq
147
+ op = "!="
148
+ when :union
149
+ op = "|"
150
+ end
151
+ left = predicate_to_string( path.shift, &block )
152
+ right = predicate_to_string( path.shift, &block )
153
+ string << " "
154
+ string << left
155
+ string << " "
156
+ string << op.to_s
157
+ string << " "
158
+ string << right
159
+ string << " "
160
+ when :function
161
+ path.shift
162
+ name = path.shift
163
+ string << name
164
+ string << "( "
165
+ string << predicate_to_string( path.shift, &block )
166
+ string << " )"
167
+ when :literal
168
+ path.shift
169
+ string << " "
170
+ string << path.shift.inspect
171
+ string << " "
172
+ else
173
+ string << " "
174
+ string << yield( path )
175
+ string << " "
176
+ end
177
+ return string.squeeze(" ")
178
+ end
179
+
180
+ private
181
+ #LocationPath
182
+ # | RelativeLocationPath
183
+ # | '/' RelativeLocationPath?
184
+ # | '//' RelativeLocationPath
185
+ def LocationPath path, parsed
186
+ #puts "LocationPath '#{path}'"
187
+ path = path.strip
188
+ if path[0] == ?/
189
+ parsed << :document
190
+ if path[1] == ?/
191
+ parsed << :descendant_or_self
192
+ parsed << :node
193
+ path = path[2..-1]
194
+ else
195
+ path = path[1..-1]
196
+ end
197
+ end
198
+ #puts parsed.inspect
199
+ return RelativeLocationPath( path, parsed ) if path.size > 0
200
+ end
201
+
202
+ #RelativeLocationPath
203
+ # | Step
204
+ # | (AXIS_NAME '::' | '@' | '') AxisSpecifier
205
+ # NodeTest
206
+ # Predicate
207
+ # | '.' | '..' AbbreviatedStep
208
+ # | RelativeLocationPath '/' Step
209
+ # | RelativeLocationPath '//' Step
210
+ AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/
211
+ def RelativeLocationPath path, parsed
212
+ #puts "RelativeLocationPath #{path}"
213
+ while path.size > 0
214
+ # (axis or @ or <child::>) nodetest predicate >
215
+ # OR > / Step
216
+ # (. or ..) >
217
+ if path[0] == ?.
218
+ if path[1] == ?.
219
+ parsed << :parent
220
+ parsed << :node
221
+ path = path[2..-1]
222
+ else
223
+ parsed << :self
224
+ parsed << :node
225
+ path = path[1..-1]
226
+ end
227
+ else
228
+ if path[0] == ?@
229
+ #puts "ATTRIBUTE"
230
+ parsed << :attribute
231
+ path = path[1..-1]
232
+ # Goto Nodetest
233
+ elsif path =~ AXIS
234
+ parsed << $1.tr('-','_').intern
235
+ path = $'
236
+ # Goto Nodetest
237
+ else
238
+ parsed << :child
239
+ end
240
+
241
+ #puts "NODETESTING '#{path}'"
242
+ n = []
243
+ path = NodeTest( path, n)
244
+ #puts "NODETEST RETURNED '#{path}'"
245
+
246
+ if path[0] == ?[
247
+ path = Predicate( path, n )
248
+ end
249
+
250
+ parsed.concat(n)
251
+ end
252
+
253
+ if path.size > 0
254
+ if path[0] == ?/
255
+ if path[1] == ?/
256
+ parsed << :descendant_or_self
257
+ parsed << :node
258
+ path = path[2..-1]
259
+ else
260
+ path = path[1..-1]
261
+ end
262
+ else
263
+ return path
264
+ end
265
+ end
266
+ end
267
+ return path
268
+ end
269
+
270
+ # Returns a 1-1 map of the nodeset
271
+ # The contents of the resulting array are either:
272
+ # true/false, if a positive match
273
+ # String, if a name match
274
+ #NodeTest
275
+ # | ('*' | NCNAME ':' '*' | QNAME) NameTest
276
+ # | NODE_TYPE '(' ')' NodeType
277
+ # | PI '(' LITERAL ')' PI
278
+ # | '[' expr ']' Predicate
279
+ NCNAMETEST= /^(#{NCNAME_STR}):\*/u
280
+ QNAME = Namespace::NAMESPLIT
281
+ NODE_TYPE = /^(comment|text|node)\(\s*\)/m
282
+ PI = /^processing-instruction\(/
283
+ def NodeTest path, parsed
284
+ #puts "NodeTest with #{path}"
285
+ res = nil
286
+ case path
287
+ when /^\*/
288
+ path = $'
289
+ parsed << :any
290
+ when NODE_TYPE
291
+ type = $1
292
+ path = $'
293
+ parsed << type.tr('-', '_').intern
294
+ when PI
295
+ path = $'
296
+ literal = nil
297
+ if path !~ /^\s*\)/
298
+ path =~ LITERAL
299
+ literal = $1
300
+ path = $'
301
+ raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?)
302
+ path = path[1..-1]
303
+ end
304
+ parsed << :processing_instruction
305
+ parsed << (literal || '')
306
+ when NCNAMETEST
307
+ #puts "NCNAMETEST"
308
+ prefix = $1
309
+ path = $'
310
+ parsed << :namespace
311
+ parsed << prefix
312
+ when QNAME
313
+ #puts "QNAME"
314
+ prefix = $1
315
+ name = $2
316
+ path = $'
317
+ prefix = "" unless prefix
318
+ parsed << :qname
319
+ parsed << prefix
320
+ parsed << name
321
+ end
322
+ return path
323
+ end
324
+
325
+ # Filters the supplied nodeset on the predicate(s)
326
+ def Predicate path, parsed
327
+ #puts "PREDICATE with #{path}"
328
+ return nil unless path[0] == ?[
329
+ predicates = []
330
+ while path[0] == ?[
331
+ path, expr = get_group(path)
332
+ predicates << expr[1..-2] if expr
333
+ end
334
+ #puts "PREDICATES = #{predicates.inspect}"
335
+ predicates.each{ |expr|
336
+ #puts "ORING #{expr}"
337
+ preds = []
338
+ parsed << :predicate
339
+ parsed << preds
340
+ OrExpr(expr, preds)
341
+ }
342
+ #puts "PREDICATES = #{predicates.inspect}"
343
+ path
344
+ end
345
+
346
+ # The following return arrays of true/false, a 1-1 mapping of the
347
+ # supplied nodeset, except for axe(), which returns a filtered
348
+ # nodeset
349
+
350
+ #| OrExpr S 'or' S AndExpr
351
+ #| AndExpr
352
+ def OrExpr path, parsed
353
+ #puts "OR >>> #{path}"
354
+ n = []
355
+ rest = AndExpr( path, n )
356
+ #puts "OR <<< #{rest}"
357
+ if rest != path
358
+ while rest =~ /^\s*( or )/
359
+ n = [ :or, n, [] ]
360
+ rest = AndExpr( $', n[-1] )
361
+ end
362
+ end
363
+ if parsed.size == 0 and n.size != 0
364
+ parsed.replace(n)
365
+ elsif n.size > 0
366
+ parsed << n
367
+ end
368
+ rest
369
+ end
370
+
371
+ #| AndExpr S 'and' S EqualityExpr
372
+ #| EqualityExpr
373
+ def AndExpr path, parsed
374
+ #puts "AND >>> #{path}"
375
+ n = []
376
+ rest = EqualityExpr( path, n )
377
+ #puts "AND <<< #{rest}"
378
+ if rest != path
379
+ while rest =~ /^\s*( and )/
380
+ n = [ :and, n, [] ]
381
+ #puts "AND >>> #{rest}"
382
+ rest = EqualityExpr( $', n[-1] )
383
+ #puts "AND <<< #{rest}"
384
+ end
385
+ end
386
+ if parsed.size == 0 and n.size != 0
387
+ parsed.replace(n)
388
+ elsif n.size > 0
389
+ parsed << n
390
+ end
391
+ rest
392
+ end
393
+
394
+ #| EqualityExpr ('=' | '!=') RelationalExpr
395
+ #| RelationalExpr
396
+ def EqualityExpr path, parsed
397
+ #puts "EQUALITY >>> #{path}"
398
+ n = []
399
+ rest = RelationalExpr( path, n )
400
+ #puts "EQUALITY <<< #{rest}"
401
+ if rest != path
402
+ while rest =~ /^\s*(!?=)\s*/
403
+ if $1[0] == ?!
404
+ n = [ :neq, n, [] ]
405
+ else
406
+ n = [ :eq, n, [] ]
407
+ end
408
+ rest = RelationalExpr( $', n[-1] )
409
+ end
410
+ end
411
+ if parsed.size == 0 and n.size != 0
412
+ parsed.replace(n)
413
+ elsif n.size > 0
414
+ parsed << n
415
+ end
416
+ rest
417
+ end
418
+
419
+ #| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr
420
+ #| AdditiveExpr
421
+ def RelationalExpr path, parsed
422
+ #puts "RELATION >>> #{path}"
423
+ n = []
424
+ rest = AdditiveExpr( path, n )
425
+ #puts "RELATION <<< #{rest}"
426
+ if rest != path
427
+ while rest =~ /^\s*([<>]=?)\s*/
428
+ if $1[0] == ?<
429
+ sym = "lt"
430
+ else
431
+ sym = "gt"
432
+ end
433
+ sym << "eq" if $1[-1] == ?=
434
+ n = [ sym.intern, n, [] ]
435
+ rest = AdditiveExpr( $', n[-1] )
436
+ end
437
+ end
438
+ if parsed.size == 0 and n.size != 0
439
+ parsed.replace(n)
440
+ elsif n.size > 0
441
+ parsed << n
442
+ end
443
+ rest
444
+ end
445
+
446
+ #| AdditiveExpr ('+' | S '-') MultiplicativeExpr
447
+ #| MultiplicativeExpr
448
+ def AdditiveExpr path, parsed
449
+ #puts "ADDITIVE >>> #{path}"
450
+ n = []
451
+ rest = MultiplicativeExpr( path, n )
452
+ #puts "ADDITIVE <<< #{rest}"
453
+ if rest != path
454
+ while rest =~ /^\s*(\+| -)\s*/
455
+ if $1[0] == ?+
456
+ n = [ :plus, n, [] ]
457
+ else
458
+ n = [ :minus, n, [] ]
459
+ end
460
+ rest = MultiplicativeExpr( $', n[-1] )
461
+ end
462
+ end
463
+ if parsed.size == 0 and n.size != 0
464
+ parsed.replace(n)
465
+ elsif n.size > 0
466
+ parsed << n
467
+ end
468
+ rest
469
+ end
470
+
471
+ #| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr
472
+ #| UnaryExpr
473
+ def MultiplicativeExpr path, parsed
474
+ #puts "MULT >>> #{path}"
475
+ n = []
476
+ rest = UnaryExpr( path, n )
477
+ #puts "MULT <<< #{rest}"
478
+ if rest != path
479
+ while rest =~ /^\s*(\*| div | mod )\s*/
480
+ if $1[0] == ?*
481
+ n = [ :mult, n, [] ]
482
+ elsif $1.include?( "div" )
483
+ n = [ :div, n, [] ]
484
+ else
485
+ n = [ :mod, n, [] ]
486
+ end
487
+ rest = UnaryExpr( $', n[-1] )
488
+ end
489
+ end
490
+ if parsed.size == 0 and n.size != 0
491
+ parsed.replace(n)
492
+ elsif n.size > 0
493
+ parsed << n
494
+ end
495
+ rest
496
+ end
497
+
498
+ #| '-' UnaryExpr
499
+ #| UnionExpr
500
+ def UnaryExpr path, parsed
501
+ path =~ /^(\-*)/
502
+ path = $'
503
+ if $1 and (($1.size % 2) != 0)
504
+ mult = -1
505
+ else
506
+ mult = 1
507
+ end
508
+ parsed << :neg if mult < 0
509
+
510
+ #puts "UNARY >>> #{path}"
511
+ n = []
512
+ path = UnionExpr( path, n )
513
+ #puts "UNARY <<< #{path}"
514
+ parsed.concat( n )
515
+ path
516
+ end
517
+
518
+ #| UnionExpr '|' PathExpr
519
+ #| PathExpr
520
+ def UnionExpr path, parsed
521
+ #puts "UNION >>> #{path}"
522
+ n = []
523
+ rest = PathExpr( path, n )
524
+ #puts "UNION <<< #{rest}"
525
+ if rest != path
526
+ while rest =~ /^\s*(\|)\s*/
527
+ n = [ :union, n, [] ]
528
+ rest = PathExpr( $', n[-1] )
529
+ end
530
+ end
531
+ if parsed.size == 0 and n.size != 0
532
+ parsed.replace( n )
533
+ elsif n.size > 0
534
+ parsed << n
535
+ end
536
+ rest
537
+ end
538
+
539
+ #| LocationPath
540
+ #| FilterExpr ('/' | '//') RelativeLocationPath
541
+ def PathExpr path, parsed
542
+ path =~ /^\s*/
543
+ path = $'
544
+ #puts "PATH >>> #{path}"
545
+ n = []
546
+ rest = FilterExpr( path, n )
547
+ #puts "PATH <<< '#{rest}'"
548
+ if rest != path
549
+ if rest and rest[0] == ?/
550
+ return RelativeLocationPath(rest, n)
551
+ end
552
+ end
553
+ #puts "BEFORE WITH '#{rest}'"
554
+ rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/
555
+ parsed.concat(n)
556
+ return rest
557
+ end
558
+
559
+ #| FilterExpr Predicate
560
+ #| PrimaryExpr
561
+ def FilterExpr path, parsed
562
+ #puts "FILTER >>> #{path}"
563
+ n = []
564
+ path = PrimaryExpr( path, n )
565
+ #puts "FILTER <<< #{path}"
566
+ path = Predicate(path, n) if path and path[0] == ?[
567
+ #puts "FILTER <<< #{path}"
568
+ parsed.concat(n)
569
+ path
570
+ end
571
+
572
+ #| VARIABLE_REFERENCE
573
+ #| '(' expr ')'
574
+ #| LITERAL
575
+ #| NUMBER
576
+ #| FunctionCall
577
+ VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u
578
+ NUMBER = /^(\d*\.?\d+)/
579
+ NT = /^comment|text|processing-instruction|node$/
580
+ def PrimaryExpr path, parsed
581
+ arry = []
582
+ case path
583
+ when VARIABLE_REFERENCE
584
+ varname = $1
585
+ path = $'
586
+ parsed << :variable
587
+ parsed << varname
588
+ #arry << @variables[ varname ]
589
+ when /^(\w[-\w]*)(?:\()/
590
+ #puts "PrimaryExpr :: Function >>> #$1 -- '#$''"
591
+ fname = $1
592
+ tmp = $'
593
+ #puts "#{fname} =~ #{NT.inspect}"
594
+ return path if fname =~ NT
595
+ path = tmp
596
+ parsed << :function
597
+ parsed << fname
598
+ path = FunctionCall(path, parsed)
599
+ when NUMBER
600
+ #puts "LITERAL or NUMBER: #$1"
601
+ varname = $1.nil? ? $2 : $1
602
+ path = $'
603
+ parsed << :literal
604
+ parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
605
+ when LITERAL
606
+ #puts "LITERAL or NUMBER: #$1"
607
+ varname = $1.nil? ? $2 : $1
608
+ path = $'
609
+ parsed << :literal
610
+ parsed << varname
611
+ when /^\(/ #/
612
+ path, contents = get_group(path)
613
+ contents = contents[1..-2]
614
+ n = []
615
+ OrExpr( contents, n )
616
+ parsed.concat(n)
617
+ end
618
+ path
619
+ end
620
+
621
+ #| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')'
622
+ def FunctionCall rest, parsed
623
+ path, arguments = parse_args(rest)
624
+ argset = []
625
+ for argument in arguments
626
+ args = []
627
+ OrExpr( argument, args )
628
+ argset << args
629
+ end
630
+ parsed << argset
631
+ path
632
+ end
633
+
634
+ # get_group( '[foo]bar' ) -> ['bar', '[foo]']
635
+ def get_group string
636
+ ind = 0
637
+ depth = 0
638
+ st = string[0,1]
639
+ en = (st == "(" ? ")" : "]")
640
+ begin
641
+ case string[ind,1]
642
+ when st
643
+ depth += 1
644
+ when en
645
+ depth -= 1
646
+ end
647
+ ind += 1
648
+ end while depth > 0 and ind < string.length
649
+ return nil unless depth==0
650
+ [string[ind..-1], string[0..ind-1]]
651
+ end
652
+
653
+ def parse_args( string )
654
+ arguments = []
655
+ ind = 0
656
+ inquot = false
657
+ inapos = false
658
+ depth = 1
659
+ begin
660
+ case string[ind]
661
+ when ?"
662
+ inquot = !inquot unless inapos
663
+ when ?'
664
+ inapos = !inapos unless inquot
665
+ else
666
+ unless inquot or inapos
667
+ case string[ind]
668
+ when ?(
669
+ depth += 1
670
+ if depth == 1
671
+ string = string[1..-1]
672
+ ind -= 1
673
+ end
674
+ when ?)
675
+ depth -= 1
676
+ if depth == 0
677
+ s = string[0,ind].strip
678
+ arguments << s unless s == ""
679
+ string = string[ind+1..-1]
680
+ end
681
+ when ?,
682
+ if depth == 1
683
+ s = string[0,ind].strip
684
+ arguments << s unless s == ""
685
+ string = string[ind+1..-1]
686
+ ind = -1
687
+ end
688
+ end
689
+ end
690
+ end
691
+ ind += 1
692
+ end while depth > 0 and ind < string.length
693
+ return nil unless depth==0
694
+ [string,arguments]
695
+ end
696
+ end
697
+ end
698
+ end