rubysl-rexml 1.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/lib/rexml/attlistdecl.rb +56 -56
  4. data/lib/rexml/attribute.rb +155 -149
  5. data/lib/rexml/cdata.rb +48 -48
  6. data/lib/rexml/child.rb +82 -82
  7. data/lib/rexml/comment.rb +59 -59
  8. data/lib/rexml/doctype.rb +22 -24
  9. data/lib/rexml/document.rb +185 -129
  10. data/lib/rexml/dtd/attlistdecl.rb +7 -7
  11. data/lib/rexml/dtd/dtd.rb +41 -41
  12. data/lib/rexml/dtd/elementdecl.rb +13 -13
  13. data/lib/rexml/dtd/entitydecl.rb +49 -49
  14. data/lib/rexml/dtd/notationdecl.rb +32 -32
  15. data/lib/rexml/element.rb +122 -107
  16. data/lib/rexml/encoding.rb +37 -58
  17. data/lib/rexml/entity.rb +144 -144
  18. data/lib/rexml/formatters/default.rb +6 -4
  19. data/lib/rexml/formatters/pretty.rb +11 -8
  20. data/lib/rexml/formatters/transitive.rb +4 -3
  21. data/lib/rexml/functions.rb +33 -21
  22. data/lib/rexml/instruction.rb +49 -49
  23. data/lib/rexml/light/node.rb +190 -191
  24. data/lib/rexml/namespace.rb +39 -39
  25. data/lib/rexml/node.rb +38 -38
  26. data/lib/rexml/output.rb +17 -12
  27. data/lib/rexml/parent.rb +26 -25
  28. data/lib/rexml/parseexception.rb +4 -4
  29. data/lib/rexml/parsers/baseparser.rb +90 -61
  30. data/lib/rexml/parsers/lightparser.rb +41 -43
  31. data/lib/rexml/parsers/pullparser.rb +1 -1
  32. data/lib/rexml/parsers/sax2parser.rb +233 -198
  33. data/lib/rexml/parsers/streamparser.rb +6 -2
  34. data/lib/rexml/parsers/treeparser.rb +9 -6
  35. data/lib/rexml/parsers/ultralightparser.rb +40 -40
  36. data/lib/rexml/parsers/xpathparser.rb +51 -52
  37. data/lib/rexml/quickpath.rb +247 -248
  38. data/lib/rexml/rexml.rb +9 -10
  39. data/lib/rexml/sax2listener.rb +92 -92
  40. data/lib/rexml/security.rb +27 -0
  41. data/lib/rexml/source.rb +95 -50
  42. data/lib/rexml/streamlistener.rb +90 -90
  43. data/lib/rexml/syncenumerator.rb +3 -4
  44. data/lib/rexml/text.rb +157 -76
  45. data/lib/rexml/validation/relaxng.rb +18 -18
  46. data/lib/rexml/validation/validation.rb +5 -5
  47. data/lib/rexml/xmldecl.rb +59 -63
  48. data/lib/rexml/xmltokens.rb +14 -14
  49. data/lib/rexml/xpath.rb +67 -53
  50. data/lib/rexml/xpath_parser.rb +49 -38
  51. data/lib/rubysl/rexml.rb +1 -0
  52. data/lib/rubysl/rexml/version.rb +1 -1
  53. data/rubysl-rexml.gemspec +3 -1
  54. metadata +19 -28
  55. data/lib/rexml/encodings/CP-1252.rb +0 -103
  56. data/lib/rexml/encodings/EUC-JP.rb +0 -35
  57. data/lib/rexml/encodings/ICONV.rb +0 -22
  58. data/lib/rexml/encodings/ISO-8859-1.rb +0 -7
  59. data/lib/rexml/encodings/ISO-8859-15.rb +0 -72
  60. data/lib/rexml/encodings/SHIFT-JIS.rb +0 -37
  61. data/lib/rexml/encodings/SHIFT_JIS.rb +0 -1
  62. data/lib/rexml/encodings/UNILE.rb +0 -34
  63. data/lib/rexml/encodings/US-ASCII.rb +0 -30
  64. data/lib/rexml/encodings/UTF-16.rb +0 -35
  65. data/lib/rexml/encodings/UTF-8.rb +0 -18
@@ -5,11 +5,11 @@ module REXML
5
5
  @listener = listener
