class REXML::Parsers::XPathParser

你最好不要使用这个类。真的。请使用 XPath,它是这个类的包装器。相信我。你不会想在这里瞎逛的。这段代码中有奇怪的、黑暗的魔法在运作。当心。回去!趁现在还能回去!

常量

AXIS

RelativeLocationPath

|                                                    Step
  | (AXIS_NAME '::' | '@' | '')                     AxisSpecifier
    NodeTest
      Predicate
  | '.' | '..'                                      AbbreviatedStep
|  RelativeLocationPath '/' Step
| RelativeLocationPath '//' Step
LITERAL
LOCAL_NAME_WILDCARD
NODE_TYPE
NT
NUMBER
PI
PREFIX_WILDCARD
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
| '*' ':' NCNAME                                NameTest since XPath 2.0
| NODE_TYPE '(' ')'                             NodeType
| PI '(' LITERAL ')'                            PI
  | '[' expr ']'                                Predicate
QNAME
VARIABLE_REFERENCE

| VARIABLE_REFERENCE | ‘(’ expr ‘)’ | LITERAL | NUMBER | FunctionCall

公共实例方法

abbreviate(path_or_parsed) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 42
def abbreviate(path_or_parsed)
  if path_or_parsed.kind_of?(String)
    parsed = parse(path_or_parsed)
  else
    parsed = path_or_parsed
  end
  components = []
  component = nil
  while parsed.size > 0
    op = parsed.shift
    case op
    when :node
      component << "node()"
    when :attribute
      component = "@"
      components << component
    when :child
      component = ""
      components << component
    when :descendant_or_self
      next_op = parsed[0]
      if next_op == :node
        parsed.shift
        component = ""
        components << component
      else
        component = "descendant-or-self::"
        components << component
      end
    when :self
      next_op = parsed[0]
      if next_op == :node
        parsed.shift
        components << "."
      else
        component = "self::"
        components << component
      end
    when :parent
      next_op = parsed[0]
      if next_op == :node
        parsed.shift
        components << ".."
      else
        component = "parent::"
        components << component
      end
    when :any
      component << "*"
    when :text
      component << "text()"
    when :following, :following_sibling,
          :ancestor, :ancestor_or_self, :descendant,
          :namespace, :preceding, :preceding_sibling
      component = op.to_s.tr("_", "-") << "::"
      components << component
    when :qname
      prefix = parsed.shift
      name = parsed.shift
      component << prefix+":" if prefix.size > 0
      component << name
    when :predicate
      component << '['
      component << predicate_to_path(parsed.shift) {|x| abbreviate(x)}
      component << ']'
    when :document
      components << ""
    when :function
      component << parsed.shift
      component << "( "
      component << predicate_to_path(parsed.shift[0]) {|x| abbreviate(x)}
      component << " )"
    when :literal
      component << quote_literal(parsed.shift)
    else
      component << "UNKNOWN("
      component << op.inspect
      component << ")"
    end
  end
  case components
  when [""]
    "/"
  when ["", ""]
    "//"
  else
    components.join("/")
  end
end
expand(path_or_parsed) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 132
def expand(path_or_parsed)
  if path_or_parsed.kind_of?(String)
    parsed = parse(path_or_parsed)
  else
    parsed = path_or_parsed
  end
  path = ""
  document = false
  while parsed.size > 0
    op = parsed.shift
    case op
    when :node
      path << "node()"
    when :attribute, :child, :following, :following_sibling,
          :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
          :namespace, :preceding, :preceding_sibling, :self, :parent
      path << "/" unless path.size == 0
      path << op.to_s.tr("_", "-")
      path << "::"
    when :any
      path << "*"
    when :qname
      prefix = parsed.shift
      name = parsed.shift
      path << prefix+":" if prefix.size > 0
      path << name
    when :predicate
      path << '['
      path << predicate_to_path( parsed.shift ) { |x| expand(x) }
      path << ']'
    when :document
      document = true
    else
      path << "UNKNOWN("
      path << op.inspect
      path << ")"
    end
  end
  path = "/"+path if document
  path
