Class REXML::QuickPath
In: lib/rexml/quickpath.rb
Parent: Object

Methods

attribute   axe   each   filter   first   function   match   method_missing   name   parse_args   predicate  

Included Modules

Functions XMLTokens

Constants

EMPTY_HASH = {}

Public Class methods

[Source]

     # File lib/rexml/quickpath.rb, line 206
206:                 def QuickPath::attribute( name )
207:                         return Functions.node.attributes[name] if Functions.node.kind_of? Element
208:                 end

[Source]

     # File lib/rexml/quickpath.rb, line 106
106:                 def QuickPath::axe( elements, axe_name, rest )
107:                         matches = []
108:                         matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
109:                         case axe_name
110:                         when /^descendant/u
111:                                 elements.each do |element|
112:                                         matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
113:                                 end
114:                         when /^ancestor/u
115:                                 elements.each do |element|
116:                                         while element.parent
117:                                                 matches << element.parent
118:                                                 element = element.parent
119:                                         end
120:                                 end
121:                                 matches = filter( matches, rest )
122:                         when "self"
123:                                 matches = filter( elements, rest )
124:                         when "child"
125:                                 elements.each do |element|
126:                                         matches |= filter( element.to_a, rest ) if element.kind_of? Element
127:                                 end
128:                         when "attribute"
129:                                 elements.each do |element|
130:                                         matches << element.attributes[ rest ] if element.kind_of? Element
131:                                 end
132:                         when "parent"
133:                                 matches = filter(elements.collect{|element| element.parent}.uniq, rest)
134:                         when "following-sibling"
135:                                 matches = filter(elements.collect{|element| element.next_sibling}.uniq,
136:                                         rest)
137:                         when "previous-sibling"
138:                                 matches = filter(elements.collect{|element| 
139:                                         element.previous_sibling}.uniq, rest )
140:                         end
141:                         return matches.uniq
142:                 end

[Source]

    # File lib/rexml/quickpath.rb, line 15
15:                 def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
16:                         path = "*" unless path
17:                         match(element, path, namespaces).each( &block )
18:                 end

Given an array of nodes it filters the array based on the path. The result is that when this method returns, the array will contain elements which match the path

