5
5
require_relative 'namespace'
6
6
require_relative 'xmltokens'
7
7
require_relative 'attribute'
8
- require_relative 'syncenumerator'
9
8
require_relative 'parsers/xpathparser'
10
9
11
10
class Object
@@ -141,7 +140,7 @@ def match(path_stack, nodeset)
141
140
when Array # nodeset
142
141
unnode ( result )
143
142
else
144
- result
143
+ [ result ]
145
144
end
146
145
end
147
146
@@ -341,26 +340,24 @@ def expr( path_stack, nodeset, context=nil )
341
340
var_name = path_stack . shift
342
341
return [ @variables [ var_name ] ]
343
342
344
- # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
345
- # TODO: Special case for :or and :and -- not evaluate the right
346
- # operand if the left alone determines result (i.e. is true for
347
- # :or and false for :and).
348
- when :eq , :neq , :lt , :lteq , :gt , :gteq , :or
343
+ when :eq , :neq , :lt , :lteq , :gt , :gteq
349
344
left = expr ( path_stack . shift , nodeset . dup , context )
350
345
right = expr ( path_stack . shift , nodeset . dup , context )
351
346
res = equality_relational_compare ( left , op , right )
352
347
trace ( op , left , right , res ) if @debug
353
348
return res
354
349
350
+ when :or
351
+ left = expr ( path_stack . shift , nodeset . dup , context )
352
+ return true if Functions . boolean ( left )
353
+ right = expr ( path_stack . shift , nodeset . dup , context )
354
+ return Functions . boolean ( right )
355
+
355
356
when :and
356
- left = expr ( path_stack . shift , nodeset . dup , context )
357
- return [ ] unless left
358
- if left . respond_to? ( :inject ) and !left . inject ( false ) { |a , b | a | b }
359
- return [ ]
360
- end
361
- right = expr ( path_stack . shift , nodeset . dup , context )
362
- res = equality_relational_compare ( left , op , right )
363
- return res
357
+ left = expr ( path_stack . shift , nodeset . dup , context )
358
+ return false unless Functions . boolean ( left )
359
+ right = expr ( path_stack . shift , nodeset . dup , context )
360
+ return Functions . boolean ( right )
364
361
365
362
when :div , :mod , :mult , :plus , :minus
366
363
left = expr ( path_stack . shift , nodeset , context )
@@ -397,31 +394,34 @@ def expr( path_stack, nodeset, context=nil )
397
394
when :function
398
395
func_name = path_stack . shift . tr ( '-' , '_' )
399
396
arguments = path_stack . shift
400
- subcontext = context ? nil : { :size => nodeset . size }
401
-
402
- res = [ ]
403
- cont = context
404
- nodeset . each_with_index do |node , i |
405
- if subcontext
406
- if node . is_a? ( XPathNode )
407
- subcontext [ :node ] = node . raw_node
408
- subcontext [ :index ] = node . position
409
- else
410
- subcontext [ :node ] = node
411
- subcontext [ :index ] = i
412
- end
413
- cont = subcontext
414
- end
415
- arg_clone = arguments . dclone
416
- args = arg_clone . collect do |arg |
417
- result = expr ( arg , [ node ] , cont )
418
- result = unnode ( result ) if result . is_a? ( Array )
419
- result
397
+
398
+ if nodeset . size != 1
399
+ message = "[BUG] Node set size must be 1 for function call: "
400
+ message += "<#{ func_name } >: <#{ nodeset . inspect } >: "
401
+ message += "<#{ arguments . inspect } >"
402
+ raise message
403
+ end
404
+
405
+ node = nodeset . first
406
+ if context
407
+ target_context = context
408
+ else
409
+ target_context = { :size => nodeset . size }
410
+ if node . is_a? ( XPathNode )
411
+ target_context [ :node ] = node . raw_node
412
+ target_context [ :index ] = node . position
413
+ else
414
+ target_context [ :node ] = node
415
+ target_context [ :index ] = 1
420
416
end
421
- Functions . context = cont
422
- res << Functions . send ( func_name , *args )
423
417
end
424
- return res
418
+ args = arguments . dclone . collect do |arg |
419
+ result = expr ( arg , nodeset , target_context )
420
+ result = unnode ( result ) if result . is_a? ( Array )
421
+ result
422
+ end
423
+ Functions . context = target_context
424
+ return Functions . send ( func_name , *args )
425
425
426
426
else
427
427
raise "[BUG] Unexpected path: <#{ op . inspect } >: <#{ path_stack . inspect } >"
@@ -806,31 +806,28 @@ def norm b
806
806
end
807
807
end
808
808
809
- def equality_relational_compare ( set1 , op , set2 )
809
+ def equality_relational_compare ( set1 , op , set2 )
810
810
set1 = unnode ( set1 ) if set1 . is_a? ( Array )
811
811
set2 = unnode ( set2 ) if set2 . is_a? ( Array )
812
+
812
813
if set1 . kind_of? Array and set2 . kind_of? Array
813
- if set1 . size == 0 or set2 . size == 0
814
- nd = set1 . size ==0 ? set2 : set1
815
- rv = nd . collect { |il | compare ( il , op , nil ) }
816
- return rv
817
- else
818
- res = [ ]
819
- SyncEnumerator . new ( set1 , set2 ) . each { |i1 , i2 |
820
- i1 = norm ( i1 )
821
- i2 = norm ( i2 )
822
- res << compare ( i1 , op , i2 )
823
- }
824
- return res
814
+ # If both objects to be compared are node-sets, then the
815
+ # comparison will be true if and only if there is a node in the
816
+ # first node-set and a node in the second node-set such that the
817
+ # result of performing the comparison on the string-values of
818
+ # the two nodes is true.
819
+ set1 . product ( set2 ) . any? do |node1 , node2 |
820
+ node_string1 = Functions . string ( node1 )
821
+ node_string2 = Functions . string ( node2 )
822
+ compare ( node_string1 , op , node_string2 )
825
823
end
826
- end
827
- # If one is nodeset and other is number, compare number to each item
828
- # in nodeset s.t. number op number(string(item))
829
- # If one is nodeset and other is string, compare string to each item
830
- # in nodeset s.t. string op string(item)
831
- # If one is nodeset and other is boolean, compare boolean to each item
832
- # in nodeset s.t. boolean op boolean(item)
833
- if set1 . kind_of? Array or set2 . kind_of? Array
824
+ elsif set1 . kind_of? Array or set2 . kind_of? Array
825
+ # If one is nodeset and other is number, compare number to each item
826
+ # in nodeset s.t. number op number(string(item))
827
+ # If one is nodeset and other is string, compare string to each item
828
+ # in nodeset s.t. string op string(item)
829
+ # If one is nodeset and other is boolean, compare boolean to each item
830
+ # in nodeset s.t. boolean op boolean(item)
834
831
if set1 . kind_of? Array
835
832
a = set1
836
833
b = set2
@@ -841,15 +838,23 @@ def equality_relational_compare( set1, op, set2 )
841
838
842
839
case b
843
840
when true , false
844
- return unnode ( a ) { |v | compare ( Functions ::boolean ( v ) , op , b ) }
841
+ each_unnode ( a ) . any? do |unnoded |
842
+ compare ( Functions . boolean ( unnoded ) , op , b )
843
+ end
845
844
when Numeric
846
- return unnode ( a ) { |v | compare ( Functions ::number ( v ) , op , b ) }
847
- when /^\d +(\. \d +)?$/
848
- b = Functions ::number ( b )
849
- return unnode ( a ) { |v | compare ( Functions ::number ( v ) , op , b ) }
845
+ each_unnode ( a ) . any? do |unnoded |
846
+ compare ( Functions . number ( unnoded ) , op , b )
847
+ end
848
+ when /\A \d +(\. \d +)?\z /
849
+ b = Functions . number ( b )
850
+ each_unnode ( a ) . any? do |unnoded |
851
+ compare ( Functions . number ( unnoded ) , op , b )
852
+ end
850
853
else
851
- b = Functions ::string ( b )
852
- return unnode ( a ) { |v | compare ( Functions ::string ( v ) , op , b ) }
854
+ b = Functions ::string ( b )
855
+ each_unnode ( a ) . any? do |unnoded |
856
+ compare ( Functions ::string ( unnoded ) , op , b )
857
+ end
853
858
end
854
859
else
855
860
# If neither is nodeset,
@@ -880,13 +885,12 @@ def equality_relational_compare( set1, op, set2 )
880
885
set2 = Functions ::number ( set2 )
881
886
end
882
887
end
883
- return compare ( set1 , op , set2 )
888
+ compare ( set1 , op , set2 )
884
889
end
885
- return false
886
890
end
887
891
888
- def compare a , op , b
889
- case op
892
+ def compare ( a , operator , b )
893
+ case operator
890
894
when :eq
891
895
a == b
892
896
when :neq
@@ -899,22 +903,27 @@ def compare a, op, b
899
903
a > b
900
904
when :gteq
901
905
a >= b
902
- when :and
903
- a and b
904
- when :or
905
- a or b
906
906
else
907
- false
907
+ message = "[BUG] Unexpected compare operator: " +
908
+ "<#{ operator . inspect } >: <#{ a . inspect } >: <#{ b . inspect } >"
909
+ raise message
908
910
end
909
911
end
910
912
911
- def unnode ( nodeset )
912
- nodeset . collect do |node |
913
+ def each_unnode ( nodeset )
914
+ return to_enum ( __method__ , nodeset ) unless block_given?
915
+ nodeset . each do |node |
913
916
if node . is_a? ( XPathNode )
914
917
unnoded = node . raw_node
915
918
else
916
919
unnoded = node
917
920
end
921
+ yield ( unnoded )
922
+ end
923
+ end
924
+
925
+ def unnode ( nodeset )
926
+ each_unnode ( nodeset ) . collect do |unnoded |
918
927
unnoded = yield ( unnoded ) if block_given?
919
928
unnoded
920
929
end
0 commit comments