Class: REXML::QuickPath
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/rexml/quickpath.rb |
Constant Summary
-
EMPTY_HASH =
A base Hash object to be used when initializing a default empty namespaces set.
{}
-
OPERAND_ =
# File 'lib/rexml/quickpath.rb', line 144'((?=(?:(?!and|or).)*[^\s<>=])[^\s<>=]+)'
Functions - Included
XMLTokens - Included
NAME, NAMECHAR, NAME_CHAR, NAME_START_CHAR, NAME_STR, NCNAME_STR, NMTOKEN, NMTOKENS, REFERENCE
Class Method Summary
- .attribute(name)
- .axe(elements, axe_name, rest)
- .each(element, path, namespaces = EMPTY_HASH, &block)
-
.filter(elements, path)
Given an array of nodes it filters the array based on the path.
- .first(element, path, namespaces = EMPTY_HASH)
- .function(elements, fname, rest)
- .match(element, path, namespaces = EMPTY_HASH)
- .method_missing(id, *args)
- .name
- .parse_args(element, string)
-
.predicate(elements, path)
A predicate filters a node-set with respect to an axis to produce a new node-set.
Class Method Details
.attribute(name)
[ GitHub ].axe(elements, axe_name, rest)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 106
def QuickPath::axe( elements, axe_name, rest ) matches = [] matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u case axe_name when /^descendant/u elements.each do |element| matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element end when /^ancestor/u elements.each do |element| while element.parent matches << element.parent element = element.parent end end matches = filter( matches, rest ) when "self" matches = filter( elements, rest ) when "child" elements.each do |element| matches |= filter( element.to_a, rest ) if element.kind_of? Element end when "attribute" elements.each do |element| matches << element.attributes[ rest ] if element.kind_of? Element end when "parent" matches = filter(elements.collect{|element| element.parent}.uniq, rest) when "following-sibling" matches = filter(elements.collect{|element| element.next_sibling}.uniq, rest) when "previous-sibling" matches = filter(elements.collect{|element| element.previous_sibling}.uniq, rest ) end return matches.uniq end
.each(element, path, namespaces = EMPTY_HASH, &block)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 18
def QuickPath::each element, path, namespaces=EMPTY_HASH, &block path = "*" unless path match(element, path, namespaces).each( &block ) end
.filter(elements, path)
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
# File 'lib/rexml/quickpath.rb', line 50
def QuickPath::filter elements, path return elements if path.nil? or path == '' or elements.size == 0 case path when /^\/\//u # Descendant return axe( elements, "descendant-or-self", $' ) when /^\/?\b(\w[-\w]*)\b::/u # Axe return axe( elements, $1, $' ) when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child rest = $' results = [] elements.each do |element| results |= filter( element.to_a, rest ) end return results when /^\/?(\w[-\w]*)\(/u # / Function return function( elements, $1, $' ) when Namespace::NAMESPLIT # Element name name = $2 ns = $1 rest = $' elements.delete_if do |element| !(element.kind_of? Element and (element. == name or (element.name == name and element.namespace == Functions.namespace_context[ns]))) end return filter( elements, rest ) when /^\/\[/u matches = [] elements.each do |element| matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element end return matches when /^\[/u # Predicate return predicate( elements, path ) when /^\/?\.\.\./u # Ancestor return axe( elements, "ancestor", $' ) when /^\/?\.\./u # Parent return filter( elements.collect{|e|e.parent}, $' ) when /^\/?\./u # Self return filter( elements, $' ) when /^\*/u # Any results = [] elements.each do |element| results |= filter( [element], $' ) if element.kind_of? Element #if element.kind_of? Element # children = element.to_a # children.delete_if { |child| !child.kind_of?(Element) } # results |= filter( children, $' ) #end end return results end return [] end
.first(element, path, namespaces = EMPTY_HASH)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 14
def QuickPath::first element, path, namespaces=EMPTY_HASH match(element, path, namespaces)[0] end
.function(elements, fname, rest)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 222
def QuickPath::function( elements, fname, rest ) args = parse_args( elements, rest ) Functions.pair = [0, elements.size] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = Functions.send( fname, *args ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res end end return results end
.match(element, path, namespaces = EMPTY_HASH)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 23
def QuickPath::match element, path, namespaces=EMPTY_HASH raise "nil is not a valid xpath" unless path results = nil Functions::namespace_context = namespaces case path when /^\/([^\/]|$)/u # match on root path = path[1..-1] return [element.root.parent] if path == '' results = filter([element.root], path) when /^[-\w]*::/u results = filter([element], path) when /^\*/u results = filter(element.to_a, path) when /^[\[!\w:]/u # match on child children = element.to_a results = filter(children, path) else results = filter([element], path) end return results end
.method_missing(id, *args)
[ GitHub ].name
[ GitHub ].parse_args(element, string)
[ GitHub ]# File 'lib/rexml/quickpath.rb', line 240
def QuickPath::parse_args( element, string ) # /.*?(?:\)|,)/ arguments = [] buffer = "" while string and string != "" c = string[0] string.sub!(/^./u, "") case c when ?, # if depth = 1, then we start a new argument arguments << evaluate( buffer ) #arguments << evaluate( string[0..count] ) when ?( # start a new method call function( element, buffer, string ) buffer = "" when ?) # close the method call and return arguments return arguments else buffer << c end end "" end
.predicate(elements, path)
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 is equivalent to para.
# File 'lib/rexml/quickpath.rb', line 161
def QuickPath::predicate( elements, path ) ind = 1 bcount = 1 while bcount > 0 bcount += 1 if path[ind] == ?[ bcount -= 1 if path[ind] == ?] ind += 1 end ind -= 1 predicate = path[1..ind-1] rest = path[ind+1..-1] # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c' # predicate.gsub!( /#{OPERAND_}\s*([<>=])\s*#{OPERAND_}\s*([<>=])\s*#{OPERAND_}/u, '\1 \2 \3 and \3 \4 \5' ) # Let's do some Ruby trickery to avoid some work: predicate.gsub!( /&/u, "&&" ) predicate.gsub!( /=/u, "==" ) predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' ) predicate.gsub!( /\bmod\b/u, "%" ) predicate.gsub!( /\b(\w[-\w.]*\()/u ) { fname = $1 fname.gsub( /-/u, "_" ) } Functions.pair = [ 0, elements.size ] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = eval( predicate ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res when String results << element end end return filter( results, rest ) end