6
6
  @parser = BaseParser.new( source )
7
7
  end
8
-
8
+
9
9
  def add_listener( listener )
10
10
  @parser.add_listener( listener )
11
11
  end
12
-
12
+
13
13
  def parse
14
14
  # entity string
15
15
  while true
@@ -38,6 +38,10 @@ module REXML
38
38
  @listener.send( event[0].to_s, *event[1..-1] )
39
39
  when :entitydecl, :notationdecl
40
40
  @listener.send( event[0].to_s, event[1..-1] )
41
+ when :externalentity
42
+ entity_reference = event[1]
43
+ content = entity_reference.gsub(/\A%|;\z/, "")
44
+ @listener.entity(content)
41
45
  end
42
46
  end
43
47
  end
@@ -24,13 +24,16 @@ module REXML
24
24
  case event[0]
25
25
  when :end_document
26
26
  unless tag_stack.empty?
27
- #raise ParseException.new("No close tag for #{tag_stack.inspect}")
28
- raise ParseException.new("No close tag for #{@build_context.xpath}")
27
+ raise ParseException.new("No close tag for #{@build_context.xpath}",
28
+ @parser.source, @parser)
29
29
  end
30
30
  return
31
31
  when :start_element
32
32
  tag_stack.push(event[1])
33
- el = @build_context = @build_context.add_element( event[1], event[2] )
33
+ el = @build_context = @build_context.add_element( event[1] )
34
+ event[2].each do |key, value|
35
+ el.attributes[key]=Attribute.new(key,value,self)
36
+ end
34
37
  when :end_element
35
38
  tag_stack.pop
36
39
  @build_context = @build_context.parent
@@ -39,8 +42,8 @@ module REXML
39
42
  if @build_context[-1].instance_of? Text
40
43
  @build_context[-1] << event[1]
41
44
  else
42
- @build_context.add(
43
- Text.new(event[1], @build_context.whitespace, nil, true)
45
+ @build_context.add(
46
+ Text.new(event[1], @build_context.whitespace, nil, true)
44
47
  ) unless (
45
48
  @build_context.ignore_whitespace_nodes and
46
49
  event[1].strip.size==0
@@ -86,7 +89,7 @@ module REXML
86
89
  end
87
90
  rescue REXML::Validation::ValidationException
88
91
  raise
89
- rescue REXML::UndefinedNamespaceException
92
+ rescue REXML::ParseException
90
93
  raise
91
94
  rescue
92
95
  raise ParseException.new( $!.message, @parser.source, @parser, $! )
@@ -2,12 +2,12 @@ require 'rexml/parsers/streamparser'
2
2
  require 'rexml/parsers/baseparser'
3
3
 
4
4
  module REXML
5
- module Parsers
6
- class UltraLightParser
7
- def initialize stream
8
- @stream = stream
9
- @parser = REXML::Parsers::BaseParser.new( stream )
10
- end
5
+ module Parsers
6
+ class UltraLightParser
7
+ def initialize stream
8
+ @stream = stream
9
+ @parser = REXML::Parsers::BaseParser.new( stream )
10
+ end
11
11
 
12
12
  def add_listener( listener )
13
13
  @parser.add_listener( listener )
@@ -18,39 +18,39 @@ module REXML
18
18
  @parser.stream = @stream
19
19
  end
20
20
 
21
- def parse
22
- root = context = []
23
- while true
24
- event = @parser.pull
25
- case event[0]
26
- when :end_document
27
- break
28
- when :end_doctype
29
- context = context[1]
30
- when :start_element, :doctype
31
- context << event
32
- event[1,0] = [context]
33
- context = event
34
- when :end_element
35
- context = context[1]
36
- else
37
- context << event
38
- end
39
- end
40
- root
41
- end
42
- end
21
+ def parse
22
+ root = context = []
23
+ while true
24
+ event = @parser.pull
25
+ case event[0]
26
+ when :end_document
27
+ break
28
+ when :end_doctype
29
+ context = context[1]
30
+ when :start_element, :doctype
31
+ context << event
32
+ event[1,0] = [context]
33
+ context = event
34
+ when :end_element
35
+ context = context[1]
36
+ else
37
+ context << event
38
+ end
39
+ end
40
+ root
41
+ end
42
+ end
43
43
 
44
- # An element is an array. The array contains:
45
- # 0 The parent element
46
- # 1 The tag name
47
- # 2 A hash of attributes
48
- # 3..-1 The child elements
49
- # An element is an array of size > 3
50
- # Text is a String
51
- # PIs are [ :processing_instruction, target, data ]
52
- # Comments are [ :comment, data ]
53
- # DocTypes are DocType structs
54
- # The root is an array with XMLDecls, Text, DocType, Array, Text
55
- end
44
+ # An element is an array. The array contains:
45
+ # 0 The parent element
46
+ # 1 The tag name
47
+ # 2 A hash of attributes
48
+ # 3..-1 The child elements
49
+ # An element is an array of size > 3
50
+ # Text is a String
51
+ # PIs are [ :processing_instruction, target, data ]
52
+ # Comments are [ :comment, data ]
53
+ # DocTypes are DocType structs
54
+ # The root is an array with XMLDecls, Text, DocType, Array, Text
55
+ end
56
56
  end
@@ -17,8 +17,9 @@ module REXML
17
17
  end
18
18
 
19
19
  def parse path
20
+ path = path.dup
20
21
  path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
21
- path.gsub!( /\s+([\]\)])/, '\1' )
22
+ path.gsub!( /\s+([\]\)])/, '\1')
22
23
  parsed = []
