class REXML::Parsers::XPathParser

You don't want to use this class. Really. Use XPath, which is a wrapper for this class. Believe me. You don't want to poke around in here. There is strange, dark magic at work in this code. Beware. Go back! Go back while you still can!

Constants

AXIS

#RelativeLocationPath

| Step
 | (AXIS_NAME '::' | '@' | '') AxisSpecifier
 NodeTest
 Predicate
 | '.' | '..' AbbreviatedStep
| RelativeLocationPath '/' Step
| RelativeLocationPath '//' Step
LITERAL
NCNAMETEST
Returns a 1-1 map of the nodeset
The contents of the resulting array are either:
 true/false, if a positive match
 String, if a name match

#NodeTest

| ('*' | NCNAME ':' '*' | QNAME) NameTest
| NODE_TYPE '(' ')' NodeType
| PI '(' LITERAL ')' PI
 | '[' expr ']' Predicate
NODE_TYPE
NT
NUMBER
PI
QNAME
VARIABLE_REFERENCE

| VARIABLE_REFERENCE | '(' expr ')' | LITERAL | NUMBER | #FunctionCall

Public Instance Methods

abbreviate( path ) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 34
def abbreviate( path )
 path = path.kind_of?(String) ? parse( path ) : path
 string = ""
 document = false
 while path.size > 0
 op = path.shift
 case op
 when :node
 when :attribute
 string << "/" if string.size > 0
 string << "@"
 when :child
 string << "/" if string.size > 0
 when :descendant_or_self
 string << "/"
 when :self
 string << "."
 when :parent
 string << ".."
 when :any
 string << "*"
 when :text
 string << "text()"
 when :following, :following_sibling,
 :ancestor, :ancestor_or_self, :descendant,
 :namespace, :preceding, :preceding_sibling
 string << "/" unless string.size == 0
 string << op.to_s.tr("_", "-")
 string << "::"
 when :qname
 prefix = path.shift
 name = path.shift
 string << prefix+":" if prefix.size > 0
 string << name
 when :predicate
 string << '['
 string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
 string << ']'
 when :document
 document = true
 when :function
 string << path.shift
 string << "( "
 string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
 string << " )"
 when :literal
 string << %Q{ "#{path.shift}" }
 else
 string << "/" unless string.size == 0
 string << "UNKNOWN("
 string << op.inspect
 string << ")"
 end
 end
 string = "/"+string if document
 return string
end
expand( path ) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 92
def expand( path )
 path = path.kind_of?(String) ? parse( path ) : path
 string = ""
 document = false
 while path.size > 0
 op = path.shift
 case op
 when :node
 string << "node()"
 when :attribute, :child, :following, :following_sibling,
 :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
 :namespace, :preceding, :preceding_sibling, :self, :parent
 string << "/" unless string.size == 0
 string << op.to_s.tr("_", "-")
 string << "::"
 when :any
 string << "*"
 when :qname
 prefix = path.shift
 name = path.shift
 string << prefix+":" if prefix.size > 0
 string << name
 when :predicate
 string << '['
 string << predicate_to_string( path.shift ) { |x| expand(x) }
 string << ']'
 when :document
 document = true
 else
 string << "/" unless string.size == 0
 string << "UNKNOWN("
 string << op.inspect
 string << ")"
 end
 end
 string = "/"+string if document
 return string
end
namespaces=( namespaces ) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 14
def namespaces=( namespaces )
 Functions::namespace_context = namespaces
 @namespaces = namespaces
end
parse(path) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 19
def parse path
 path = path.dup
 path.gsub!(/([\(\[])\s+/, '1円') # Strip ignorable spaces
 path.gsub!( /\s+([\]\)])/, '1円')
 parsed = []
 path = OrExpr(path, parsed)
 parsed
end
predicate(path) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 28
def predicate path
 parsed = []
 Predicate( "[#{path}]", parsed )
 parsed
end
predicate_to_string( path ) { |path| ... } click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 131
def predicate_to_string( path, &block )
 string = ""
 case path[0]
 when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
 op = path.shift
 case op
 when :eq
 op = "="
 when :lt
 op = "<"
 when :gt
 op = ">"
 when :lteq
 op = "<="
 when :gteq
 op = ">="
 when :neq
 op = "!="
 when :union
 op = "|"
 end
 left = predicate_to_string( path.shift, &block )
 right = predicate_to_string( path.shift, &block )
 string << " "
 string << left
 string << " "
 string << op.to_s
 string << " "
 string << right
 string << " "
 when :function
 path.shift
 name = path.shift
 string << name
 string << "( "
 string << predicate_to_string( path.shift, &block )
 string << " )"
 when :literal
 path.shift
 string << " "
 string << path.shift.inspect
 string << " "
 else
 string << " "
 string << yield( path )
 string << " "
 end
 return string.squeeze(" ")
