Class: REXML::Parsers::XPathParser

Inherits:
Object
  • Object
show all
Includes:
XMLTokens
Defined in:
lib/rexml/parsers/xpathparser.rb

Overview

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!

Constant Summary collapse

LITERAL =
/^'([^']*)'|^"([^"]*)"/u

Constants included from XMLTokens

XMLTokens::NAME, XMLTokens::NAMECHAR, XMLTokens::NAME_CHAR, XMLTokens::NAME_START_CHAR, XMLTokens::NAME_STR, XMLTokens::NCNAME_STR, XMLTokens::NMTOKEN, XMLTokens::NMTOKENS, XMLTokens::REFERENCE

Instance Method Summary collapse

Instance Method Details

#abbreviate(path_or_parsed) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File '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) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File '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) ⇒ Object



16
17
18
19
# File 'lib/rexml/parsers/xpathparser.rb', line 16

def namespaces=( namespaces )
  Functions::namespace_context = namespaces
  @namespaces = namespaces
end

#parse(path) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File '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

#predicate(path) ⇒ Object



36
37
38
39
40
# File 'lib/rexml/parsers/xpathparser.rb', line 36

def predicate path
  parsed = []
  Predicate( "[#{path}]", parsed )
  parsed
end

#predicate_to_path(parsed, &block) ⇒ Object Also known as: preciate_to_string



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File '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