23
24
  path = OrExpr(path, parsed)
24
25
  parsed
@@ -39,10 +40,10 @@ module REXML
39
40
  case op
40
41
  when :node
41
42
  when :attribute
42
- string << "/" if string.size > 0
43
- string << "@"
43
+ string << "/" if string.size > 0
44
+ string << "@"
44
45
  when :child
45
- string << "/" if string.size > 0
46
+ string << "/" if string.size > 0
46
47
  when :descendant_or_self
47
48
  string << "/"
48
49
  when :self
@@ -51,10 +52,10 @@ module REXML
51
52
  string << ".."
52
53
  when :any
53
54
  string << "*"
54
- when :text
55
- string << "text()"
56
- when :following, :following_sibling,
57
- :ancestor, :ancestor_or_self, :descendant,
55
+ when :text
56
+ string << "text()"
57
+ when :following, :following_sibling,
58
+ :ancestor, :ancestor_or_self, :descendant,
58
59
  :namespace, :preceding, :preceding_sibling
59
60
  string << "/" unless string.size == 0
60
61
  string << op.to_s.tr("_", "-")
@@ -70,13 +71,13 @@ module REXML
70
71
  string << ']'
71
72
  when :document
72
73
  document = true
73
- when :function
74
- string << path.shift
75
- string << "( "
76
- string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
77
- string << " )"
78
- when :literal
79
- string << %Q{ "#{path.shift}" }
74
+ when :function
75
+ string << path.shift
76
+ string << "( "
77
+ string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
78
+ string << " )"
79
+ when :literal
80
+ string << %Q{ "#{path.shift}" }
80
81
  else
81
82
  string << "/" unless string.size == 0
82
83
  string << "UNKNOWN("
@@ -84,7 +85,7 @@ module REXML
84
85
  string << ")"
85
86
  end
86
87
  end
87
- string = "/"+string if document
88
+ string = "/"+string if document
88
89
  return string
89
90
  end
90
91
 
@@ -97,7 +98,7 @@ module REXML
97
98
  case op
98
99
  when :node
99
100
  string << "node()"
100
- when :attribute, :child, :following, :following_sibling,
101
+ when :attribute, :child, :following, :following_sibling,
101
102
  :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
102
103
  :namespace, :preceding, :preceding_sibling, :self, :parent
103
104
  string << "/" unless string.size == 0
@@ -249,7 +250,7 @@ module REXML
249
250
 
250
251
  parsed.concat(n)
251
252
  end
252
-
253
+
253
254
  if path.size > 0
254
255
  if path[0] == ?/
255
256
  if path[1] == ?/