end
namespaces=( namespaces ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 16
def namespaces=( namespaces )
  Functions::namespace_context = namespaces
  @namespaces = namespaces
end
parse(path) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 21
def parse path
  path = path.dup
  path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
  path.gsub!( /\s+([\]\)])/, '\1')
  parsed = []
  rest = OrExpr(path, parsed)
  if rest
    unless rest.strip.empty?
      raise ParseException.new("Garbage component exists at the end: " +
                               "<#{rest}>: <#{path}>")
    end
  end
  parsed
end
preciate_to_string(parsed, &block)

用于向后兼容

别名为:predicate_to_path
predicate(path) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 36
def predicate path
  parsed = []
  Predicate( "[#{path}]", parsed )
  parsed
end
predicate_to_path(parsed) { |parsed| ... } 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 174
def predicate_to_path(parsed, &block)
  path = ""
  case parsed[0]
  when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
    op = parsed.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_path( parsed.shift, &block )
    right = predicate_to_path( parsed.shift, &block )
    path << left
    path << " "
    path << op.to_s
    path << " "
    path << right
  when :function
    parsed.shift
    name = parsed.shift
    path << name
    path << "("
    parsed.shift.each_with_index do |argument, i|
      path << ", " if i > 0
      path << predicate_to_path(argument, &block)
    end
    path << ")"
  when :literal
    parsed.shift
    path << quote_literal(parsed.shift)
  else
    path << yield( parsed )
  end
  return path.squeeze(" ")
end
也别名为:preciate_to_string

私有实例方法

AdditiveExpr(path, parsed) 点击切换源代码

| AdditiveExpr (‘+’ | ‘-’) MultiplicativeExpr | MultiplicativeExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 505
def AdditiveExpr path, parsed
  n = []
  rest = MultiplicativeExpr( path, n )
  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) 点击切换源代码

| AndExpr S ‘and’ S EqualityExpr | EqualityExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 438
def AndExpr path, parsed
  n = []
  rest = EqualityExpr( path, n )
  if rest != path
    while rest =~ /^\s*( and )/
      n = [ :and, n, [] ]
      rest = EqualityExpr( $', n[-1] )
    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) 点击切换源代码

| EqualityExpr (‘=’ | ‘!=’) RelationalExpr | RelationalExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 457
def EqualityExpr path, parsed
  n = []
  rest = RelationalExpr( path, n )
  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) 点击切换源代码

| FilterExpr Predicate | PrimaryExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 608
def FilterExpr path, parsed
  n = []
  path_before_primary_expr = path
  path = PrimaryExpr(path, n)
  return path_before_primary_expr if path == path_before_primary_expr
  path = Predicate(path, n)
  parsed.concat(n)
  path
end
FunctionCall(rest, parsed) 点击切换源代码

| FUNCTION_NAME ‘(’ ( expr ( ‘,’ expr )* )? ‘)’

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 663
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) 点击切换源代码

LocationPath

| RelativeLocationPath
| '/' RelativeLocationPath?
| '//' RelativeLocationPath
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 243
def LocationPath path, parsed
  path = path.lstrip
  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
  return RelativeLocationPath( path, parsed ) if path.size > 0
end
MultiplicativeExpr(path, parsed) 点击切换源代码

| MultiplicativeExpr (‘*’ | S (‘div’ | ‘mod’) S) UnaryExpr | UnaryExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 528
def MultiplicativeExpr path, parsed
  n = []
  rest = UnaryExpr( path, n )
  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) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 343
def NodeTest path, parsed
  original_path = path
  path = path.lstrip
  case path
  when PREFIX_WILDCARD
    prefix = nil
    name = $1
    path = $'
    parsed << :qname
    parsed << prefix
    parsed << name
  when /^\*/
    path = $'
    parsed << :any
  when NODE_TYPE
    type = $1
    path = $'
    parsed << type.tr('-', '_').intern
  when PI
    path = $'
    literal = nil
    if path =~ /^\s*\)/
      path = $'
    else
      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 LOCAL_NAME_WILDCARD
    prefix = $1
    path = $'
    parsed << :namespace
    parsed << prefix
  when QNAME
    prefix = $1
    name = $2
    path = $'
    prefix = "" unless prefix
    parsed << :qname
    parsed << prefix
    parsed << name
  else
    path = original_path
  end
  return path
end
OrExpr(path, parsed) 点击切换源代码

