rexml 3.2.6 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/rexml/element.rb CHANGED
@@ -7,14 +7,6 @@ require_relative "xpath"
7
7
  require_relative "parseexception"
8
8
 
9
9
  module REXML
10
- # An implementation note about namespaces:
11
- # As we parse, when we find namespaces we put them in a hash and assign
12
- # them a unique ID. We then convert the namespace prefix for the node
13
- # to the unique ID. This makes namespace lookup much faster for the
14
- # cost of extra memory use. We save the namespace prefix for the
15
- # context node and convert it back when we write it.
16
- @@namespaces = {}
17
-
18
10
  # An \REXML::Element object represents an XML element.
19
11
  #
20
12
  # An element:
@@ -449,9 +441,14 @@ module REXML
449
441
  # Related: #root_node, #document.
450
442
  #
451
443
  def root
452
- return elements[1] if self.kind_of? Document
453
- return self if parent.kind_of? Document or parent.nil?
454
- return parent.root
444
+ target = self
445
+ while target
446
+ return target.elements[1] if target.kind_of? Document
447
+ parent = target.parent
448
+ return target if parent.kind_of? Document or parent.nil?
449
+ target = parent
450
+ end
451
+ nil
455
452
  end
456
453
 
457
454
  # :call-seq:
@@ -476,8 +473,7 @@ module REXML
476
473
  # Related: #root, #root_node.
477
474
  #
478
475
  def document
479
- rt = root
480
- rt.parent if rt
476
+ root&.parent
481
477
  end
482
478
 
483
479
  # :call-seq:
@@ -569,7 +565,7 @@ module REXML
569
565
  prefixes = []
570
566
  prefixes = parent.prefixes if parent
571
567
  prefixes |= attributes.prefixes
572
- return prefixes
568
+ prefixes
573
569
  end
574
570
 
575
571
  # :call-seq:
@@ -592,10 +588,12 @@ module REXML
592
588
  # d.elements['//c'].namespaces # => {"x"=>"1", "y"=>"2", "z"=>"3"}
593
589
  #
594
590
  def namespaces
595
- namespaces = {}
596
- namespaces = parent.namespaces if parent
597
- namespaces = namespaces.merge( attributes.namespaces )
598
- return namespaces
591
+ namespaces_cache = document&.__send__(:namespaces_cache)
592
+ if namespaces_cache
593
+ namespaces_cache[self] ||= calculate_namespaces
594
+ else
595
+ calculate_namespaces
596
+ end
599
597
  end
600
598
 
601
599
  # :call-seq:
@@ -622,15 +620,11 @@ module REXML
622
620
  if prefix.nil?
623
621
  prefix = prefix()
624
622
  end
625
- if prefix == ''
626
- prefix = "xmlns"
627
- else
628
- prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
629
- end
630
- ns = attributes[ prefix ]
631
- ns = parent.namespace(prefix) if ns.nil? and parent
623
+ prefix = (prefix == '') ? 'xmlns' : prefix.delete_prefix("xmlns:")
624
+ ns = namespaces[prefix]
625
+
632
626
  ns = '' if ns.nil? and prefix == 'xmlns'
633
- return ns
627
+ ns
634
628
  end
635
629
 
636
630
  # :call-seq:
@@ -962,7 +956,7 @@ module REXML
962
956
  def next_element
963
957
  element = next_sibling
964
958
  element = element.next_sibling until element.nil? or element.kind_of? Element
965
- return element
959
+ element
966
960
  end
967
961
 
968
962
  # :call-seq:
@@ -978,7 +972,7 @@ module REXML
978
972
  def previous_element
979
973
  element = previous_sibling
980
974
  element = element.previous_sibling until element.nil? or element.kind_of? Element
981
- return element
975
+ element
982
976
  end
983
977
 
984
978
 
@@ -1028,8 +1022,7 @@ module REXML
1028
1022
  #
1029
1023
  def text( path = nil )
1030
1024
  rv = get_text(path)
1031
- return rv.value unless rv.nil?
1032
- nil
1025
+ rv&.value
1033
1026
  end
1034
1027
 
1035
1028
  # :call-seq:
@@ -1057,7 +1050,7 @@ module REXML
1057
1050
  else
1058
1051
  rv = @children.find { |node| node.kind_of? Text }
1059
1052
  end
1060
- return rv
1053
+ rv
1061
1054
  end
1062
1055
 
1063
1056
  # :call-seq:
@@ -1101,7 +1094,7 @@ module REXML
1101
1094
  old_text.replace_with( text )
1102
1095
  end
1103
1096
  end
1104
- return self
1097
+ self
1105
1098
  end
