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

[Source]

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

[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

[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

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

[Source]

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

[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

[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

[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

[Source]

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

[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

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

[Validate]