[Source]

     # File lib/rexml/quickpath.rb, line 48
 48:                 def QuickPath::filter elements, path
 49:                         return elements if path.nil? or path == '' or elements.size == 0
 50:                         case path
 51:                         when /^\/\//u                                                                                        # Descendant
 52:                                 return axe( elements, "descendant-or-self", $' )
 53:                         when /^\/?\b(\w[-\w]*)\b::/u                                                 # Axe
 54:                                 axe_name = $1
 55:                                 rest = $'
 56:                                 return axe( elements, $1, $' )
 57:                         when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child
 58:                                 rest = $'
 59:                                 results = []
 60:                                 elements.each do |element|
 61:                                         results |= filter( element.to_a, rest )
 62:                                 end
 63:                                 return results
 64:                         when /^\/?(\w[-\w]*)\(/u                                                     # / Function
 65:                                 return function( elements, $1, $' )
 66:                         when Namespace::NAMESPLIT            # Element name
 67:                                 name = $2
 68:                                 ns = $1
 69:                                 rest = $'
 70:                                 elements.delete_if do |element|
 71:                                         !(element.kind_of? Element and 
 72:                                                 (element.expanded_name == name or
 73:                                                  (element.name == name and
 74:                                                   element.namespace == Functions.namespace_context[ns])))
 75:                                 end
 76:                                 return filter( elements, rest )
 77:                         when /^\/\[/u
 78:                                 matches = []
 79:                                 elements.each do |element|
 80:                                         matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
 81:                                 end
 82:                                 return matches
 83:                         when /^\[/u                                                                                          # Predicate
 84:                                 return predicate( elements, path )
 85:                         when /^\/?\.\.\./u                                                                           # Ancestor
 86:                                 return axe( elements, "ancestor", $' )
 87:                         when /^\/?\.\./u                                                                                     # Parent
 88:                                 return filter( elements.collect{|e|e.parent}, $' )
 89:                         when /^\/?\./u                                                                                               # Self
 90:                                 return filter( elements, $' )
 91:                         when /^\*/u                                                                                                  # Any
 92:                                 results = []
 93:                                 elements.each do |element|
 94:                                         results |= filter( [element], $' ) if element.kind_of? Element
 95:                                         #if element.kind_of? Element
 96:                                         #  children = element.to_a
 97:                                         #  children.delete_if { |child| !child.kind_of?(Element) }
 98:                                         #  results |= filter( children, $' )
 99:                                         #end
100:                                 end
101:                                 return results
102:                         end
103:                         return []
104:                 end

[Source]

    # File lib/rexml/quickpath.rb, line 11
11:                 def QuickPath::first element, path, namespaces=EMPTY_HASH
12:                         match(element, path, namespaces)[0]
13:                 end

[Source]

     # File lib/rexml/quickpath.rb, line 222
222:                 def QuickPath::function( elements, fname, rest )
223:                         args = parse_args( elements, rest )
224:                         Functions.pair = [0, elements.size]
225:                         results = []
226:                         elements.each do |element|
227:                                 Functions.pair[0] += 1
228:                                 Functions.node = element
229:                                 res = Functions.send( fname, *args )
230:                                 case res
231:                                 when true
232:                                         results << element
233:                                 when Fixnum
234:                                         results << element if Functions.pair[0] == res
235:                                 end
236:                         end
237:                         return results
238:                 end

[Source]

    # File lib/rexml/quickpath.rb, line 20
20:                 def QuickPath::match element, path, namespaces=EMPTY_HASH
21:                         raise "nil is not a valid xpath" unless path
22:                         results = nil
23:                         Functions::namespace_context = namespaces
24:                         case path
25:                         when /^\/([^\/]|$)/u
26:                                 # match on root
27:                                 path = path[1..-1]
28:                                 return [element.root.parent] if path == ''
29:                                 results = filter([element.root], path)
30:                         when /^[-\w]*::/u
31:                                 results = filter([element], path)
32:                         when /^\*/u
33:                                 results = filter(element.to_a, path)
34:                         when /^[\[!\w:]/u
35:                                 # match on child
36:                                 matches = []
37:                                 children = element.to_a
38:                                 results = filter(children, path)
39:                         else
40:                                 results = filter([element], path)
41:                         end
42:                         return results
43:                 end

[Source]

     # File lib/rexml/quickpath.rb, line 214
214:                 def QuickPath::method_missing( id, *args )
215:                         begin
216:                                 Functions.send( id.id2name, *args )
217:                         rescue Exception
218:                                 raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
219:                         end
220:                 end

[Source]

     # File lib/rexml/quickpath.rb, line 210
210:                 def QuickPath::name()
211:                         return Functions.node.name if Functions.node.kind_of? Element
212:                 end

[Source]

     # File lib/rexml/quickpath.rb, line 240
240:                 def QuickPath::parse_args( element, string )
241:                         # /.*?(?:\)|,)/
242:                         arguments = []
243:                         buffer = ""
244:                         while string and string != ""
245:                                 c = string[0]
246:                                 string.sub!(/^./u, "")
247:                                 case c
248:                                 when ?,
249:                                         # if depth = 1, then we start a new argument
250:                                         arguments << evaluate( buffer )
251:                                         #arguments << evaluate( string[0..count] )
252:                                 when ?(
253:                                         # start a new method call
254:                                         function( element, buffer, string )
255:                                         buffer = ""
256:                                 when ?)
257:                                         # close the method call and return arguments
258:                                         return arguments
259:                                 else
260:                                         buffer << c
261:                                 end
262:                         end
263:                         ""
264:                 end

A predicate filters a node-set with respect to an axis to produce a new node-set. For each node in the node-set to be filtered, the PredicateExpr is evaluated with that node as the context node, with the number of nodes in the node-set as the context size, and with the proximity position of the node in the node-set with respect to the axis as the context position; if PredicateExpr evaluates to true for that node, the node is included in the new node-set; otherwise, it is not included.

A PredicateExpr is evaluated by evaluating the Expr and converting the result to a boolean. If the result is a number, the result will be converted to true if the number is equal to the context position and will be converted to false otherwise; if the result is not a number, then the result will be converted as if by a call to the boolean function. Thus a location path para[3] is equivalent to para[position()=3].

[Source]

     # File lib/rexml/quickpath.rb, line 160
160:                 def QuickPath::predicate( elements, path ) 
161:                         ind = 1
162:                         bcount = 1
163:                         while bcount > 0
164:                                 bcount += 1 if path[ind] == ?[
165:                                 bcount -= 1 if path[ind] == ?]
166:                                 ind += 1
167:                         end
168:                         ind -= 1
169:                         predicate = path[1..ind-1]
170:                         rest = path[ind+1..-1]
171: 
172:                         # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
173:                         predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u ) { 
174:                                 "#$1 #$2 #$3 and #$3 #$4 #$5"
175:                         }
176:                         # Let's do some Ruby trickery to avoid some work:
177:                         predicate.gsub!( /&/u, "&&" )
178:                         predicate.gsub!( /=/u, "==" )
179:                         predicate.gsub!( /@(\w[-\w.]*)/u ) {
180:                                 "attribute(\"#$1\")" 
181:                         }
182:                         predicate.gsub!( /\bmod\b/u, "%" )
183:                         predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
184:                                 fname = $1
185:                                 fname.gsub( /-/u, "_" )
186:                         }
187:                         
188:                         Functions.pair = [ 0, elements.size ]
189:                         results = []
190:                         elements.each do |element|
191:                                 Functions.pair[0] += 1
192:                                 Functions.node = element
193:                                 res = eval( predicate )
194:                                 case res
195:                                 when true
196:                                         results << element
197:                                 when Fixnum
198:                                         results << element if Functions.pair[0] == res
199:                                 when String
200:                                         results << element
201:                                 end
202:                         end
203:                         return filter( results, rest )
204:                 end

[Validate]