end

Private Instance Methods

AdditiveExpr(path, parsed) click to toggle source

| #AdditiveExpr ('+' | S '-') #MultiplicativeExpr | #MultiplicativeExpr

# File lib/rexml/parsers/xpathparser.rb, line 448
def AdditiveExpr path, parsed
 #puts "ADDITIVE >>> #{path}"
 n = []
 rest = MultiplicativeExpr( path, n )
 #puts "ADDITIVE <<< #{rest}"
 if rest != path
 while rest =~ /^\s*(\+| -)\s*/
 if 1ドル[0] == ?+
 n = [ :plus, n, [] ]
 else
 n = [ :minus, n, [] ]
 end
 rest = MultiplicativeExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
AndExpr(path, parsed) click to toggle source

| #AndExpr S 'and' S #EqualityExpr | #EqualityExpr

# File lib/rexml/parsers/xpathparser.rb, line 373
def AndExpr path, parsed
 #puts "AND >>> #{path}"
 n = []
 rest = EqualityExpr( path, n )
 #puts "AND <<< #{rest}"
 if rest != path
 while rest =~ /^\s*( and )/
 n = [ :and, n, [] ]
 #puts "AND >>> #{rest}"
 rest = EqualityExpr( $', n[-1] )
 #puts "AND <<< #{rest}"
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
EqualityExpr(path, parsed) click to toggle source

| #EqualityExpr ('=' | '!=') #RelationalExpr | #RelationalExpr

# File lib/rexml/parsers/xpathparser.rb, line 396
def EqualityExpr path, parsed
 #puts "EQUALITY >>> #{path}"
 n = []
 rest = RelationalExpr( path, n )
 #puts "EQUALITY <<< #{rest}"
 if rest != path
 while rest =~ /^\s*(!?=)\s*/
 if 1ドル[0] == ?!
 n = [ :neq, n, [] ]
 else
 n = [ :eq, n, [] ]
 end
 rest = RelationalExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
FilterExpr(path, parsed) click to toggle source

| #FilterExpr #Predicate | #PrimaryExpr

# File lib/rexml/parsers/xpathparser.rb, line 561
def FilterExpr path, parsed
 #puts "FILTER >>> #{path}"
 n = []
 path = PrimaryExpr( path, n )
 #puts "FILTER <<< #{path}"
 path = Predicate(path, n) if path and path[0] == ?[
 #puts "FILTER <<< #{path}"
 parsed.concat(n)
 path
end
FunctionCall(rest, parsed) click to toggle source

| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')'

# File lib/rexml/parsers/xpathparser.rb, line 621
def FunctionCall rest, parsed
 path, arguments = parse_args(rest)
 argset = []
 for argument in arguments
 args = []
 OrExpr( argument, args )
 argset << args
 end
 parsed << argset
 path
end
LocationPath(path, parsed) click to toggle source

#LocationPath

| RelativeLocationPath
| '/' RelativeLocationPath?
| '//' RelativeLocationPath
# File lib/rexml/parsers/xpathparser.rb, line 186
def LocationPath path, parsed
 #puts "LocationPath '#{path}'"
 path = path.strip
 if path[0] == ?/
 parsed << :document
 if path[1] == ?/
 parsed << :descendant_or_self
 parsed << :node
 path = path[2..-1]
 else
 path = path[1..-1]
 end
 end
 #puts parsed.inspect
 return RelativeLocationPath( path, parsed ) if path.size > 0
end
MultiplicativeExpr(path, parsed) click to toggle source

| #MultiplicativeExpr ('*' | S ('div' | 'mod') S) #UnaryExpr | #UnaryExpr

# File lib/rexml/parsers/xpathparser.rb, line 473
def MultiplicativeExpr path, parsed
 #puts "MULT >>> #{path}"
 n = []
 rest = UnaryExpr( path, n )
 #puts "MULT <<< #{rest}"
 if rest != path
 while rest =~ /^\s*(\*| div | mod )\s*/
 if 1ドル[0] == ?*
 n = [ :mult, n, [] ]
 elsif 1ドル.include?( "div" )
 n = [ :div, n, [] ]
 else
 n = [ :mod, n, [] ]
 end
 rest = UnaryExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
NodeTest(path, parsed) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 284
def NodeTest path, parsed
 #puts "NodeTest with #{path}"
 case path
 when /^\*/
 path = $'
 parsed << :any
 when NODE_TYPE
 type = 1ドル
 path = $'
 parsed << type.tr('-', '_').intern
 when PI
 path = $'
 literal = nil
 if path !~ /^\s*\)/
 path =~ LITERAL
 literal = 1ドル
 path = $'
 raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?)
 path = path[1..-1]
 end
 parsed << :processing_instruction
 parsed << (literal || '')
 when NCNAMETEST
 #puts "NCNAMETEST"
 prefix = 1ドル
 path = $'
 parsed << :namespace
 parsed << prefix
 when QNAME
 #puts "QNAME"
 prefix = 1ドル
 name = 2ドル
 path = $'
 prefix = "" unless prefix
 parsed << :qname
 parsed << prefix
 parsed << name
 end
 return path