@@ -282,7 +283,6 @@ module REXML
282
283
  PI = /^processing-instruction\(/
283
284
  def NodeTest path, parsed
284
285
  #puts "NodeTest with #{path}"
285
- res = nil
286
286
  case path
287
287
  when /^\*/
288
288
  path = $'
@@ -332,12 +332,12 @@ module REXML
332
332
  predicates << expr[1..-2] if expr
333
333
  end
334
334
  #puts "PREDICATES = #{predicates.inspect}"
335
- predicates.each{ |expr|
336
- #puts "ORING #{expr}"
335
+ predicates.each{ |pred|
336
+ #puts "ORING #{pred}"
337
337
  preds = []
338
338
  parsed << :predicate
339
339
  parsed << preds
340
- OrExpr(expr, preds)
340
+ OrExpr(pred, preds)
341
341
  }
342
342
  #puts "PREDICATES = #{predicates.inspect}"
343
343
  path
@@ -551,7 +551,7 @@ module REXML
551
551
  end
552
552
  end
553
553
  #puts "BEFORE WITH '#{rest}'"
554
- rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/
554
+ rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
555
555
  parsed.concat(n)
556
556
  return rest
557
557
  end
@@ -578,7 +578,6 @@ module REXML
578
578
  NUMBER = /^(\d*\.?\d+)/
579
579
  NT = /^comment|text|processing-instruction|node$/
580
580
  def PrimaryExpr path, parsed
581
- arry = []
582
581
  case path
583
582
  when VARIABLE_REFERENCE
584
583
  varname = $1
@@ -600,13 +599,13 @@ module REXML
600
599
  #puts "LITERAL or NUMBER: #$1"
601
600
  varname = $1.nil? ? $2 : $1
602
601
  path = $'
603
- parsed << :literal
602
+ parsed << :literal
604
603
  parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
605
604
  when LITERAL
606
605
  #puts "LITERAL or NUMBER: #$1"
607
606
  varname = $1.nil? ? $2 : $1
608
607
  path = $'
609
- parsed << :literal
608
+ parsed << :literal
610
609
  parsed << varname
611
610
  when /^\(/ #/
612
611
  path, contents = get_group(path)
@@ -649,43 +648,43 @@ module REXML
649
648
  return nil unless depth==0
650
649
  [string[ind..-1], string[0..ind-1]]
651
650
  end
652
-
651
+
653
652
  def parse_args( string )
654
653
  arguments = []
655
654
  ind = 0
656
- inquot = false
657
- inapos = false
655
+ inquot = false
656
+ inapos = false
658
657
  depth = 1
659
658
  begin
660
659
  case string[ind]
661
660
  when ?"
662
- inquot = !inquot unless inapos
661
+ inquot = !inquot unless inapos
663
662
  when ?'
664
- inapos = !inapos unless inquot
663
+ inapos = !inapos unless inquot
665
664
  else
666
- unless inquot or inapos
667
- case string[ind]
668
- when ?(
669
- depth += 1
665
+ unless inquot or inapos
666
+ case string[ind]
667
+ when ?(
668
+ depth += 1
670
669
  if depth == 1
671
- string = string[1..-1]
672
- ind -= 1
670
+ string = string[1..-1]
671
+ ind -= 1
672
+ end
673
+ when ?)
674
+ depth -= 1
675
+ if depth == 0
676
+ s = string[0,ind].strip
677
+ arguments << s unless s == ""
678
+ string = string[ind+1..-1]
673
679
  end
674
- when ?)
675
- depth -= 1
676
- if depth == 0
677
- s = string[0,ind].strip
678
- arguments << s unless s == ""
679
- string = string[ind+1..-1]
680
- end
681
- when ?,
682
- if depth == 1
683
- s = string[0,ind].strip
684
- arguments << s unless s == ""
685
- string = string[ind+1..-1]
686
- ind = -1
687
- end
688
- end
680
+ when ?,
681
+ if depth == 1
682
+ s = string[0,ind].strip
683
+ arguments << s unless s == ""
684
+ string = string[ind+1..-1]
685
+ ind = -1
686
+ end
687
+ end
689
688
  end
690
689
  end
691
690
  ind += 1
@@ -2,265 +2,264 @@ require 'rexml/functions'
2
2
  require 'rexml/xmltokens'
3
3
 
4
4
  module REXML
5
- class QuickPath
6
- include Functions
7
- include XMLTokens
5
+ class QuickPath
6
+ include Functions
7
+ include XMLTokens
8
8
 
9
- EMPTY_HASH = {}
9
+ # A base Hash object to be used when initializing a
10
+ # default empty namespaces set.
11
+ EMPTY_HASH = {}
10
12
 
11
- def QuickPath::first element, path, namespaces=EMPTY_HASH
12
- match(element, path, namespaces)[0]
13
- end
13
+ def QuickPath::first element, path, namespaces=EMPTY_HASH
14
+ match(element, path, namespaces)[0]
15
+ end
14
16
 
15
- def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
16
- path = "*" unless path
17
- match(element, path, namespaces).each( &block )
18
- end
17
+ def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
18
+ path = "*" unless path
19
+ match(element, path, namespaces).each( &block )
20
+ end
19
21
 
20
- def QuickPath::match element, path, namespaces=EMPTY_HASH
21
- raise "nil is not a valid xpath" unless path
22
- results = nil
23
- Functions::namespace_context = namespaces
24
- case path
25
- when /^\/([^\/]|$)/u
26
- # match on root
27
- path = path[1..-1]
28
- return [element.root.parent] if path == ''
29
- results = filter([element.root], path)
30
- when /^[-\w]*::/u
31
- results = filter([element], path)
32
- when /^\*/u
33
- results = filter(element.to_a, path)
34
- when /^[\[!\w:]/u
35
- # match on child
36
- matches = []
37
- children = element.to_a
38
- results = filter(children, path)
39
- else
40
- results = filter([element], path)
41
- end
42
- return results
43
- end
22
+ def QuickPath::match element, path, namespaces=EMPTY_HASH
23
+ raise "nil is not a valid xpath" unless path
24
+ results = nil
25
+ Functions::namespace_context = namespaces
26
+ case path
27
+ when /^\/([^\/]|$)/u
28
+ # match on root
29
+ path = path[1..-1]
30
+ return [element.root.parent] if path == ''
31
+ results = filter([element.root], path)
32
+ when /^[-\w]*::/u
33
+ results = filter([element], path)
34
+ when /^\*/u
35
+ results = filter(element.to_a, path)
36
+ when /^[\[!\w:]/u
37
+ # match on child
38
+ children = element.to_a
39
+ results = filter(children, path)
40
+ else
41
+ results = filter([element], path)
42
+ end
43
+ return results
44
+ end
44
45
 
45
- # Given an array of nodes it filters the array based on the path. The
46
- # result is that when this method returns, the array will contain elements
47
- # which match the path
48
- def QuickPath::filter elements, path
49
- return elements if path.nil? or path == '' or elements.size == 0
50
- case path
51
- when /^\/\//u # Descendant
52
- return axe( elements, "descendant-or-self", $' )
53
- when /^\/?\b(\w[-\w]*)\b::/u # Axe
54
- axe_name = $1
55
- rest = $'
56
- return axe( elements, $1, $' )
57
- when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child
58
- rest = $'
59
- results = []
60
- elements.each do |element|
61
- results |= filter( element.to_a, rest )
62
- end
63
- return results
64
- when /^\/?(\w[-\w]*)\(/u # / Function
65
- return function( elements, $1, $' )
66
- when Namespace::NAMESPLIT # Element name
67
- name = $2
68
- ns = $1
69
- rest = $'
70
- elements.delete_if do |element|
71
- !(element.kind_of? Element and
72
- (element.expanded_name == name or
73
- (element.name == name and
74
- element.namespace == Functions.namespace_context[ns])))
75
- end
76
- return filter( elements, rest )
77
- when /^\/\[/u
78
- matches = []
79
- elements.each do |element|
80
- matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
81
- end
82
- return matches
83
- when /^\[/u # Predicate
84
- return predicate( elements, path )
85
- when /^\/?\.\.\./u # Ancestor
86
- return axe( elements, "ancestor", $' )
87
- when /^\/?\.\./u # Parent
88
- return filter( elements.collect{|e|e.parent}, $' )
89
- when /^\/?\./u # Self
90
- return filter( elements, $' )
91
- when /^\*/u # Any
92
- results = []
93
- elements.each do |element|
94
- results |= filter( [element], $' ) if element.kind_of? Element
95
- #if element.kind_of? Element
96
- # children = element.to_a
97
- # children.delete_if { |child| !child.kind_of?(Element) }
98
- # results |= filter( children, $' )
99
- #end
100
- end
101
- return results
102
- end
103
- return []
104
- end
46
+ # Given an array of nodes it filters the array based on the path. The
47
+ # result is that when this method returns, the array will contain elements
48
+ # which match the path
49
+ def QuickPath::filter elements, path
50
+ return elements if path.nil? or path == '' or elements.size == 0
51
+ case path
52
+ when /^\/\//u # Descendant
53
+ return axe( elements, "descendant-or-self", $' )
54
+ when /^\/?\b(\w[-\w]*)\b::/u # Axe
55
+ return axe( elements, $1, $' )
56
+ when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child
57
+ rest = $'
58
+ results = []
59
+ elements.each do |element|
60
+ results |= filter( element.to_a, rest )
61
+ end
62
+ return results
63
+ when /^\/?(\w[-\w]*)\(/u # / Function
64
+ return function( elements, $1, $' )
65
+ when Namespace::NAMESPLIT # Element name
66
+ name = $2
67
+ ns = $1
68
+ rest = $'
69
+ elements.delete_if do |element|
70
+ !(element.kind_of? Element and
71
+ (element.expanded_name == name or
72
+ (element.name == name and
73
+ element.namespace == Functions.namespace_context[ns])))
74
+ end
75
+ return filter( elements, rest )
76
+ when /^\/\[/u
77
+ matches = []
78
+ elements.each do |element|
79
+ matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
80
+ end
81
+ return matches
82
+ when /^\[/u # Predicate
83
+ return predicate( elements, path )
84
+ when /^\/?\.\.\./u # Ancestor
85
+ return axe( elements, "ancestor", $' )
86
+ when /^\/?\.\./u # Parent
87
+ return filter( elements.collect{|e|e.parent}, $' )
88
+ when /^\/?\./u # Self
89
+ return filter( elements, $' )
90
+ when /^\*/u # Any
91
+ results = []
92
+ elements.each do |element|
93
+ results |= filter( [element], $' ) if element.kind_of? Element
94
+ #if element.kind_of? Element
95
+ # children = element.to_a
96
+ # children.delete_if { |child| !child.kind_of?(Element) }
97
+ # results |= filter( children, $' )
98
+ #end
99
+ end
100
+ return results
101
+ end
102
+ return []
103
+ end
105
104
 
106
- def QuickPath::axe( elements, axe_name, rest )
107
- matches = []
108
- matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
109
- case axe_name
110
- when /^descendant/u
111
- elements.each do |element|
112
- matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
113
- end
114
- when /^ancestor/u
115
- elements.each do |element|
116
- while element.parent
117
- matches << element.parent
118
- element = element.parent
119
- end
120
- end
121
- matches = filter( matches, rest )
122
- when "self"
123
- matches = filter( elements, rest )
124
- when "child"
125
- elements.each do |element|
126
- matches |= filter( element.to_a, rest ) if element.kind_of? Element
127
- end
128
- when "attribute"
129
- elements.each do |element|
130
- matches << element.attributes[ rest ] if element.kind_of? Element
131
- end
132
- when "parent"
133
- matches = filter(elements.collect{|element| element.parent}.uniq, rest)
134
- when "following-sibling"
135
- matches = filter(elements.collect{|element| element.next_sibling}.uniq,
136
- rest)
137
- when "previous-sibling"
138
- matches = filter(elements.collect{|element|
139
- element.previous_sibling}.uniq, rest )
140
- end
141
- return matches.uniq
142
- end
105
+ def QuickPath::axe( elements, axe_name, rest )
106
+ matches = []
107
+ matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
108
+ case axe_name
109
+ when /^descendant/u
110
+ elements.each do |element|
111
+ matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
112
+ end
113
+ when /^ancestor/u
114
+ elements.each do |element|
115
+ while element.parent
116
+ matches << element.parent
117
+ element = element.parent
118
+ end
119
+ end
120
+ matches = filter( matches, rest )
121
+ when "self"
122
+ matches = filter( elements, rest )
123
+ when "child"
124
+ elements.each do |element|
125
+ matches |= filter( element.to_a, rest ) if element.kind_of? Element
126
+ end
127
+ when "attribute"
128
+ elements.each do |element|
129
+ matches << element.attributes[ rest ] if element.kind_of? Element
130
+ end
131
+ when "parent"
132
+ matches = filter(elements.collect{|element| element.parent}.uniq, rest)
133
+ when "following-sibling"
134
+ matches = filter(elements.collect{|element| element.next_sibling}.uniq,
135
+ rest)
136
+ when "previous-sibling"
137
+ matches = filter(elements.collect{|element|
138
+ element.previous_sibling}.uniq, rest )
139
+ end
140
+ return matches.uniq
141
+ end
143
142
 
144
- # A predicate filters a node-set with respect to an axis to produce a
145
- # new node-set. For each node in the node-set to be filtered, the
146
- # PredicateExpr is evaluated with that node as the context node, with
147
- # the number of nodes in the node-set as the context size, and with the
148
- # proximity position of the node in the node-set with respect to the
149
- # axis as the context position; if PredicateExpr evaluates to true for
150
- # that node, the node is included in the new node-set; otherwise, it is
151
- # not included.
152
- #
153
- # A PredicateExpr is evaluated by evaluating the Expr and converting
154
- # the result to a boolean. If the result is a number, the result will
155
- # be converted to true if the number is equal to the context position
156
- # and will be converted to false otherwise; if the result is not a
157
- # number, then the result will be converted as if by a call to the
158
- # boolean function. Thus a location path para[3] is equivalent to
159
- # para[position()=3].
160
- def QuickPath::predicate( elements, path )
161
- ind = 1
162
- bcount = 1
163
- while bcount > 0
164
- bcount += 1 if path[ind] == ?[
165
- bcount -= 1 if path[ind] == ?]
166
- ind += 1
167
- end
168
- ind -= 1
169
- predicate = path[1..ind-1]
170
- rest = path[ind+1..-1]
143
+ OPERAND_ = '((?=(?:(?!and|or).)*[^\s<>=])[^\s<>=]+)'
144
+ # A predicate filters a node-set with respect to an axis to produce a
145
+ # new node-set. For each node in the node-set to be filtered, the
146
+ # PredicateExpr is evaluated with that node as the context node, with
147
+ # the number of nodes in the node-set as the context size, and with the
148
+ # proximity position of the node in the node-set with respect to the
149
+ # axis as the context position; if PredicateExpr evaluates to true for
150
+ # that node, the node is included in the new node-set; otherwise, it is
151
+ # not included.
152
+ #
153
+ # A PredicateExpr is evaluated by evaluating the Expr and converting
154
+ # the result to a boolean. If the result is a number, the result will
155
+ # be converted to true if the number is equal to the context position
156
+ # and will be converted to false otherwise; if the result is not a
157
+ # number, then the result will be converted as if by a call to the
158
+ # boolean function. Thus a location path para[3] is equivalent to
159
+ # para[position()=3].
160
+ def QuickPath::predicate( elements, path )
161
+ ind = 1
162
+ bcount = 1
163
+ while bcount > 0
164
+ bcount += 1 if path[ind] == ?[
165
+ bcount -= 1 if path[ind] == ?]
166
+ ind += 1
167
+ end
168
+ ind -= 1
169
+ predicate = path[1..ind-1]
170
+ rest = path[ind+1..-1]
171
171
 
172
- # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
173
- predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u ) {
174
- "#$1 #$2 #$3 and #$3 #$4 #$5"
175
- }
176
- # Let's do some Ruby trickery to avoid some work:
177
- predicate.gsub!( /&/u, "&&" )
178
- predicate.gsub!( /=/u, "==" )
179
- predicate.gsub!( /@(\w[-\w.]*)/u ) {
180
- "attribute(\"#$1\")"
181
- }
182
- predicate.gsub!( /\bmod\b/u, "%" )
183
- predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
184
- fname = $1
185
- fname.gsub( /-/u, "_" )
186
- }
187
-
188
- Functions.pair = [ 0, elements.size ]
189
- results = []
190
- elements.each do |element|
191
- Functions.pair[0] += 1
192
- Functions.node = element
193
- res = eval( predicate )
194
- case res
195
- when true
196
- results << element
197
- when Fixnum
198
- results << element if Functions.pair[0] == res
199
- when String
200
- results << element
201
- end
202
- end
203
- return filter( results, rest )
204
- end
172
+ # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
173
+ #
174
+ predicate.gsub!(
175
+ /#{OPERAND_}\s*([<>=])\s*#{OPERAND_}\s*([<>=])\s*#{OPERAND_}/u,
176
+ '\1 \2 \3 and \3 \4 \5' )
177
+ # Let's do some Ruby trickery to avoid some work:
178
+ predicate.gsub!( /&/u, "&&" )
179
+ predicate.gsub!( /=/u, "==" )
180
+ predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' )
181
+ predicate.gsub!( /\bmod\b/u, "%" )
182
+ predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
183
+ fname = $1
184
+ fname.gsub( /-/u, "_" )
185
+ }
205
186
 
206
- def QuickPath::attribute( name )
207
- return Functions.node.attributes[name] if Functions.node.kind_of? Element
208
- end
187
+ Functions.pair = [ 0, elements.size ]
188
+ results = []
189
+ elements.each do |element|
190
+ Functions.pair[0] += 1
191
+ Functions.node = element
192
+ res = eval( predicate )
193
+ case res
194
+ when true
195
+ results << element
196
+ when Fixnum
197
+ results << element if Functions.pair[0] == res
198
+ when String
199
+ results << element
200
+ end
201
+ end
202
+ return filter( results, rest )
203
+ end
209
204
 
210
- def QuickPath::name()
211
- return Functions.node.name if Functions.node.kind_of? Element
212
- end
205
+ def QuickPath::attribute( name )
206
+ return Functions.node.attributes[name] if Functions.node.kind_of? Element
207
+ end
213
208
 
214
- def QuickPath::method_missing( id, *args )
215
- begin
216
- Functions.send( id.id2name, *args )
217
- rescue Exception
218
- raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
219
- end
220
- end
209
+ def QuickPath::name()
210
+ return Functions.node.name if Functions.node.kind_of? Element
211
+ end
221
212
 
222
- def QuickPath::function( elements, fname, rest )
223
- args = parse_args( elements, rest )
224
- Functions.pair = [0, elements.size]
225
- results = []
226
- elements.each do |element|
227
- Functions.pair[0] += 1
228
- Functions.node = element
229
- res = Functions.send( fname, *args )
230
- case res
231
- when true
232
- results << element
233
- when Fixnum
234
- results << element if Functions.pair[0] == res
235
- end
236
- end
237
- return results
238
- end
213
+ def QuickPath::method_missing( id, *args )
214
+ begin
215
+ Functions.send( id.id2name, *args )
216
+ rescue Exception
217
+ raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
218
+ end
219
+ end
239
220
 
240
- def QuickPath::parse_args( element, string )
241
- # /.*?(?:\)|,)/
242
- arguments = []
243
- buffer = ""
244
- while string and string != ""
245
- c = string[0]
246
- string.sub!(/^./u, "")
247
- case c
248
- when ?,
249
- # if depth = 1, then we start a new argument
250
- arguments << evaluate( buffer )
251
- #arguments << evaluate( string[0..count] )
252
- when ?(
253
- # start a new method call
254
- function( element, buffer, string )
255
- buffer = ""
256
- when ?)
257
- # close the method call and return arguments
258
- return arguments
259
- else
260
- buffer << c
261
- end
262
- end
263
- ""
264
- end
265
- end
221
+ def QuickPath::function( elements, fname, rest )
222
+ args = parse_args( elements, rest )
223
+ Functions.pair = [0, elements.size]
224
+ results = []
225
+ elements.each do |element|
226
+ Functions.pair[0] += 1
227
+ Functions.node = element
228
+ res = Functions.send( fname, *args )
229
+ case res
230
+ when true
231
+ results << element
232
+ when Fixnum
233
+ results << element if Functions.pair[0] == res
234
+ end
235
+ end
236
+ return results
237
+ end
238
+
239
+ def QuickPath::parse_args( element, string )
240
+ # /.*?(?:\)|,)/
241
+ arguments = []
242
+ buffer = ""
243
+ while string and string != ""
244
+ c = string[0]
245
+ string.sub!(/^./u, "")
246
+ case c
247
+ when ?,
248
+ # if depth = 1, then we start a new argument
249
+ arguments << evaluate( buffer )
250
+ #arguments << evaluate( string[0..count] )
251
+ when ?(
252
+ # start a new method call
253
+ function( element, buffer, string )
254
+ buffer = ""
255
+ when ?)
256
+ # close the method call and return arguments
257
+ return arguments
258
+ else
259
+ buffer << c
260
+ end
261
+ end
262
+ ""
263
+ end
264
+ end
266
265
  end