rexml 3.2.5 → 3.3.1
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 +251 -2
- data/README.md +10 -1
- data/doc/rexml/tasks/rdoc/element.rdoc +2 -2
- data/doc/rexml/tutorial.rdoc +1358 -0
- data/lib/rexml/attribute.rb +14 -9
- data/lib/rexml/document.rb +1 -1
- data/lib/rexml/element.rb +5 -18
- data/lib/rexml/entity.rb +25 -15
- data/lib/rexml/formatters/pretty.rb +2 -2
- data/lib/rexml/functions.rb +1 -2
- data/lib/rexml/namespace.rb +8 -4
- data/lib/rexml/node.rb +8 -4
- data/lib/rexml/parseexception.rb +1 -0
- data/lib/rexml/parsers/baseparser.rb +281 -240
- data/lib/rexml/parsers/treeparser.rb +9 -14
- data/lib/rexml/parsers/xpathparser.rb +136 -86
- data/lib/rexml/rexml.rb +3 -1
- data/lib/rexml/source.rb +120 -100
- data/lib/rexml/text.rb +6 -4
- data/lib/rexml/xpath_parser.rb +7 -3
- metadata +11 -39
data/lib/rexml/attribute.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require_relative "namespace"
|
3
3
|
require_relative 'text'
|
4
4
|
|
@@ -13,9 +13,6 @@ module REXML
|
|
13
13
|
|
14
14
|
# The element to which this attribute belongs
|
15
15
|
attr_reader :element
|
16
|
-
# The normalized value of this attribute. That is, the attribute with
|
17
|
-
# entities intact.
|
18
|
-
attr_writer :normalized
|
19
16
|
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
|
20
17
|
|
21
18
|
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
|
@@ -122,10 +119,13 @@ module REXML
|
|
122
119
|
# b = Attribute.new( "ns:x", "y" )
|
123
120
|
# b.to_string # -> "ns:x='y'"
|
124
121
|
def to_string
|
122
|
+
value = to_s
|
125
123
|
if @element and @element.context and @element.context[:attribute_quote] == :quote
|
126
|
-
|
124
|
+
value = value.gsub('"', '"') if value.include?('"')
|
125
|
+
%Q^#@expanded_name="#{value}"^
|
127
126
|
else
|
128
|
-
|
127
|
+
value = value.gsub("'", ''') if value.include?("'")
|
128
|
+
"#@expanded_name='#{value}'"
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
@@ -141,7 +141,6 @@ module REXML
|
|
141
141
|
return @normalized if @normalized
|
142
142
|
|
143
143
|
@normalized = Text::normalize( @unnormalized, doctype )
|
144
|
-
@unnormalized = nil
|
145
144
|
@normalized
|
146
145
|
end
|
147
146
|
|
@@ -150,10 +149,16 @@ module REXML
|
|
150
149
|
def value
|
151
150
|
return @unnormalized if @unnormalized
|
152
151
|
@unnormalized = Text::unnormalize( @normalized, doctype )
|
153
|
-
@normalized = nil
|
154
152
|
@unnormalized
|
155
153
|
end
|
156
154
|
|
155
|
+
# The normalized value of this attribute. That is, the attribute with
|
156
|
+
# entities intact.
|
157
|
+
def normalized=(new_normalized)
|
158
|
+
@normalized = new_normalized
|
159
|
+
@unnormalized = nil
|
160
|
+
end
|
161
|
+
|
157
162
|
# Returns a copy of this attribute
|
158
163
|
def clone
|
159
164
|
Attribute.new self
|
@@ -190,7 +195,7 @@ module REXML
|
|
190
195
|
end
|
191
196
|
|
192
197
|
def inspect
|
193
|
-
rv = ""
|
198
|
+
rv = +""
|
194
199
|
write( rv )
|
195
200
|
rv
|
196
201
|
end
|
data/lib/rexml/document.rb
CHANGED
@@ -69,7 +69,7 @@ module REXML
|
|
69
69
|
# d.to_s # => "<root><foo>Foo</foo><bar>Bar</bar></root>"
|
70
70
|
#
|
71
71
|
# When argument +document+ is given, it must be an existing
|
72
|
-
# document object, whose context and attributes (but not
|
72
|
+
# document object, whose context and attributes (but not children)
|
73
73
|
# are cloned into the new document:
|
74
74
|
#
|
75
75
|
# d = REXML::Document.new(xml_string)
|
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:
|
@@ -989,7 +981,7 @@ module REXML
|
|
989
981
|
# :call-seq:
|
990
982
|
# has_text? -> true or false
|
991
983
|
#
|
992
|
-
# Returns +true if the element has one or more text noded,
|
984
|
+
# Returns +true+ if the element has one or more text noded,
|
993
985
|
# +false+ otherwise:
|
994
986
|
#
|
995
987
|
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
@@ -1006,7 +998,7 @@ module REXML
|
|
1006
998
|
# text(xpath = nil) -> text_string or nil
|
1007
999
|
#
|
1008
1000
|
# Returns the text string from the first text node child
|
1009
|
-
# in a specified element, if it exists,
|
1001
|
+
# in a specified element, if it exists, +nil+ otherwise.
|
1010
1002
|
#
|
1011
1003
|
# With no argument, returns the text from the first text node in +self+:
|
1012
1004
|
#
|
@@ -1014,7 +1006,7 @@ module REXML
|
|
1014
1006
|
# d.root.text.class # => String
|
1015
1007
|
# d.root.text # => "some text "
|
1016
1008
|
#
|
1017
|
-
# With argument +xpath+, returns text from the
|
1009
|
+
# With argument +xpath+, returns text from the first text node
|
1018
1010
|
# in the element that matches +xpath+:
|
1019
1011
|
#
|
1020
1012
|
# d.root.text(1) # => "this is bold!"
|
@@ -1284,16 +1276,11 @@ module REXML
|
|
1284
1276
|
# document.root.attribute("x", "a") # => a:x='a:x'
|
1285
1277
|
#
|
1286
1278
|
def attribute( name, namespace=nil )
|
1287
|
-
prefix =
|
1288
|
-
if namespaces.respond_to? :key
|
1289
|
-
prefix = namespaces.key(namespace) if namespace
|
1290
|
-
else
|
1291
|
-
prefix = namespaces.index(namespace) if namespace
|
1292
|
-
end
|
1279
|
+
prefix = namespaces.key(namespace) if namespace
|
1293
1280
|
prefix = nil if prefix == 'xmlns'
|
1294
1281
|
|
1295
1282
|
ret_val =
|
1296
|
-
attributes.get_attribute(
|
1283
|
+
attributes.get_attribute( prefix ? "#{prefix}:#{name}" : name )
|
1297
1284
|
|
1298
1285
|
return ret_val unless ret_val.nil?
|
1299
1286
|
return nil if prefix.nil?
|
data/lib/rexml/entity.rb
CHANGED
@@ -132,24 +132,34 @@ module REXML
|
|
132
132
|
# then:
|
133
133
|
# doctype.entity('yada').value #-> "nanoo bar nanoo"
|
134
134
|
def value
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|
148
158
|
end
|
159
|
+
rv.gsub!( /%#{entity_reference.join};/um, entity_value )
|
149
160
|
end
|
150
|
-
return rv
|
151
161
|
end
|
152
|
-
|
162
|
+
rv
|
153
163
|
end
|
154
164
|
end
|
155
165
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require_relative 'default'
|
3
3
|
|
4
4
|
module REXML
|
@@ -58,7 +58,7 @@ module REXML
|
|
58
58
|
skip = false
|
59
59
|
if compact
|
60
60
|
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
|
61
|
-
string = ""
|
61
|
+
string = +""
|
62
62
|
old_level = @level
|
63
63
|
@level = 0
|
64
64
|
node.children.each { |child| write( child, string ) }
|
data/lib/rexml/functions.rb
CHANGED
@@ -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|
|
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
|
data/lib/rexml/namespace.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'xmltokens'
|
4
4
|
|
@@ -10,13 +10,17 @@ module REXML
|
|
10
10
|
# The expanded name of the object, valid if name is set
|
11
11
|
attr_accessor :prefix
|
12
12
|
include XMLTokens
|
13
|
+
NAME_WITHOUT_NAMESPACE = /\A#{NCNAME_STR}\z/
|
13
14
|
NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
|
14
15
|
|
15
16
|
# Sets the name and the expanded name
|
16
17
|
def name=( name )
|
17
18
|
@expanded_name = name
|
18
|
-
|
19
|
-
|
19
|
+
if name.match?(NAME_WITHOUT_NAMESPACE)
|
20
|
+
@prefix = ""
|
21
|
+
@namespace = ""
|
22
|
+
@name = name
|
23
|
+
elsif name =~ NAMESPLIT
|
20
24
|
if $1
|
21
25
|
@prefix = $1
|
22
26
|
else
|
@@ -24,7 +28,7 @@ module REXML
|
|
24
28
|
@namespace = ""
|
25
29
|
end
|
26
30
|
@name = $2
|
27
|
-
|
31
|
+
elsif name == ""
|
28
32
|
@prefix = nil
|
29
33
|
@namespace = nil
|
30
34
|
@name = nil
|
data/lib/rexml/node.rb
CHANGED
@@ -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
|
-
|
56
|
-
|
57
|
-
|
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
|
data/lib/rexml/parseexception.rb
CHANGED