end
OrExpr(path, parsed) click to toggle source

| #OrExpr S 'or' S #AndExpr | #AndExpr

# File lib/rexml/parsers/xpathparser.rb, line 352
def OrExpr path, parsed
 #puts "OR >>> #{path}"
 n = []
 rest = AndExpr( path, n )
 #puts "OR <<< #{rest}"
 if rest != path
 while rest =~ /^\s*( or )/
 n = [ :or, n, [] ]
 rest = AndExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
PathExpr(path, parsed) click to toggle source

| #LocationPath | #FilterExpr ('/' | '//') #RelativeLocationPath

# File lib/rexml/parsers/xpathparser.rb, line 541
def PathExpr path, parsed
 path =~ /^\s*/
 path = $'
 #puts "PATH >>> #{path}"
 n = []
 rest = FilterExpr( path, n )
 #puts "PATH <<< '#{rest}'"
 if rest != path
 if rest and rest[0] == ?/
 return RelativeLocationPath(rest, n)
 end
 end
 #puts "BEFORE WITH '#{rest}'"
 rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
 parsed.concat(n)
 return rest
end
Predicate(path, parsed) click to toggle source

Filters the supplied nodeset on the predicate(s)

# File lib/rexml/parsers/xpathparser.rb, line 326
def Predicate path, parsed
 #puts "PREDICATE with #{path}"
 return nil unless path[0] == ?[
 predicates = []
 while path[0] == ?[
 path, expr = get_group(path)
 predicates << expr[1..-2] if expr
 end
 #puts "PREDICATES = #{predicates.inspect}"
 predicates.each{ |pred|
 #puts "ORING #{pred}"
 preds = []
 parsed << :predicate
 parsed << preds
 OrExpr(pred, preds)
 }
 #puts "PREDICATES = #{predicates.inspect}"
 path
end
PrimaryExpr(path, parsed) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 580
def PrimaryExpr path, parsed
 case path
 when VARIABLE_REFERENCE
 varname = 1ドル
 path = $'
 parsed << :variable
 parsed << varname
 #arry << @variables[ varname ]
 when /^(\w[-\w]*)(?:\()/
 #puts "PrimaryExpr :: Function >>> #1ドル -- '#$''"
 fname = 1ドル
 tmp = $'
 #puts "#{fname} =~ #{NT.inspect}"
 return path if fname =~ NT
 path = tmp
 parsed << :function
 parsed << fname
 path = FunctionCall(path, parsed)
 when NUMBER
 #puts "LITERAL or NUMBER: #1ドル"
 varname = 1ドル.nil? ? 2ドル : 1ドル
 path = $'
 parsed << :literal
 parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
 when LITERAL
 #puts "LITERAL or NUMBER: #1ドル"
 varname = 1ドル.nil? ? 2ドル : 1ドル
 path = $'
 parsed << :literal
 parsed << varname
 when /^\(/ #/
 path, contents = get_group(path)
 contents = contents[1..-2]
 n = []
 OrExpr( contents, n )
 parsed.concat(n)
 end
 path
end
RelationalExpr(path, parsed) click to toggle source

| #RelationalExpr ('<' | '>' | '<=' | '>=') #AdditiveExpr | #AdditiveExpr

# File lib/rexml/parsers/xpathparser.rb, line 421
def RelationalExpr path, parsed
 #puts "RELATION >>> #{path}"
 n = []
 rest = AdditiveExpr( path, n )
 #puts "RELATION <<< #{rest}"
 if rest != path
 while rest =~ /^\s*([<>]=?)\s*/
 if 1ドル[0] == ?<
 sym = "lt"
 else
 sym = "gt"
 end
 sym << "eq" if 1ドル[-1] == ?=
 n = [ sym.intern, n, [] ]
 rest = AdditiveExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace(n)
 elsif n.size > 0
 parsed << n
 end
 rest
end
RelativeLocationPath(path, parsed) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 212
def RelativeLocationPath path, parsed
 #puts "RelativeLocationPath #{path}"
 while path.size > 0
 # (axis or @ or <child::>) nodetest predicate >
 # OR > / Step
 # (. or ..) >
 if path[0] == ?.
 if path[1] == ?.
 parsed << :parent
 parsed << :node
 path = path[2..-1]
 else
 parsed << :self
 parsed << :node
 path = path[1..-1]
 end
 else
 if path[0] == ?@
 #puts "ATTRIBUTE"
 parsed << :attribute
 path = path[1..-1]
 # Goto Nodetest
 elsif path =~ AXIS
 parsed << 1ドル.tr('-','_').intern
 path = $'
 # Goto Nodetest
 else
 parsed << :child
 end
 #puts "NODETESTING '#{path}'"
 n = []
 path = NodeTest( path, n)
 #puts "NODETEST RETURNED '#{path}'"
 if path[0] == ?[
 path = Predicate( path, n )
 end
 parsed.concat(n)
 end
 if path.size > 0
 if path[0] == ?/
 if path[1] == ?/
 parsed << :descendant_or_self
 parsed << :node
 path = path[2..-1]
 else
 path = path[1..-1]
 end
 else
 return path
 end
 end
 end
 return path
end
UnaryExpr(path, parsed) click to toggle source

| '-' #UnaryExpr | #UnionExpr

# File lib/rexml/parsers/xpathparser.rb, line 500
def UnaryExpr path, parsed
 path =~ /^(\-*)/
 path = $'
 if 1ドル and ((1ドル.size % 2) != 0)
 mult = -1
 else
 mult = 1
 end
 parsed << :neg if mult < 0
 #puts "UNARY >>> #{path}"
 n = []
 path = UnionExpr( path, n )
 #puts "UNARY <<< #{path}"
 parsed.concat( n )
 path
end
UnionExpr(path, parsed) click to toggle source

| #UnionExpr '|' #PathExpr | #PathExpr

# File lib/rexml/parsers/xpathparser.rb, line 520
def UnionExpr path, parsed
 #puts "UNION >>> #{path}"
 n = []
 rest = PathExpr( path, n )
 #puts "UNION <<< #{rest}"
 if rest != path
 while rest =~ /^\s*(\|)\s*/
 n = [ :union, n, [] ]
 rest = PathExpr( $', n[-1] )
 end
 end
 if parsed.size == 0 and n.size != 0
 parsed.replace( n )
 elsif n.size > 0
 parsed << n
 end
 rest
end
get_group(string) click to toggle source

#get_group( '[foo]bar' ) -> ['bar', '[foo]']

# File lib/rexml/parsers/xpathparser.rb, line 634
def get_group string
 ind = 0
 depth = 0
 st = string[0,1]
 en = (st == "(" ? ")" : "]")
 begin
 case string[ind,1]
 when st
 depth += 1
 when en
 depth -= 1
 end
 ind += 1
 end while depth > 0 and ind < string.length
 return nil unless depth==0
 [string[ind..-1], string[0..ind-1]]
end
parse_args( string ) click to toggle source
# File lib/rexml/parsers/xpathparser.rb, line 652
def parse_args( string )
 arguments = []
 ind = 0
 inquot = false
 inapos = false
 depth = 1
 begin
 case string[ind]
 when ?"
 inquot = !inquot unless inapos
 when ?'
 inapos = !inapos unless inquot
 else
 unless inquot or inapos
 case string[ind]
 when ?(
 depth += 1
 if depth == 1
 string = string[1..-1]
 ind -= 1
 end
 when ?)
 depth -= 1
 if depth == 0
 s = string[0,ind].strip
 arguments << s unless s == ""
 string = string[ind+1..-1]
 end
 when ?,
 if depth == 1
 s = string[0,ind].strip
 arguments << s unless s == ""
 string = string[ind+1..-1]
 ind = -1
 end
 end
 end
 end
 ind += 1
 end while depth > 0 and ind < string.length
 return nil unless depth==0
 [string,arguments]
end