1106
1099
 
1107
1100
  # :call-seq:
@@ -1152,7 +1145,7 @@ module REXML
1152
1145
  text = Text.new( text, whitespace(), nil, raw() )
1153
1146
  end
1154
1147
  self << text unless text.nil?
1155
- return self
1148
+ self
1156
1149
  end
1157
1150
 
1158
1151
  # :call-seq:
@@ -1196,7 +1189,7 @@ module REXML
1196
1189
  cur = cur.parent
1197
1190
  path_elements << __to_xpath_helper( cur )
1198
1191
  end
1199
- return path_elements.reverse.join( "/" )
1192
+ path_elements.reverse.join( "/" )
1200
1193
  end
1201
1194
 
1202
1195
  #################################################
@@ -1284,16 +1277,11 @@ module REXML
1284
1277
  # document.root.attribute("x", "a") # => a:x='a:x'
1285
1278
  #
1286
1279
  def attribute( name, namespace=nil )
1287
- prefix = nil
1288
- if namespaces.respond_to? :key
1289
- prefix = namespaces.key(namespace) if namespace
1290
- else
1291
- prefix = namespaces.index(namespace) if namespace
1292
- end
1280
+ prefix = namespaces.key(namespace) if namespace
1293
1281
  prefix = nil if prefix == 'xmlns'
1294
1282
 
1295
1283
  ret_val =
1296
- attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
1284
+ attributes.get_attribute( prefix ? "#{prefix}:#{name}" : name )
1297
1285
 
1298
1286
  return ret_val unless ret_val.nil?
1299
1287
  return nil if prefix.nil?
@@ -1303,7 +1291,6 @@ module REXML
1303
1291
  return nil unless ( namespaces[ prefix ] == namespaces[ 'xmlns' ] )
1304
1292
 
1305
1293
  attributes.get_attribute( name )
1306
-
1307
1294
  end
1308
1295
 
1309
1296
  # :call-seq:
@@ -1317,7 +1304,7 @@ module REXML
1317
1304
  # b.has_attributes? # => false
1318
1305
  #
1319
1306
  def has_attributes?
1320
- return !@attributes.empty?
1307
+ !@attributes.empty?
1321
1308
  end
1322
1309
 
1323
1310
  # :call-seq:
@@ -1506,7 +1493,7 @@ module REXML
1506
1493
  # doc.write( out ) #-> doc is written to the string 'out'
1507
1494
  # doc.write( $stdout ) #-> doc written to the console
1508
1495
  def write(output=$stdout, indent=-1, transitive=false, ie_hack=false)
1509
- Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters", uplevel: 1)
1496
+ Kernel.warn("#{self.class.name}#write is deprecated. See REXML::Formatters", uplevel: 1)
1510
1497
  formatter = if indent > -1
1511
1498
  if transitive
1512
1499
  require_relative "formatters/transitive"
@@ -1520,8 +1507,15 @@ module REXML
1520
1507
  formatter.write( self, output )
1521
1508
  end
1522
1509
 
1523
-
1524
1510
  private
1511
+ def calculate_namespaces
1512
+ if parent
1513
+ parent.namespaces.merge(attributes.namespaces)
1514
+ else
1515
+ attributes.namespaces
1516
+ end
1517
+ end
1518
+
1525
1519
  def __to_xpath_helper node
1526
1520
  rv = node.expanded_name.clone
1527
1521
  if node.parent
@@ -1688,11 +1682,7 @@ module REXML
1688
1682
  (num += 1) == index
1689
1683
  }
1690
1684
  else
1691
- return XPath::first( @element, index )
1692
- #{ |element|
1693
- # return element if element.kind_of? Element
1694
- #}
1695
- #return nil
1685
+ XPath::first( @element, index )
1696
1686
  end
1697
1687
  end
1698
1688
 
@@ -1739,7 +1729,7 @@ module REXML
1739
1729
  else
1740
1730
  previous.replace_with element
1741
1731
  end
1742
- return previous
1732
+ previous
1743
1733
  end
1744
1734
 
1745
1735
  # :call-seq:
@@ -1778,7 +1768,7 @@ module REXML
1778
1768
  child == element
1779
1769
  end
1780
1770
  return rv if found == element
1781
- return -1
1771
+ -1
1782
1772
  end
1783
1773
 
1784
1774
  # :call-seq:
@@ -1857,7 +1847,7 @@ module REXML
1857
1847
  @element.delete element
1858
1848
  element.remove
1859
1849
  end
1860
- return rv
1850
+ rv
1861
1851
  end
1862
1852
 
1863
1853
  # :call-seq:
@@ -2184,8 +2174,7 @@ module REXML
2184
2174
  #