| OrExpr S ‘or’ S AndExpr | AndExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 419
def OrExpr path, parsed
  n = []
  rest = AndExpr( path, n )
  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) 点击切换源代码

| LocationPath | FilterExpr (‘/’ | ‘//’) RelativeLocationPath

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 590
def PathExpr path, parsed
  path = path.lstrip
  n = []
  rest = FilterExpr( path, n )
  if rest != path
    if rest and rest[0] == ?/
      rest = RelativeLocationPath(rest, n)
      parsed.concat(n)
      return rest
    end
  end
  rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
  parsed.concat(n)
  return rest
end
Predicate(path, parsed) 点击切换源代码

在谓词上过滤提供的节点集

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 395
def Predicate path, parsed
  original_path = path
  path = path.lstrip
  return original_path unless path[0] == ?[
  predicates = []
  while path[0] == ?[
    path, expr = get_group(path)
    predicates << expr[1..-2] if expr
  end
  predicates.each{ |pred|
    preds = []
    parsed << :predicate
    parsed << preds
    OrExpr(pred, preds)
  }
  path
end
PrimaryExpr(path, parsed) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 626
def PrimaryExpr path, parsed
  case path
  when VARIABLE_REFERENCE
    varname = $1
    path = $'
    parsed << :variable
    parsed << varname
    #arry << @variables[ varname ]
  when /^(\w[-\w]*)(?:\()/
    fname = $1
    tmp = $'
    return path if fname =~ NT
    path = tmp
    parsed << :function
    parsed << fname
    path = FunctionCall(path, parsed)
  when NUMBER
    varname = $1.nil? ? $2 : $1
    path = $'
    parsed << :literal
    parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
  when LITERAL
    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) 点击切换源代码

| RelationalExpr (‘<’ | ‘>’ | ‘<=’ | ‘>=’) AdditiveExpr | AdditiveExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 480
def RelationalExpr path, parsed
  n = []
  rest = AdditiveExpr( path, n )
  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) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 267
def RelativeLocationPath path, parsed
  loop do
    original_path = path
    path = path.lstrip

    return original_path if path.empty?

    # (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
      path_before_axis_specifier = path
      parsed_not_abberviated = []
      if path[0] == ?@
        parsed_not_abberviated << :attribute
        path = path[1..-1]
        # Goto Nodetest
      elsif path =~ AXIS
        parsed_not_abberviated << $1.tr('-','_').intern
        path = $'
        # Goto Nodetest
      else
        parsed_not_abberviated << :child
      end

      path_before_node_test = path
      path = NodeTest(path, parsed_not_abberviated)
      if path == path_before_node_test
        return path_before_axis_specifier
      end
      path = Predicate(path, parsed_not_abberviated)

      parsed.concat(parsed_not_abberviated)
    end

    original_path = path
    path = path.lstrip
    return original_path if path.empty?

    return original_path if path[0] != ?/

    if path[1] == ?/
      parsed << :descendant_or_self
      parsed << :node
      path = path[2..-1]
    else
      path = path[1..-1]
    end
  end
end
UnaryExpr(path, parsed) 点击切换源代码

| ‘-’ UnaryExpr | UnionExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 553
def UnaryExpr path, parsed
  path =~ /^(\-*)/
  path = $'
  if $1 and (($1.size % 2) != 0)
    mult = -1
  else
    mult = 1
  end
  parsed << :neg if mult < 0

  n = []
  path = UnionExpr( path, n )
  parsed.concat( n )
  path
end
UnionExpr(path, parsed) 点击切换源代码

| UnionExpr ‘|’ PathExpr | PathExpr

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 571
def UnionExpr path, parsed
  n = []
  rest = PathExpr( path, n )
  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) 点击切换源代码

get_group( ‘[foo]bar’ ) -> [‘bar’, ‘[foo]’]

# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 676
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 ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 694
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
quote_literal( literal ) 点击切换源代码
# File rexml-3.4.0/lib/rexml/parsers/xpathparser.rb, line 224
def quote_literal( literal )
  case literal
  when String
    # XPath 1.0 does not support escape characters.
    # Assumes literal does not contain both single and double quotes.
    if literal.include?("'")
      "\"#{literal}\""
    else
      "'#{literal}'"
    end
  else
    literal.inspect
  end
end