rexml 3.2.3 → 3.2.8
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 +219 -0
- data/README.md +11 -14
- 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/doc/rexml/tutorial.rdoc +1358 -0
- data/lib/rexml/attribute.rb +14 -9
- 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 +26 -16
- data/lib/rexml/formatters/pretty.rb +2 -2
- data/lib/rexml/functions.rb +1 -2
- data/lib/rexml/light/node.rb +0 -8
- data/lib/rexml/namespace.rb +8 -4
- data/lib/rexml/parseexception.rb +1 -0
- data/lib/rexml/parsers/baseparser.rb +321 -222
- data/lib/rexml/parsers/xpathparser.rb +161 -97
- data/lib/rexml/rexml.rb +29 -22
- data/lib/rexml/source.rb +72 -99
- data/lib/rexml/text.rb +7 -5
- data/lib/rexml/xpath_parser.rb +43 -33
- data/lib/rexml.rb +3 -0
- metadata +43 -34
- data/.gitignore +0 -9
- data/.travis.yml +0 -24
- data/Gemfile +0 -6
- data/Rakefile +0 -8
- data/rexml.gemspec +0 -84
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/doctype.rb
CHANGED
@@ -7,6 +7,44 @@ require_relative 'attlistdecl'
|
|
7
7
|
require_relative 'xmltokens'
|
8
8
|
|
9
9
|
module REXML
|
10
|
+
class ReferenceWriter
|
11
|
+
def initialize(id_type,
|
12
|
+
public_id_literal,
|
13
|
+
system_literal,
|
14
|
+
context=nil)
|
15
|
+
@id_type = id_type
|
16
|
+
@public_id_literal = public_id_literal
|
17
|
+
@system_literal = system_literal
|
18
|
+
if context and context[:prologue_quote] == :apostrophe
|
19
|
+
@default_quote = "'"
|
20
|
+
else
|
21
|
+
@default_quote = "\""
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(output)
|
26
|
+
output << " #{@id_type}"
|
27
|
+
if @public_id_literal
|
28
|
+
if @public_id_literal.include?("'")
|
29
|
+
quote = "\""
|
30
|
+
else
|
31
|
+
quote = @default_quote
|
32
|
+
end
|
33
|
+
output << " #{quote}#{@public_id_literal}#{quote}"
|
34
|
+
end
|
35
|
+
if @system_literal
|
36
|
+
if @system_literal.include?("'")
|
37
|
+
quote = "\""
|
38
|
+
elsif @system_literal.include?("\"")
|
39
|
+
quote = "'"
|
40
|
+
else
|
41
|
+
quote = @default_quote
|
42
|
+
end
|
43
|
+
output << " #{quote}#{@system_literal}#{quote}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
10
48
|
# Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
|
11
49
|
# ... >. DOCTYPES can be used to declare the DTD of a document, as well as
|
12
50
|
# being used to declare entities used in the document.
|
@@ -50,6 +88,8 @@ module REXML
|
|
50
88
|
super( parent )
|
51
89
|
@name = first.name
|
52
90
|
@external_id = first.external_id
|
91
|
+
@long_name = first.instance_variable_get(:@long_name)
|
92
|
+
@uri = first.instance_variable_get(:@uri)
|
53
93
|
elsif first.kind_of? Array
|
54
94
|
super( parent )
|
55
95
|
@name = first[0]
|
@@ -108,19 +148,17 @@ module REXML
|
|
108
148
|
# Ignored
|
109
149
|
def write( output, indent=0, transitive=false, ie_hack=false )
|
110
150
|
f = REXML::Formatters::Default.new
|
111
|
-
c = context
|
112
|
-
if c and c[:prologue_quote] == :apostrophe
|
113
|
-
quote = "'"
|
114
|
-
else
|
115
|
-
quote = "\""
|
116
|
-
end
|
117
151
|
indent( output, indent )
|
118
152
|
output << START
|
119
153
|
output << ' '
|
120
154
|
output << @name
|
121
|
-
|
122
|
-
|
123
|
-
|
155
|
+
if @external_id
|
156
|
+
reference_writer = ReferenceWriter.new(@external_id,
|
157
|
+
@long_name,
|
158
|
+
@uri,
|
159
|
+
context)
|
160
|
+
reference_writer.write(output)
|
161
|
+
end
|
124
162
|
unless @children.empty?
|
125
163
|
output << ' ['
|
126
164
|
@children.each { |child|
|
@@ -159,7 +197,7 @@ module REXML
|
|
159
197
|
when "SYSTEM"
|
160
198
|
nil
|
161
199
|
when "PUBLIC"
|
162
|
-
|
200
|
+
@long_name
|
163
201
|
end
|
164
202
|
end
|
165
203
|
|
@@ -169,9 +207,9 @@ module REXML
|
|
169
207
|
def system
|
170
208
|
case @external_id
|
171
209
|
when "SYSTEM"
|
172
|
-
|
210
|
+
@long_name
|
173
211
|
when "PUBLIC"
|
174
|
-
@uri.kind_of?(String) ?
|
212
|
+
@uri.kind_of?(String) ? @uri : nil
|
175
213
|
end
|
176
214
|
end
|
177
215
|
|
@@ -193,15 +231,6 @@ module REXML
|
|
193
231
|
notation_decl.name == name
|
194
232
|
}
|
195
233
|
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
# Method contributed by Henrik Martensson
|
200
|
-
def strip_quotes(quoted_string)
|
201
|
-
quoted_string =~ /^[\'\"].*[\'\"]$/ ?
|
202
|
-
quoted_string[1, quoted_string.length-2] :
|
203
|
-
quoted_string
|
204
|
-
end
|
205
234
|
end
|
206
235
|
|
207
236
|
# We don't really handle any of these since we're not a validating
|
@@ -259,16 +288,11 @@ module REXML
|
|
259
288
|
end
|
260
289
|
|
261
290
|
def to_s
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
quote = "\""
|
268
|
-
end
|
269
|
-
notation = "<!NOTATION #{@name} #{@middle}"
|
270
|
-
notation << " #{quote}#{@public}#{quote}" if @public
|
271
|
-
notation << " #{quote}#{@system}#{quote}" if @system
|
291
|
+
context = nil
|
292
|
+
context = parent.context if parent
|
293
|
+
notation = "<!NOTATION #{@name}"
|
294
|
+
reference_writer = ReferenceWriter.new(@middle, @public, @system, context)
|
295
|
+
reference_writer.write(notation)
|
272
296
|
notation << ">"
|
273
297
|
notation
|
274
298
|
end
|
data/lib/rexml/document.rb
CHANGED
@@ -14,25 +14,81 @@ require_relative "parsers/streamparser"
|
|
14
14
|
require_relative "parsers/treeparser"
|
15
15
|
|
16
16
|
module REXML
|
17
|
-
# Represents
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
17
|
+
# Represents an XML document.
|
18
|
+
#
|
19
|
+
# A document may have:
|
20
|
+
#
|
21
|
+
# - A single child that may be accessed via method #root.
|
22
|
+
# - An XML declaration.
|
23
|
+
# - A document type.
|
24
|
+
# - Processing instructions.
|
25
|
+
#
|
26
|
+
# == In a Hurry?
|
27
|
+
#
|
28
|
+
# If you're somewhat familiar with XML
|
29
|
+
# and have a particular task in mind,
|
30
|
+
# you may want to see the
|
31
|
+
# {tasks pages}[../doc/rexml/tasks/tocs/master_toc_rdoc.html],
|
32
|
+
# and in particular, the
|
33
|
+
# {tasks page for documents}[../doc/rexml/tasks/tocs/document_toc_rdoc.html].
|
34
|
+
#
|
22
35
|
class Document < Element
|
23
|
-
# A convenient default XML declaration.
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
36
|
+
# A convenient default XML declaration. Use:
|
37
|
+
#
|
38
|
+
# mydoc << XMLDecl.default
|
39
|
+
#
|
27
40
|
DECLARATION = XMLDecl.default
|
28
41
|
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
42
|
+
# :call-seq:
|
43
|
+
# new(string = nil, context = {}) -> new_document
|
44
|
+
# new(io_stream = nil, context = {}) -> new_document
|
45
|
+
# new(document = nil, context = {}) -> new_document
|
46
|
+
#
|
47
|
+
# Returns a new \REXML::Document object.
|
48
|
+
#
|
49
|
+
# When no arguments are given,
|
50
|
+
# returns an empty document:
|
51
|
+
#
|
52
|
+
# d = REXML::Document.new
|
53
|
+
# d.to_s # => ""
|
54
|
+
#
|
55
|
+
# When argument +string+ is given, it must be a string
|
56
|
+
# containing a valid XML document:
|
57
|
+
#
|
58
|
+
# xml_string = '<root><foo>Foo</foo><bar>Bar</bar></root>'
|
59
|
+
# d = REXML::Document.new(xml_string)
|
60
|
+
# d.to_s # => "<root><foo>Foo</foo><bar>Bar</bar></root>"
|
61
|
+
#
|
62
|
+
# When argument +io_stream+ is given, it must be an \IO object
|
63
|
+
# that is opened for reading, and when read must return a valid XML document:
|
64
|
+
#
|
65
|
+
# File.write('t.xml', xml_string)
|
66
|
+
# d = File.open('t.xml', 'r') do |io|
|
67
|
+
# REXML::Document.new(io)
|
68
|
+
# end
|
69
|
+
# d.to_s # => "<root><foo>Foo</foo><bar>Bar</bar></root>"
|
70
|
+
#
|
71
|
+
# When argument +document+ is given, it must be an existing
|
72
|
+
# document object, whose context and attributes (but not children)
|
73
|
+
# are cloned into the new document:
|
74
|
+
#
|
75
|
+
# d = REXML::Document.new(xml_string)
|
76
|
+
# d.children # => [<root> ... </>]
|
77
|
+
# d.context = {raw: :all, compress_whitespace: :all}
|
78
|
+
# d.add_attributes({'bar' => 0, 'baz' => 1})
|
79
|
+
# d1 = REXML::Document.new(d)
|
80
|
+
# d1.children # => []
|
81
|
+
# d1.context # => {:raw=>:all, :compress_whitespace=>:all}
|
82
|
+
# d1.attributes # => {"bar"=>bar='0', "baz"=>baz='1'}
|
83
|
+
#
|
84
|
+
# When argument +context+ is given, it must be a hash
|
85
|
+
# containing context entries for the document;
|
86
|
+
# see {Element Context}[../doc/rexml/context_rdoc.html]:
|
87
|
+
#
|
88
|
+
# context = {raw: :all, compress_whitespace: :all}
|
89
|
+
# d = REXML::Document.new(xml_string, context)
|
90
|
+
# d.context # => {:raw=>:all, :compress_whitespace=>:all}
|
91
|
+
#
|
36
92
|
def initialize( source = nil, context = {} )
|
37
93
|
@entity_expansion_count = 0
|
38
94
|
super()
|
@@ -46,26 +102,71 @@ module REXML
|
|
46
102
|
end
|
47
103
|
end
|
48
104
|
|
105
|
+
# :call-seq:
|
106
|
+
# node_type -> :document
|
107
|
+
#
|
108
|
+
# Returns the symbol +:document+.
|
109
|
+
#
|
49
110
|
def node_type
|
50
111
|
:document
|
51
112
|
end
|
52
113
|
|
53
|
-
#
|
114
|
+
# :call-seq:
|
115
|
+
# clone -> new_document
|
116
|
+
#
|
117
|
+
# Returns the new document resulting from executing
|
118
|
+
# <tt>Document.new(self)</tt>. See Document.new.
|
119
|
+
#
|
54
120
|
def clone
|
55
121
|
Document.new self
|
56
122
|
end
|
57
123
|
|
58
|
-
#
|
124
|
+
# :call-seq:
|
125
|
+
# expanded_name -> empty_string
|
126
|
+
#
|
127
|
+
# Returns an empty string.
|
128
|
+
#
|
59
129
|
def expanded_name
|
60
130
|
''
|
61
131
|
#d = doc_type
|
62
132
|
#d ? d.name : "UNDEFINED"
|
63
133
|
end
|
64
|
-
|
65
134
|
alias :name :expanded_name
|
66
135
|
|
67
|
-
#
|
68
|
-
#
|
136
|
+
# :call-seq:
|
137
|
+
# add(xml_decl) -> self
|
138
|
+
# add(doc_type) -> self
|
139
|
+
# add(object) -> self
|
140
|
+
#
|
141
|
+
# Adds an object to the document; returns +self+.
|
142
|
+
#
|
143
|
+
# When argument +xml_decl+ is given,
|
144
|
+
# it must be an REXML::XMLDecl object,
|
145
|
+
# which becomes the XML declaration for the document,
|
146
|
+
# replacing the previous XML declaration if any:
|
147
|
+
#
|
148
|
+
# d = REXML::Document.new
|
149
|
+
# d.xml_decl.to_s # => ""
|
150
|
+
# d.add(REXML::XMLDecl.new('2.0'))
|
151
|
+
# d.xml_decl.to_s # => "<?xml version='2.0'?>"
|
152
|
+
#
|
153
|
+
# When argument +doc_type+ is given,
|
154
|
+
# it must be an REXML::DocType object,
|
155
|
+
# which becomes the document type for the document,
|
156
|
+
# replacing the previous document type, if any:
|
157
|
+
#
|
158
|
+
# d = REXML::Document.new
|
159
|
+
# d.doctype.to_s # => ""
|
160
|
+
# d.add(REXML::DocType.new('foo'))
|
161
|
+
# d.doctype.to_s # => "<!DOCTYPE foo>"
|
162
|
+
#
|
163
|
+
# When argument +object+ (not an REXML::XMLDecl or REXML::DocType object)
|
164
|
+
# is given it is added as the last child:
|
165
|
+
#
|
166
|
+
# d = REXML::Document.new
|
167
|
+
# d.add(REXML::Element.new('foo'))
|
168
|
+
# d.to_s # => "<foo/>"
|
169
|
+
#
|
69
170
|
def add( child )
|
70
171
|
if child.kind_of? XMLDecl
|
71
172
|
if @children[0].kind_of? XMLDecl
|
@@ -99,49 +200,108 @@ module REXML
|
|
99
200
|
end
|
100
201
|
alias :<< :add
|
101
202
|
|
203
|
+
# :call-seq:
|
204
|
+
# add_element(name_or_element = nil, attributes = nil) -> new_element
|
205
|
+
#
|
206
|
+
# Adds an element to the document by calling REXML::Element.add_element:
|
207
|
+
#
|
208
|
+
# REXML::Element.add_element(name_or_element, attributes)
|
102
209
|
def add_element(arg=nil, arg2=nil)
|
103
210
|
rv = super
|
104
211
|
raise "attempted adding second root element to document" if @elements.size > 1
|
105
212
|
rv
|
106
213
|
end
|
107
214
|
|
108
|
-
#
|
109
|
-
#
|
215
|
+
# :call-seq:
|
216
|
+
# root -> root_element or nil
|
217
|
+
#
|
218
|
+
# Returns the root element of the document, if it exists, otherwise +nil+:
|
219
|
+
#
|
220
|
+
# d = REXML::Document.new('<root></root>')
|
221
|
+
# d.root # => <root/>
|
222
|
+
# d = REXML::Document.new('')
|
223
|
+
# d.root # => nil
|
224
|
+
#
|
110
225
|
def root
|
111
226
|
elements[1]
|
112
227
|
#self
|
113
228
|
#@children.find { |item| item.kind_of? Element }
|
114
229
|
end
|
115
230
|
|
116
|
-
#
|
117
|
-
#
|
231
|
+
# :call-seq:
|
232
|
+
# doctype -> doc_type or nil
|
233
|
+
#
|
234
|
+
# Returns the DocType object for the document, if it exists, otherwise +nil+:
|
235
|
+
#
|
236
|
+
# d = REXML::Document.new('<!DOCTYPE document SYSTEM "subjects.dtd">')
|
237
|
+
# d.doctype.class # => REXML::DocType
|
238
|
+
# d = REXML::Document.new('')
|
239
|
+
# d.doctype.class # => nil
|
240
|
+
#
|
118
241
|
def doctype
|
119
242
|
@children.find { |item| item.kind_of? DocType }
|
120
243
|
end
|
121
244
|
|
122
|
-
#
|
123
|
-
#
|
245
|
+
# :call-seq:
|
246
|
+
# xml_decl -> xml_decl
|
247
|
+
#
|
248
|
+
# Returns the XMLDecl object for the document, if it exists,
|
249
|
+
# otherwise the default XMLDecl object:
|
250
|
+
#
|
251
|
+
# d = REXML::Document.new('<?xml version="1.0" encoding="UTF-8"?>')
|
252
|
+
# d.xml_decl.class # => REXML::XMLDecl
|
253
|
+
# d.xml_decl.to_s # => "<?xml version='1.0' encoding='UTF-8'?>"
|
254
|
+
# d = REXML::Document.new('')
|
255
|
+
# d.xml_decl.class # => REXML::XMLDecl
|
256
|
+
# d.xml_decl.to_s # => ""
|
257
|
+
#
|
124
258
|
def xml_decl
|
125
259
|
rv = @children[0]
|
126
260
|
return rv if rv.kind_of? XMLDecl
|
127
261
|
@children.unshift(XMLDecl.default)[0]
|
128
262
|
end
|
129
263
|
|
130
|
-
#
|
131
|
-
#
|
264
|
+
# :call-seq:
|
265
|
+
# version -> version_string
|
266
|
+
#
|
267
|
+
# Returns the XMLDecl version of this document as a string,
|
268
|
+
# if it has been set, otherwise the default version:
|
269
|
+
#
|
270
|
+
# d = REXML::Document.new('<?xml version="2.0" encoding="UTF-8"?>')
|
271
|
+
# d.version # => "2.0"
|
272
|
+
# d = REXML::Document.new('')
|
273
|
+
# d.version # => "1.0"
|
274
|
+
#
|
132
275
|
def version
|
133
276
|
xml_decl().version
|
134
277
|
end
|
135
278
|
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
279
|
+
# :call-seq:
|
280
|
+
# encoding -> encoding_string
|
281
|
+
#
|
282
|
+
# Returns the XMLDecl encoding of the document,
|
283
|
+
# if it has been set, otherwise the default encoding:
|
284
|
+
#
|
285
|
+
# d = REXML::Document.new('<?xml version="1.0" encoding="UTF-16"?>')
|
286
|
+
# d.encoding # => "UTF-16"
|
287
|
+
# d = REXML::Document.new('')
|
288
|
+
# d.encoding # => "UTF-8"
|
289
|
+
#
|
139
290
|
def encoding
|
140
291
|
xml_decl().encoding
|
141
292
|
end
|
142
293
|
|
143
|
-
#
|
144
|
-
#
|
294
|
+
# :call-seq:
|
295
|
+
# stand_alone?
|
296
|
+
#
|
297
|
+
# Returns the XMLDecl standalone value of the document as a string,
|
298
|
+
# if it has been set, otherwise the default standalone value:
|
299
|
+
#
|
300
|
+
# d = REXML::Document.new('<?xml standalone="yes"?>')
|
301
|
+
# d.stand_alone? # => "yes"
|
302
|
+
# d = REXML::Document.new('')
|
303
|
+
# d.stand_alone? # => nil
|
304
|
+
#
|
145
305
|
def stand_alone?
|
146
306
|
xml_decl().stand_alone?
|
147
307
|
end
|