2185
2175
  def [](name)
2186
2176
  attr = get_attribute(name)
2187
- return attr.value unless attr.nil?
2188
- return nil
2177
+ attr&.value
2189
2178
  end
2190
2179
 
2191
2180
  # :call-seq:
@@ -2328,11 +2317,11 @@ module REXML
2328
2317
  return attr
2329
2318
  end
2330
2319
  end
2331
- element_document = @element.document
2332
- if element_document and element_document.doctype
2320
+ doctype = @element.document&.doctype
2321
+ if doctype
2333
2322
  expn = @element.expanded_name
2334
- expn = element_document.doctype.name if expn.size == 0
2335
- attr_val = element_document.doctype.attribute_of(expn, name)
2323
+ expn = doctype.name if expn.size == 0
2324
+ attr_val = doctype.attribute_of(expn, name)
2336
2325
  return Attribute.new( name, attr_val ) if attr_val
2337
2326
  end
2338
2327
  return nil
@@ -2340,7 +2329,7 @@ module REXML
2340
2329
  if attr.kind_of? Hash
2341
2330
  attr = attr[ @element.prefix ]
2342
2331
  end
2343
- return attr
2332
+ attr
2344
2333
  end
2345
2334
 
2346
2335
  # :call-seq:
@@ -2374,8 +2363,9 @@ module REXML
2374
2363
  end
2375
2364
 
2376
2365
  unless value.kind_of? Attribute
2377
- if @element.document and @element.document.doctype
2378
- value = Text::normalize( value, @element.document.doctype )
2366
+ doctype = @element.document&.doctype
2367
+ if doctype
2368
+ value = Text::normalize( value, doctype )
2379
2369
  else
2380
2370
  value = Text::normalize( value, nil )
2381
2371
  end
@@ -2388,23 +2378,12 @@ module REXML
2388
2378
  elsif old_attr.kind_of? Hash
2389
2379
  old_attr[value.prefix] = value
2390
2380
  elsif old_attr.prefix != value.prefix
2391
- # Check for conflicting namespaces
2392
- if value.prefix != "xmlns" and old_attr.prefix != "xmlns"
2393
- old_namespace = old_attr.namespace
2394
- new_namespace = value.namespace
2395
- if old_namespace == new_namespace
2396
- raise ParseException.new(
2397
- "Namespace conflict in adding attribute \"#{value.name}\": "+
2398
- "Prefix \"#{old_attr.prefix}\" = \"#{old_namespace}\" and "+
2399
- "prefix \"#{value.prefix}\" = \"#{new_namespace}\"")
2400
- end
2401
- end
2402
2381
  store value.name, {old_attr.prefix => old_attr,
2403
2382
  value.prefix => value}
2404
2383
  else
2405
2384
  store value.name, value
2406
2385
  end
2407
- return @element
2386
+ @element
2408
2387
  end
2409
2388
 
2410
2389
  # :call-seq:
@@ -2423,10 +2402,11 @@ module REXML
2423
2402
  each_attribute do |attribute|
2424
2403
  ns << attribute.name if attribute.prefix == 'xmlns'
2425
2404
  end
2426
- if @element.document and @element.document.doctype
2405
+ doctype = @element.document&.doctype
2406
+ if doctype
2427
2407
  expn = @element.expanded_name
