# REXML::QuickPath (Class)

In: | rexml/quickpath.rb
Parent: | Object

## Methods

attribute axe each filter first function match method_missing name parse_args predicate

## Constants

EMPTY_HASH | = | {}

## Included Modules

Functions XMLTokens

## Public Class methods

first(element, path, namespaces=EMPTY_HASH)

[Source]

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

each(element, path, namespaces=EMPTY_HASH, &block)

[Source]

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

match(element, path, namespaces=EMPTY_HASH)

[Source]

    # File rexml/quickpath.rb, line 20
                    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

                                    matches = []
                                    children = element.to_a
                                    results = filter(children, path)
                            else
                                    results = filter([element], path)
                            end
                            return results
                    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

[Source]

    # File rexml/quickpath.rb, line 48
                    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

                                    axe_name = $1
                                    rest = $'
                                    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.expanded_name == 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

axe( elements, axe_name, rest )

[Source]

    # File 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

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[3] is equivalent to para[position()=3].

[Source]

    # File rexml/quickpath.rb, line 160
                    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!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/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

attribute( name )

[Source]

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

name()

[Source]

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

method_missing( id, *args )

[Source]

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

function( elements, fname, rest )

[Source]

    # File 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

parse_args( element, string )

[Source]

    # File 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

[Validate]