rexml 3.2.0 → 3.2.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rexml might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/NEWS.md +111 -1
- data/README.md +4 -16
- data/doc/rexml/context.rdoc +143 -0
- data/doc/rexml/tasks/rdoc/child.rdoc +87 -0
- data/doc/rexml/tasks/rdoc/document.rdoc +276 -0
- data/doc/rexml/tasks/rdoc/element.rdoc +602 -0
- data/doc/rexml/tasks/rdoc/node.rdoc +97 -0
- data/doc/rexml/tasks/rdoc/parent.rdoc +267 -0
- data/doc/rexml/tasks/tocs/child_toc.rdoc +12 -0
- data/doc/rexml/tasks/tocs/document_toc.rdoc +30 -0
- data/doc/rexml/tasks/tocs/element_toc.rdoc +55 -0
- data/doc/rexml/tasks/tocs/master_toc.rdoc +135 -0
- data/doc/rexml/tasks/tocs/node_toc.rdoc +16 -0
- data/doc/rexml/tasks/tocs/parent_toc.rdoc +25 -0
- data/lib/rexml.rb +3 -0
- data/lib/rexml/doctype.rb +55 -31
- data/lib/rexml/document.rb +194 -34
- data/lib/rexml/element.rb +1786 -456
- data/lib/rexml/entity.rb +1 -1
- data/lib/rexml/functions.rb +27 -27
- data/lib/rexml/light/node.rb +0 -8
- data/lib/rexml/parsers/baseparser.rb +143 -39
- data/lib/rexml/parsers/xpathparser.rb +25 -11
- data/lib/rexml/rexml.rb +27 -22
- data/lib/rexml/source.rb +2 -2
- data/lib/rexml/text.rb +5 -5
- data/lib/rexml/xmldecl.rb +1 -0
- data/lib/rexml/xpath_parser.rb +185 -143
- metadata +49 -11
- data/.gitignore +0 -9
- data/.travis.yml +0 -24
- data/Gemfile +0 -6
- data/Rakefile +0 -8
- data/lib/rexml/syncenumerator.rb +0 -33
- data/rexml.gemspec +0 -85
data/lib/rexml/rexml.rb
CHANGED
@@ -1,30 +1,35 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
# frozen_string_literal: false
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
3
|
+
#
|
4
|
+
# \Module \REXML provides classes and methods for parsing,
|
5
|
+
# editing, and generating XML.
|
6
|
+
#
|
7
|
+
# == Implementation
|
8
|
+
#
|
9
|
+
# \REXML:
|
10
|
+
# - Is pure Ruby.
|
11
|
+
# - Provides tree, stream, SAX2, pull, and lightweight APIs.
|
12
|
+
# - Conforms to {XML version 1.0}[https://www.w3.org/TR/REC-xml/].
|
13
|
+
# - Fully implements {XPath version 1.0}[http://www.w3c.org/tr/xpath].
|
14
|
+
# - Is {non-validating}[https://www.w3.org/TR/xml/].
|
15
|
+
# - Passes 100% of the non-validating {Oasis tests}[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml].
|
16
|
+
#
|
17
|
+
# == In a Hurry?
|
18
|
+
#
|
19
|
+
# If you're somewhat familiar with XML
|
20
|
+
# and have a particular task in mind,
|
21
|
+
# you may want to see {the tasks pages}[doc/rexml/tasks/tocs/master_toc_rdoc.html].
|
22
|
+
#
|
23
|
+
# == API
|
24
|
+
#
|
25
|
+
# Among the most important classes for using \REXML are:
|
26
|
+
# - REXML::Document.
|
27
|
+
# - REXML::Element.
|
28
|
+
#
|
24
29
|
module REXML
|
25
30
|
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
|
26
31
|
DATE = "2008/019"
|
27
|
-
VERSION = "3.2.
|
32
|
+
VERSION = "3.2.5"
|
28
33
|
REVISION = ""
|
29
34
|
|
30
35
|
Copyright = COPYRIGHT
|
data/lib/rexml/source.rb
CHANGED
@@ -200,7 +200,7 @@ module REXML
|
|
200
200
|
end
|
201
201
|
rv = super
|
202
202
|
end
|
203
|
-
rv.taint
|
203
|
+
rv.taint if RUBY_VERSION < '2.7'
|
204
204
|
rv
|
205
205
|
end
|
206
206
|
|
@@ -228,7 +228,7 @@ module REXML
|
|
228
228
|
@source = nil
|
229
229
|
end
|
230
230
|
end
|
231
|
-
rv.taint
|
231
|
+
rv.taint if RUBY_VERSION < '2.7'
|
232
232
|
rv
|
233
233
|
end
|
234
234
|
|
data/lib/rexml/text.rb
CHANGED
@@ -109,7 +109,7 @@ module REXML
|
|
109
109
|
@string = arg.instance_variable_get(:@string).dup
|
110
110
|
@raw = arg.raw
|
111
111
|
@entity_filter = arg.instance_variable_get(:@entity_filter)
|
112
|
-
|
112
|
+
else
|
113
113
|
raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})"
|
114
114
|
end
|
115
115
|
|
@@ -137,7 +137,7 @@ module REXML
|
|
137
137
|
case c.ord
|
138
138
|
when *VALID_CHAR
|
139
139
|
else
|
140
|
-
raise "Illegal character #{c.inspect} in raw string
|
140
|
+
raise "Illegal character #{c.inspect} in raw string #{string.inspect}"
|
141
141
|
end
|
142
142
|
end
|
143
143
|
else
|
@@ -145,7 +145,7 @@ module REXML
|
|
145
145
|
case c.unpack('U')
|
146
146
|
when *VALID_CHAR
|
147
147
|
else
|
148
|
-
raise "Illegal character #{c.inspect} in raw string
|
148
|
+
raise "Illegal character #{c.inspect} in raw string #{string.inspect}"
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -154,13 +154,13 @@ module REXML
|
|
154
154
|
# context sensitive
|
155
155
|
string.scan(pattern) do
|
156
156
|
if $1[-1] != ?;
|
157
|
-
raise "Illegal character
|
157
|
+
raise "Illegal character #{$1.inspect} in raw string #{string.inspect}"
|
158
158
|
elsif $1[0] == ?&
|
159
159
|
if $5 and $5[0] == ?#
|
160
160
|
case ($5[1] == ?x ? $5[2..-1].to_i(16) : $5[1..-1].to_i)
|
161
161
|
when *VALID_CHAR
|
162
162
|
else
|
163
|
-
raise "Illegal character
|
163
|
+
raise "Illegal character #{$1.inspect} in raw string #{string.inspect}"
|
164
164
|
end
|
165
165
|
# FIXME: below can't work but this needs API change.
|
166
166
|
# elsif @parent and $3 and !SUBSTITUTES.include?($1)
|
data/lib/rexml/xmldecl.rb
CHANGED
data/lib/rexml/xpath_parser.rb
CHANGED
@@ -1,43 +1,51 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
|
2
5
|
require_relative 'namespace'
|
3
6
|
require_relative 'xmltokens'
|
4
7
|
require_relative 'attribute'
|
5
|
-
require_relative 'syncenumerator'
|
6
8
|
require_relative 'parsers/xpathparser'
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
10
|
+
module REXML
|
11
|
+
module DClonable
|
12
|
+
refine Object do
|
13
|
+
# provides a unified +clone+ operation, for REXML::XPathParser
|
14
|
+
# to use across multiple Object types
|
15
|
+
def dclone
|
16
|
+
clone
|
17
|
+
end
|
18
|
+
end
|
19
|
+
refine Symbol do
|
20
|
+
# provides a unified +clone+ operation, for REXML::XPathParser
|
21
|
+
# to use across multiple Object types
|
22
|
+
def dclone ; self ; end
|
23
|
+
end
|
24
|
+
refine Integer do
|
25
|
+
# provides a unified +clone+ operation, for REXML::XPathParser
|
26
|
+
# to use across multiple Object types
|
27
|
+
def dclone ; self ; end
|
28
|
+
end
|
29
|
+
refine Float do
|
30
|
+
# provides a unified +clone+ operation, for REXML::XPathParser
|
31
|
+
# to use across multiple Object types
|
32
|
+
def dclone ; self ; end
|
33
|
+
end
|
34
|
+
refine Array do
|
35
|
+
# provides a unified +clone+ operation, for REXML::XPathParser
|
36
|
+
# to use across multiple Object+ types
|
37
|
+
def dclone
|
38
|
+
klone = self.clone
|
39
|
+
klone.clear
|
40
|
+
self.each{|v| klone << v.dclone}
|
41
|
+
klone
|
42
|
+
end
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
47
|
+
using REXML::DClonable
|
48
|
+
|
41
49
|
module REXML
|
42
50
|
# You don't want to use this class. Really. Use XPath, which is a wrapper
|
43
51
|
# for this class. Believe me. You don't want to poke around in here.
|
@@ -47,7 +55,10 @@ module REXML
|
|
47
55
|
include XMLTokens
|
48
56
|
LITERAL = /^'([^']*)'|^"([^"]*)"/u
|
49
57
|
|
58
|
+
DEBUG = (ENV["REXML_XPATH_PARSER_DEBUG"] == "true")
|
59
|
+
|
50
60
|
def initialize(strict: false)
|
61
|
+
@debug = DEBUG
|
51
62
|
@parser = REXML::Parsers::XPathParser.new
|
52
63
|
@namespaces = nil
|
53
64
|
@variables = {}
|
@@ -135,7 +146,7 @@ module REXML
|
|
135
146
|
when Array # nodeset
|
136
147
|
unnode(result)
|
137
148
|
else
|
138
|
-
result
|
149
|
+
[result]
|
139
150
|
end
|
140
151
|
end
|
141
152
|
|
@@ -162,10 +173,10 @@ module REXML
|
|
162
173
|
# Expr takes a stack of path elements and a set of nodes (either a Parent
|
163
174
|
# or an Array and returns an Array of matching nodes
|
164
175
|
def expr( path_stack, nodeset, context=nil )
|
165
|
-
|
176
|
+
enter(:expr, path_stack, nodeset) if @debug
|
166
177
|
return nodeset if path_stack.length == 0 || nodeset.length == 0
|
167
178
|
while path_stack.length > 0
|
168
|
-
|
179
|
+
trace(:while, path_stack, nodeset) if @debug
|
169
180
|
if nodeset.length == 0
|
170
181
|
path_stack.clear
|
171
182
|
return []
|
@@ -184,7 +195,7 @@ module REXML
|
|
184
195
|
child(nodeset)
|
185
196
|
end
|
186
197
|
when :literal
|
187
|
-
|
198
|
+
trace(:literal, path_stack, nodeset) if @debug
|
188
199
|
return path_stack.shift
|
189
200
|
when :attribute
|
190
201
|
nodeset = step(path_stack, any_type: :attribute) do
|
@@ -335,26 +346,24 @@ module REXML
|
|
335
346
|
var_name = path_stack.shift
|
336
347
|
return [@variables[var_name]]
|
337
348
|
|
338
|
-
|
339
|
-
# TODO: Special case for :or and :and -- not evaluate the right
|
340
|
-
# operand if the left alone determines result (i.e. is true for
|
341
|
-
# :or and false for :and).
|
342
|
-
when :eq, :neq, :lt, :lteq, :gt, :gteq, :or
|
349
|
+
when :eq, :neq, :lt, :lteq, :gt, :gteq
|
343
350
|
left = expr( path_stack.shift, nodeset.dup, context )
|
344
351
|
right = expr( path_stack.shift, nodeset.dup, context )
|
345
352
|
res = equality_relational_compare( left, op, right )
|
346
|
-
|
353
|
+
trace(op, left, right, res) if @debug
|
347
354
|
return res
|
348
355
|
|
356
|
+
when :or
|
357
|
+
left = expr(path_stack.shift, nodeset.dup, context)
|
358
|
+
return true if Functions.boolean(left)
|
359
|
+
right = expr(path_stack.shift, nodeset.dup, context)
|
360
|
+
return Functions.boolean(right)
|
361
|
+
|
349
362
|
when :and
|
350
|
-
left = expr(
|
351
|
-
return
|
352
|
-
|
353
|
-
|
354
|
-
end
|
355
|
-
right = expr( path_stack.shift, nodeset.dup, context )
|
356
|
-
res = equality_relational_compare( left, op, right )
|
357
|
-
return res
|
363
|
+
left = expr(path_stack.shift, nodeset.dup, context)
|
364
|
+
return false unless Functions.boolean(left)
|
365
|
+
right = expr(path_stack.shift, nodeset.dup, context)
|
366
|
+
return Functions.boolean(right)
|
358
367
|
|
359
368
|
when :div, :mod, :mult, :plus, :minus
|
360
369
|
left = expr(path_stack.shift, nodeset, context)
|
@@ -391,45 +400,48 @@ module REXML
|
|
391
400
|
when :function
|
392
401
|
func_name = path_stack.shift.tr('-','_')
|
393
402
|
arguments = path_stack.shift
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
result
|
403
|
+
|
404
|
+
if nodeset.size != 1
|
405
|
+
message = "[BUG] Node set size must be 1 for function call: "
|
406
|
+
message += "<#{func_name}>: <#{nodeset.inspect}>: "
|
407
|
+
message += "<#{arguments.inspect}>"
|
408
|
+
raise message
|
409
|
+
end
|
410
|
+
|
411
|
+
node = nodeset.first
|
412
|
+
if context
|
413
|
+
target_context = context
|
414
|
+
else
|
415
|
+
target_context = {:size => nodeset.size}
|
416
|
+
if node.is_a?(XPathNode)
|
417
|
+
target_context[:node] = node.raw_node
|
418
|
+
target_context[:index] = node.position
|
419
|
+
else
|
420
|
+
target_context[:node] = node
|
421
|
+
target_context[:index] = 1
|
414
422
|
end
|
415
|
-
Functions.context = cont
|
416
|
-
res << Functions.send( func_name, *args )
|
417
423
|
end
|
418
|
-
|
424
|
+
args = arguments.dclone.collect do |arg|
|
425
|
+
result = expr(arg, nodeset, target_context)
|
426
|
+
result = unnode(result) if result.is_a?(Array)
|
427
|
+
result
|
428
|
+
end
|
429
|
+
Functions.context = target_context
|
430
|
+
return Functions.send(func_name, *args)
|
419
431
|
|
420
432
|
else
|
421
433
|
raise "[BUG] Unexpected path: <#{op.inspect}>: <#{path_stack.inspect}>"
|
422
434
|
end
|
423
435
|
end # while
|
424
436
|
return nodeset
|
425
|
-
|
426
|
-
|
437
|
+
ensure
|
438
|
+
leave(:expr, path_stack, nodeset) if @debug
|
427
439
|
end
|
428
440
|
|
429
441
|
def step(path_stack, any_type: :element, order: :forward)
|
430
442
|
nodesets = yield
|
431
443
|
begin
|
432
|
-
|
444
|
+
enter(:step, path_stack, nodesets) if @debug
|
433
445
|
nodesets = node_test(path_stack, nodesets, any_type: any_type)
|
434
446
|
while path_stack[0] == :predicate
|
435
447
|
path_stack.shift # :predicate
|
@@ -457,13 +469,13 @@ module REXML
|
|
457
469
|
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
|
458
470
|
end
|
459
471
|
new_nodeset
|
460
|
-
|
461
|
-
|
472
|
+
ensure
|
473
|
+
leave(:step, path_stack, new_nodeset) if @debug
|
462
474
|
end
|
463
475
|
end
|
464
476
|
|
465
477
|
def node_test(path_stack, nodesets, any_type: :element)
|
466
|
-
|
478
|
+
enter(:node_test, path_stack, nodesets) if @debug
|
467
479
|
operator = path_stack.shift
|
468
480
|
case operator
|
469
481
|
when :qname
|
@@ -563,8 +575,8 @@ module REXML
|
|
563
575
|
raise message
|
564
576
|
end
|
565
577
|
new_nodesets
|
566
|
-
|
567
|
-
|
578
|
+
ensure
|
579
|
+
leave(:node_test, path_stack, new_nodesets) if @debug
|
568
580
|
end
|
569
581
|
|
570
582
|
def filter_nodeset(nodeset)
|
@@ -577,7 +589,7 @@ module REXML
|
|
577
589
|
end
|
578
590
|
|
579
591
|
def evaluate_predicate(expression, nodesets)
|
580
|
-
|
592
|
+
enter(:predicate, expression, nodesets) if @debug
|
581
593
|
new_nodesets = nodesets.collect do |nodeset|
|
582
594
|
new_nodeset = []
|
583
595
|
subcontext = { :size => nodeset.size }
|
@@ -590,7 +602,7 @@ module REXML
|
|
590
602
|
subcontext[:index] = index + 1
|
591
603
|
end
|
592
604
|
result = expr(expression.dclone, [node], subcontext)
|
593
|
-
|
605
|
+
trace(:predicate_evaluate, expression, node, subcontext, result) if @debug
|
594
606
|
result = result[0] if result.kind_of? Array and result.length == 1
|
595
607
|
if result.kind_of? Numeric
|
596
608
|
if result == node.position
|
@@ -611,13 +623,15 @@ module REXML
|
|
611
623
|
new_nodeset
|
612
624
|
end
|
613
625
|
new_nodesets
|
614
|
-
|
615
|
-
|
626
|
+
ensure
|
627
|
+
leave(:predicate, new_nodesets) if @debug
|
616
628
|
end
|
617
629
|
|
618
630
|
def trace(*args)
|
619
631
|
indent = " " * @nest
|
620
|
-
|
632
|
+
PP.pp(args, "").each_line do |line|
|
633
|
+
puts("#{indent}#{line}")
|
634
|
+
end
|
621
635
|
end
|
622
636
|
|
623
637
|
def enter(tag, *args)
|
@@ -798,31 +812,28 @@ module REXML
|
|
798
812
|
end
|
799
813
|
end
|
800
814
|
|
801
|
-
def equality_relational_compare(
|
815
|
+
def equality_relational_compare(set1, op, set2)
|
802
816
|
set1 = unnode(set1) if set1.is_a?(Array)
|
803
817
|
set2 = unnode(set2) if set2.is_a?(Array)
|
818
|
+
|
804
819
|
if set1.kind_of? Array and set2.kind_of? Array
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
res << compare( i1, op, i2 )
|
815
|
-
}
|
816
|
-
return res
|
820
|
+
# If both objects to be compared are node-sets, then the
|
821
|
+
# comparison will be true if and only if there is a node in the
|
822
|
+
# first node-set and a node in the second node-set such that the
|
823
|
+
# result of performing the comparison on the string-values of
|
824
|
+
# the two nodes is true.
|
825
|
+
set1.product(set2).any? do |node1, node2|
|
826
|
+
node_string1 = Functions.string(node1)
|
827
|
+
node_string2 = Functions.string(node2)
|
828
|
+
compare(node_string1, op, node_string2)
|
817
829
|
end
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
if set1.kind_of? Array or set2.kind_of? Array
|
830
|
+
elsif set1.kind_of? Array or set2.kind_of? Array
|
831
|
+
# If one is nodeset and other is number, compare number to each item
|
832
|
+
# in nodeset s.t. number op number(string(item))
|
833
|
+
# If one is nodeset and other is string, compare string to each item
|
834
|
+
# in nodeset s.t. string op string(item)
|
835
|
+
# If one is nodeset and other is boolean, compare boolean to each item
|
836
|
+
# in nodeset s.t. boolean op boolean(item)
|
826
837
|
if set1.kind_of? Array
|
827
838
|
a = set1
|
828
839
|
b = set2
|
@@ -833,15 +844,23 @@ module REXML
|
|
833
844
|
|
834
845
|
case b
|
835
846
|
when true, false
|
836
|
-
|
847
|
+
each_unnode(a).any? do |unnoded|
|
848
|
+
compare(Functions.boolean(unnoded), op, b)
|
849
|
+
end
|
837
850
|
when Numeric
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
851
|
+
each_unnode(a).any? do |unnoded|
|
852
|
+
compare(Functions.number(unnoded), op, b)
|
853
|
+
end
|
854
|
+
when /\A\d+(\.\d+)?\z/
|
855
|
+
b = Functions.number(b)
|
856
|
+
each_unnode(a).any? do |unnoded|
|
857
|
+
compare(Functions.number(unnoded), op, b)
|
858
|
+
end
|
842
859
|
else
|
843
|
-
b = Functions::string(
|
844
|
-
|
860
|
+
b = Functions::string(b)
|
861
|
+
each_unnode(a).any? do |unnoded|
|
862
|
+
compare(Functions::string(unnoded), op, b)
|
863
|
+
end
|
845
864
|
end
|
846
865
|
else
|
847
866
|
# If neither is nodeset,
|
@@ -851,34 +870,52 @@ module REXML
|
|
851
870
|
# Else, convert to string
|
852
871
|
# Else
|
853
872
|
# Convert both to numbers and compare
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
873
|
+
compare(set1, op, set2)
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
def value_type(value)
|
878
|
+
case value
|
879
|
+
when true, false
|
880
|
+
:boolean
|
881
|
+
when Numeric
|
882
|
+
:number
|
883
|
+
when String
|
884
|
+
:string
|
885
|
+
else
|
886
|
+
raise "[BUG] Unexpected value type: <#{value.inspect}>"
|
887
|
+
end
|
888
|
+
end
|
889
|
+
|
890
|
+
def normalize_compare_values(a, operator, b)
|
891
|
+
a_type = value_type(a)
|
892
|
+
b_type = value_type(b)
|
893
|
+
case operator
|
894
|
+
when :eq, :neq
|
895
|
+
if a_type == :boolean or b_type == :boolean
|
896
|
+
a = Functions.boolean(a) unless a_type == :boolean
|
897
|
+
b = Functions.boolean(b) unless b_type == :boolean
|
898
|
+
elsif a_type == :number or b_type == :number
|
899
|
+
a = Functions.number(a) unless a_type == :number
|
900
|
+
b = Functions.number(b) unless b_type == :number
|
861
901
|
else
|
862
|
-
|
863
|
-
|
864
|
-
set1 = Functions::number( s1 )
|
865
|
-
set2 = Functions::number( s2 )
|
866
|
-
else
|
867
|
-
set1 = Functions::string( set1 )
|
868
|
-
set2 = Functions::string( set2 )
|
869
|
-
end
|
870
|
-
else
|
871
|
-
set1 = Functions::number( set1 )
|
872
|
-
set2 = Functions::number( set2 )
|
873
|
-
end
|
902
|
+
a = Functions.string(a) unless a_type == :string
|
903
|
+
b = Functions.string(b) unless b_type == :string
|
874
904
|
end
|
875
|
-
|
905
|
+
when :lt, :lteq, :gt, :gteq
|
906
|
+
a = Functions.number(a) unless a_type == :number
|
907
|
+
b = Functions.number(b) unless b_type == :number
|
908
|
+
else
|
909
|
+
message = "[BUG] Unexpected compare operator: " +
|
910
|
+
"<#{operator.inspect}>: <#{a.inspect}>: <#{b.inspect}>"
|
911
|
+
raise message
|
876
912
|
end
|
877
|
-
|
913
|
+
[a, b]
|
878
914
|
end
|
879
915
|
|
880
|
-
def compare
|
881
|
-
|
916
|
+
def compare(a, operator, b)
|
917
|
+
a, b = normalize_compare_values(a, operator, b)
|
918
|
+
case operator
|
882
919
|
when :eq
|
883
920
|
a == b
|
884
921
|
when :neq
|
@@ -891,22 +928,27 @@ module REXML
|
|
891
928
|
a > b
|
892
929
|
when :gteq
|
893
930
|
a >= b
|
894
|
-
when :and
|
895
|
-
a and b
|
896
|
-
when :or
|
897
|
-
a or b
|
898
931
|
else
|
899
|
-
|
932
|
+
message = "[BUG] Unexpected compare operator: " +
|
933
|
+
"<#{operator.inspect}>: <#{a.inspect}>: <#{b.inspect}>"
|
934
|
+
raise message
|
900
935
|
end
|
901
936
|
end
|
902
937
|
|
903
|
-
def
|
904
|
-
nodeset
|
938
|
+
def each_unnode(nodeset)
|
939
|
+
return to_enum(__method__, nodeset) unless block_given?
|
940
|
+
nodeset.each do |node|
|
905
941
|
if node.is_a?(XPathNode)
|
906
942
|
unnoded = node.raw_node
|
907
943
|
else
|
908
944
|
unnoded = node
|
909
945
|
end
|
946
|
+
yield(unnoded)
|
947
|
+
end
|
948
|
+
end
|
949
|
+
|
950
|
+
def unnode(nodeset)
|
951
|
+
each_unnode(nodeset).collect do |unnoded|
|
910
952
|
unnoded = yield(unnoded) if block_given?
|
911
953
|
unnoded
|
912
954
|
end
|