2428
- expn = @element.document.doctype.name if expn.size == 0
2429
- @element.document.doctype.attributes_of(expn).each {
2408
+ expn = doctype.name if expn.size == 0
2409
+ doctype.attributes_of(expn).each {
2430
2410
  |attribute|
2431
2411
  ns << attribute.name if attribute.prefix == 'xmlns'
2432
2412
  }
@@ -2448,10 +2428,11 @@ module REXML
2448
2428
  each_attribute do |attribute|
2449
2429
  namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
2450
2430
  end
2451
- if @element.document and @element.document.doctype
2431
+ doctype = @element.document&.doctype
2432
+ if doctype
2452
2433
  expn = @element.expanded_name
2453
- expn = @element.document.doctype.name if expn.size == 0
2454
- @element.document.doctype.attributes_of(expn).each {
2434
+ expn = doctype.name if expn.size == 0
2435
+ doctype.attributes_of(expn).each {
2455
2436
  |attribute|
2456
2437
  namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
2457
2438
  }
@@ -2506,9 +2487,7 @@ module REXML
2506
2487
  old.each_value{|v| repl = v}
2507
2488
  store name, repl
2508
2489
  end
2509
- elsif old.nil?
2510
- return @element
2511
- else # the supplied attribute is a top-level one
2490
+ elsif old # the supplied attribute is a top-level one
2512
2491
  super(name)
2513
2492
  end
2514
2493
  @element
@@ -2562,7 +2541,7 @@ module REXML
2562
2541
  rv << attribute if attribute.expanded_name == name
2563
2542
  }
2564
2543
  rv.each{ |attr| attr.remove }
2565
- return rv
2544
+ rv
2566
2545
  end
2567
2546
 
2568
2547
  # :call-seq:
@@ -5,7 +5,7 @@ module REXML
5
5
  # ID ---> Encoding name
6
6
  attr_reader :encoding
7
7
  def encoding=(encoding)
8
- encoding = encoding.name if encoding.is_a?(Encoding)
8
+ encoding = encoding.name if encoding.is_a?(::Encoding)
9
9
  if encoding.is_a?(String)
10
10
  original_encoding = encoding
11
11
  encoding = find_encoding(encoding)
@@ -13,12 +13,9 @@ module REXML
13
13
  raise ArgumentError, "Bad encoding name #{original_encoding}"
14
14
  end
15
15
  end
16
+ encoding = encoding.upcase if encoding
16
17
  return false if defined?(@encoding) and encoding == @encoding
17
- if encoding
18
- @encoding = encoding.upcase
19
- else
20
- @encoding = 'UTF-8'
21
- end
18
+ @encoding = encoding || "UTF-8"
22
19
  true
23
20
  end
24
21
 
data/lib/rexml/entity.rb CHANGED
@@ -12,6 +12,7 @@ module REXML
12
12
  EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
13
13
  NDATADECL = "\\s+NDATA\\s+#{NAME}"
14
14
  PEREFERENCE = "%#{NAME};"
15
+ PEREFERENCE_RE = /#{PEREFERENCE}/um
15
16
  ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
16
17
  PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
17
18
  ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
@@ -19,7 +20,7 @@ module REXML
19
20
  GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
20
21
  ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
21
22
 
22
- attr_reader :name, :external, :ref, :ndata, :pubid
23
+ attr_reader :name, :external, :ref, :ndata, :pubid, :value
23
24
 
24
25
  # Create a new entity. Simple entities can be constructed by passing a
25
26
  # name, value to the constructor; this creates a generic, plain entity
@@ -68,14 +69,14 @@ module REXML
68
69
  end
69
70
 
70
71
  # Evaluates to the unnormalized value of this entity; that is, replacing
71
- # all entities -- both %ent; and &ent; entities. This differs from
72
- # +value()+ in that +value+ only replaces %ent; entities.
72
+ # &ent; entities.
73
73
  def unnormalized
74
- document.record_entity_expansion unless document.nil?
75
- v = value()
76
- return nil if v.nil?
77
- @unnormalized = Text::unnormalize(v, parent)
78
- @unnormalized
74
+ document&.record_entity_expansion
75
+
76
+ return nil if @value.nil?
77
+
78
+ @unnormalized = Text::unnormalize(@value, parent,
79
+ entity_expansion_text_limit: document&.entity_expansion_text_limit)
79
80
  end
80
81
 
81
82
  #once :unnormalized
@@ -121,46 +122,6 @@ module REXML
121
122
  write rv
122
123
  rv
123
124
  end
124
-
125
- PEREFERENCE_RE = /#{PEREFERENCE}/um
126
- # Returns the value of this entity. At the moment, only internal entities
127
- # are processed. If the value contains internal references (IE,
128
- # %blah;), those are replaced with their values. IE, if the doctype
129
- # contains:
130
- # <!ENTITY % foo "bar">
131
- # <!ENTITY yada "nanoo %foo; nanoo>
132
- # then:
133
- # doctype.entity('yada').value #-> "nanoo bar nanoo"
134
- def value
135
- @resolved_value ||= resolve_value
136
- end
137
-
138
- def parent=(other)
139
- @resolved_value = nil
140
- super
141
- end
142
-
143
- private
144
- def resolve_value
145
- return nil if @value.nil?
146
- return @value unless @value.match?(PEREFERENCE_RE)
147
-
148
- matches = @value.scan(PEREFERENCE_RE)
149
- rv = @value.clone
150
- if @parent
151
- sum = 0
152
- matches.each do |entity_reference|
153
- entity_value = @parent.entity( entity_reference[0] )
154
- if sum + entity_value.bytesize > Security.entity_expansion_text_limit
155
- raise "entity expansion has grown too large"
156
- else
157
- sum += entity_value.bytesize
158
- end
159
- rv.gsub!( /%#{entity_reference.join};/um, entity_value )
160
- end
161
- end
162
- rv
163
- end
164
125
  end
165
126
 
166
127
  # This is a set of entity constants -- the ones defined in the XML
@@ -111,7 +111,7 @@ module REXML
111
111
  # itself, then we don't need a carriage return... which makes this
112
112
  # logic more complex.
113
113
  node.children.each { |child|
114
- next if child == node.children[-1] and child.instance_of?(Text)
114
+ next if child.instance_of?(Text)
115
115
  unless child == node.children[0] or child.instance_of?(Text) or
116
116
  (child == node.children[1] and !node.children[0].writethis)
117
117
  output << "\n"
@@ -39,11 +39,11 @@ module REXML
39
39
 
40
40
  def Functions::text( )
41
41
  if @@context[:node].node_type == :element
42
- return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value}
42
+ @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value}
43
43
  elsif @@context[:node].node_type == :text
44
- return @@context[:node].value
44
+ @@context[:node].value
45
45
  else
46
- return false
46
+ false
47
47
  end
48
48
  end
49
49
 
@@ -262,11 +262,10 @@ module REXML
262
262
  string(string).length
263
263
  end
264
264
 
265
- # UNTESTED
266
265
  def Functions::normalize_space( string=nil )
267
266
  string = string(@@context[:node]) if string.nil?
268
267
  if string.kind_of? Array
269
- string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
268
+ string.collect{|x| x.to_s.strip.gsub(/\s+/um, ' ') if x}
270
269
  else
271
270
  string.to_s.strip.gsub(/\s+/um, ' ')
272
271
  end
@@ -49,7 +49,7 @@ module REXML
49
49
  # See the rexml/formatters package
50
50
  #
51
51
  def write writer, indent=-1, transitive=false, ie_hack=false
52
- Kernel.warn( "#{self.class.name}.write is deprecated", uplevel: 1)
52
+ Kernel.warn( "#{self.class.name}#write is deprecated", uplevel: 1)
53
53
  indent(writer, indent)
54
54
  writer << START
55
55
  writer << @target
@@ -42,11 +42,11 @@ module REXML
42
42
  # Compares names optionally WITH namespaces
43
43
  def has_name?( other, ns=nil )
44
44
  if ns
45
- return (namespace() == ns and name() == other)
45
+ namespace() == ns and name() == other
46
46
  elsif other.include? ":"
47
- return fully_expanded_name == other
47
+ fully_expanded_name == other
48
48
  else
49
- return name == other
49
+ name == other
50
50
  end
51
51
  end
52
52
 
@@ -57,7 +57,7 @@ module REXML
57
57
  def fully_expanded_name
58
58
  ns = prefix
59
59
  return "#{ns}:#@name" if ns.size > 0
60
- return @name
60
+ @name
61
61
  end
62
62
  end
63
63
  end
data/lib/rexml/node.rb CHANGED
@@ -26,7 +26,7 @@ module REXML
26
26
  # REXML::Formatters package for changing the output style.
27
27
  def to_s indent=nil
28
28
  unless indent.nil?
29
- Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated", uplevel: 1)
29
+ Kernel.warn( "#{self.class.name}#to_s(indent) parameter is deprecated", uplevel: 1)
30
30
  f = REXML::Formatters::Pretty.new( indent )
31
31
  f.write( self, rv = "" )
32
32
  else
@@ -52,10 +52,14 @@ module REXML
52
52
 
53
53
  # Visit all subnodes of +self+ recursively
54
54
  def each_recursive(&block) # :yields: node
55
- self.elements.each {|node|
56
- block.call(node)
57
- node.each_recursive(&block)
58
- }
55
+ stack = []
56
+ each { |child| stack.unshift child if child.node_type == :element }
57
+ until stack.empty?
58
+ child = stack.pop
59
+ yield child
60
+ n = stack.size
61
+ child.each { |grandchild| stack.insert n, grandchild if grandchild.node_type == :element }
62
+ end
59
63
  end
60
64
 
61
65
  # Find (and return) first subnode (recursively) for which the block
@@ -64,7 +68,7 @@ module REXML
64
68
  each_recursive {|node|
65
69
  return node if block.call(node)
66
70
  }
67
- return nil
71
+ nil
68
72
  end
69
73
 
70
74
  # Returns the position that +self+ holds in its parent's array, indexed
@@ -29,6 +29,7 @@ module REXML
29
29
  err << "\nLine: #{line}\n"
30
30
  err << "Position: #{position}\n"
31
31
  err << "Last 80 unconsumed characters:\n"
32
+ err.force_encoding("ASCII-8BIT")
32
33
  err << @source.buffer[0..80].force_encoding("ASCII-8BIT").gsub(/\n/, ' ')
33
34
  end
34
35