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/element.rb
CHANGED
@@ -15,9 +15,267 @@ module REXML
|
|
15
15
|
# context node and convert it back when we write it.
|
16
16
|
@@namespaces = {}
|
17
17
|
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
18
|
+
# An \REXML::Element object represents an XML element.
|
19
|
+
#
|
20
|
+
# An element:
|
21
|
+
#
|
22
|
+
# - Has a name (string).
|
23
|
+
# - May have a parent (another element).
|
24
|
+
# - Has zero or more children
|
25
|
+
# (other elements, text, CDATA, processing instructions, and comments).
|
26
|
+
# - Has zero or more siblings
|
27
|
+
# (other elements, text, CDATA, processing instructions, and comments).
|
28
|
+
# - Has zero or more named attributes.
|
29
|
+
#
|
30
|
+
# == In a Hurry?
|
31
|
+
#
|
32
|
+
# If you're somewhat familiar with XML
|
33
|
+
# and have a particular task in mind,
|
34
|
+
# you may want to see the
|
35
|
+
# {tasks pages}[../doc/rexml/tasks/tocs/master_toc_rdoc.html],
|
36
|
+
# and in particular, the
|
37
|
+
# {tasks page for elements}[../doc/rexml/tasks/tocs/element_toc_rdoc.html].
|
38
|
+
#
|
39
|
+
# === Name
|
40
|
+
#
|
41
|
+
# An element has a name, which is initially set when the element is created:
|
42
|
+
#
|
43
|
+
# e = REXML::Element.new('foo')
|
44
|
+
# e.name # => "foo"
|
45
|
+
#
|
46
|
+
# The name may be changed:
|
47
|
+
#
|
48
|
+
# e.name = 'bar'
|
49
|
+
# e.name # => "bar"
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# === \Parent
|
53
|
+
#
|
54
|
+
# An element may have a parent.
|
55
|
+
#
|
56
|
+
# Its parent may be assigned explicitly when the element is created:
|
57
|
+
#
|
58
|
+
# e0 = REXML::Element.new('foo')
|
59
|
+
# e1 = REXML::Element.new('bar', e0)
|
60
|
+
# e1.parent # => <foo> ... </>
|
61
|
+
#
|
62
|
+
# Note: the representation of an element always shows the element's name.
|
63
|
+
# If the element has children, the representation indicates that
|
64
|
+
# by including an ellipsis (<tt>...</tt>).
|
65
|
+
#
|
66
|
+
# The parent may be assigned explicitly at any time:
|
67
|
+
#
|
68
|
+
# e2 = REXML::Element.new('baz')
|
69
|
+
# e1.parent = e2
|
70
|
+
# e1.parent # => <baz/>
|
71
|
+
#
|
72
|
+
# When an element is added as a child, its parent is set automatically:
|
73
|
+
#
|
74
|
+
# e1.add_element(e0)
|
75
|
+
# e0.parent # => <bar> ... </>
|
76
|
+
#
|
77
|
+
# For an element that has no parent, method +parent+ returns +nil+.
|
78
|
+
#
|
79
|
+
# === Children
|
80
|
+
#
|
81
|
+
# An element has zero or more children.
|
82
|
+
# The children are an ordered collection
|
83
|
+
# of all objects whose parent is the element itself.
|
84
|
+
#
|
85
|
+
# The children may include any combination of elements, text, comments,
|
86
|
+
# processing instructions, and CDATA.
|
87
|
+
# (This example keeps things clean by controlling whitespace
|
88
|
+
# via a +context+ setting.)
|
89
|
+
#
|
90
|
+
# xml_string = <<-EOT
|
91
|
+
# <root>
|
92
|
+
# <ele_0/>
|
93
|
+
# text 0
|
94
|
+
# <!--comment 0-->
|
95
|
+
# <?target_0 pi_0?>
|
96
|
+
# <![CDATA[cdata 0]]>
|
97
|
+
# <ele_1/>
|
98
|
+
# text 1
|
99
|
+
# <!--comment 1-->
|
100
|
+
# <?target_0 pi_1?>
|
101
|
+
# <![CDATA[cdata 1]]>
|
102
|
+
# </root>
|
103
|
+
# EOT
|
104
|
+
# context = {ignore_whitespace_nodes: :all, compress_whitespace: :all}
|
105
|
+
# d = REXML::Document.new(xml_string, context)
|
106
|
+
# root = d.root
|
107
|
+
# root.children.size # => 10
|
108
|
+
# root.each {|child| p "#{child.class}: #{child}" }
|
109
|
+
#
|
110
|
+
# Output:
|
111
|
+
#
|
112
|
+
# "REXML::Element: <ele_0/>"
|
113
|
+
# "REXML::Text: \n text 0\n "
|
114
|
+
# "REXML::Comment: comment 0"
|
115
|
+
# "REXML::Instruction: <?target_0 pi_0?>"
|
116
|
+
# "REXML::CData: cdata 0"
|
117
|
+
# "REXML::Element: <ele_1/>"
|
118
|
+
# "REXML::Text: \n text 1\n "
|
119
|
+
# "REXML::Comment: comment 1"
|
120
|
+
# "REXML::Instruction: <?target_0 pi_1?>"
|
121
|
+
# "REXML::CData: cdata 1"
|
122
|
+
#
|
123
|
+
# A child may be added using inherited methods
|
124
|
+
# Parent#insert_before or Parent#insert_after:
|
125
|
+
#
|
126
|
+
# xml_string = '<root><a/><c/><d/></root>'
|
127
|
+
# d = REXML::Document.new(xml_string)
|
128
|
+
# root = d.root
|
129
|
+
# c = d.root[1] # => <c/>
|
130
|
+
# root.insert_before(c, REXML::Element.new('b'))
|
131
|
+
# root.to_a # => [<a/>, <b/>, <c/>, <d/>]
|
132
|
+
#
|
133
|
+
# A child may be replaced using Parent#replace_child:
|
134
|
+
#
|
135
|
+
# root.replace_child(c, REXML::Element.new('x'))
|
136
|
+
# root.to_a # => [<a/>, <b/>, <x/>, <d/>]
|
137
|
+
#
|
138
|
+
# A child may be removed using Parent#delete:
|
139
|
+
#
|
140
|
+
# x = root[2] # => <x/>
|
141
|
+
# root.delete(x)
|
142
|
+
# root.to_a # => [<a/>, <b/>, <d/>]
|
143
|
+
#
|
144
|
+
# === Siblings
|
145
|
+
#
|
146
|
+
# An element has zero or more siblings,
|
147
|
+
# which are the other children of the element's parent.
|
148
|
+
#
|
149
|
+
# In the example above, element +ele_1+ is between a CDATA sibling
|
150
|
+
# and a text sibling:
|
151
|
+
#
|
152
|
+
# ele_1 = root[5] # => <ele_1/>
|
153
|
+
# ele_1.previous_sibling # => "cdata 0"
|
154
|
+
# ele_1.next_sibling # => "\n text 1\n "
|
155
|
+
#
|
156
|
+
# === \Attributes
|
157
|
+
#
|
158
|
+
# An element has zero or more named attributes.
|
159
|
+
#
|
160
|
+
# A new element has no attributes:
|
161
|
+
#
|
162
|
+
# e = REXML::Element.new('foo')
|
163
|
+
# e.attributes # => {}
|
164
|
+
#
|
165
|
+
# Attributes may be added:
|
166
|
+
#
|
167
|
+
# e.add_attribute('bar', 'baz')
|
168
|
+
# e.add_attribute('bat', 'bam')
|
169
|
+
# e.attributes.size # => 2
|
170
|
+
# e['bar'] # => "baz"
|
171
|
+
# e['bat'] # => "bam"
|
172
|
+
#
|
173
|
+
# An existing attribute may be modified:
|
174
|
+
#
|
175
|
+
# e.add_attribute('bar', 'bad')
|
176
|
+
# e.attributes.size # => 2
|
177
|
+
# e['bar'] # => "bad"
|
178
|
+
#
|
179
|
+
# An existing attribute may be deleted:
|
180
|
+
#
|
181
|
+
# e.delete_attribute('bar')
|
182
|
+
# e.attributes.size # => 1
|
183
|
+
# e['bar'] # => nil
|
184
|
+
#
|
185
|
+
# == What's Here
|
186
|
+
#
|
187
|
+
# To begin with, what's elsewhere?
|
188
|
+
#
|
189
|
+
# \Class \REXML::Element inherits from its ancestor classes:
|
190
|
+
#
|
191
|
+
# - REXML::Child
|
192
|
+
# - REXML::Parent
|
193
|
+
#
|
194
|
+
# \REXML::Element itself and its ancestors also include modules:
|
195
|
+
#
|
196
|
+
# - {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html]
|
197
|
+
# - REXML::Namespace
|
198
|
+
# - REXML::Node
|
199
|
+
# - REXML::XMLTokens
|
200
|
+
#
|
201
|
+
# === Methods for Creating an \Element
|
202
|
+
#
|
203
|
+
# ::new:: Returns a new empty element.
|
204
|
+
# #clone:: Returns a clone of another element.
|
205
|
+
#
|
206
|
+
# === Methods for Attributes
|
207
|
+
#
|
208
|
+
# {[attribute_name]}[#method-i-5B-5D]:: Returns an attribute value.
|
209
|
+
# #add_attribute:: Adds a new attribute.
|
210
|
+
# #add_attributes:: Adds multiple new attributes.
|
211
|
+
# #attribute:: Returns the attribute value for a given name and optional namespace.
|
212
|
+
# #delete_attribute:: Removes an attribute.
|
213
|
+
#
|
214
|
+
# === Methods for Children
|
215
|
+
#
|
216
|
+
# {[index]}[#method-i-5B-5D]:: Returns the child at the given offset.
|
217
|
+
# #add_element:: Adds an element as the last child.
|
218
|
+
# #delete_element:: Deletes a child element.
|
219
|
+
# #each_element:: Calls the given block with each child element.
|
220
|
+
# #each_element_with_attribute:: Calls the given block with each child element
|
221
|
+
# that meets given criteria,
|
222
|
+
# which can include the attribute name.
|
223
|
+
# #each_element_with_text:: Calls the given block with each child element
|
224
|
+
# that meets given criteria,
|
225
|
+
# which can include text.
|
226
|
+
# #get_elements:: Returns an array of element children that match a given xpath.
|
227
|
+
#
|
228
|
+
# === Methods for \Text Children
|
229
|
+
#
|
230
|
+
# #add_text:: Adds a text node to the element.
|
231
|
+
# #get_text:: Returns a text node that meets specified criteria.
|
232
|
+
# #text:: Returns the text string from the first node that meets specified criteria.
|
233
|
+
# #texts:: Returns an array of the text children of the element.
|
234
|
+
# #text=:: Adds, removes, or replaces the first text child of the element
|
235
|
+
#
|
236
|
+
# === Methods for Other Children
|
237
|
+
#
|
238
|
+
# #cdatas:: Returns an array of the cdata children of the element.
|
239
|
+
# #comments:: Returns an array of the comment children of the element.
|
240
|
+
# #instructions:: Returns an array of the instruction children of the element.
|
241
|
+
#
|
242
|
+
# === Methods for Namespaces
|
243
|
+
#
|
244
|
+
# #add_namespace:: Adds a namespace to the element.
|
245
|
+
# #delete_namespace:: Removes a namespace from the element.
|
246
|
+
# #namespace:: Returns the string namespace URI for the element.
|
247
|
+
# #namespaces:: Returns a hash of all defined namespaces in the element.
|
248
|
+
# #prefixes:: Returns an array of the string prefixes (names)
|
249
|
+
# of all defined namespaces in the element
|
250
|
+
#
|
251
|
+
# === Methods for Querying
|
252
|
+
#
|
253
|
+
# #document:: Returns the document, if any, that the element belongs to.
|
254
|
+
# #root:: Returns the most distant element (not document) ancestor of the element.
|
255
|
+
# #root_node:: Returns the most distant ancestor of the element.
|
256
|
+
# #xpath:: Returns the string xpath to the element
|
257
|
+
# relative to the most distant parent
|
258
|
+
# #has_attributes?:: Returns whether the element has attributes.
|
259
|
+
# #has_elements?:: Returns whether the element has elements.
|
260
|
+
# #has_text?:: Returns whether the element has text.
|
261
|
+
# #next_element:: Returns the next sibling that is an element.
|
262
|
+
# #previous_element:: Returns the previous sibling that is an element.
|
263
|
+
# #raw:: Returns whether raw mode is set for the element.
|
264
|
+
# #whitespace:: Returns whether whitespace is respected for the element.
|
265
|
+
# #ignore_whitespace_nodes:: Returns whether whitespace nodes
|
266
|
+
# are to be ignored for the element.
|
267
|
+
# #node_type:: Returns symbol <tt>:element</tt>.
|
268
|
+
#
|
269
|
+
# === One More Method
|
270
|
+
#
|
271
|
+
# #inspect:: Returns a string representation of the element.
|
272
|
+
#
|
273
|
+
# === Accessors
|
274
|
+
#
|
275
|
+
# #elements:: Returns the REXML::Elements object for the element.
|
276
|
+
# #attributes:: Returns the REXML::Attributes object for the element.
|
277
|
+
# #context:: Returns or sets the context hash for the element.
|
278
|
+
#
|
21
279
|
class Element < Parent
|
22
280
|
include Namespace
|
23
281
|
|
@@ -30,32 +288,42 @@ module REXML
|
|
30
288
|
# whitespace handling.
|
31
289
|
attr_accessor :context
|
32
290
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
291
|
+
# :call-seq:
|
292
|
+
# Element.new(name = 'UNDEFINED', parent = nil, context = nil) -> new_element
|
293
|
+
# Element.new(element, parent = nil, context = nil) -> new_element
|
294
|
+
#
|
295
|
+
# Returns a new \REXML::Element object.
|
296
|
+
#
|
297
|
+
# When no arguments are given,
|
298
|
+
# returns an element with name <tt>'UNDEFINED'</tt>:
|
299
|
+
#
|
300
|
+
# e = REXML::Element.new # => <UNDEFINED/>
|
301
|
+
# e.class # => REXML::Element
|
302
|
+
# e.name # => "UNDEFINED"
|
303
|
+
#
|
304
|
+
# When only argument +name+ is given,
|
305
|
+
# returns an element of the given name:
|
306
|
+
#
|
307
|
+
# REXML::Element.new('foo') # => <foo/>
|
308
|
+
#
|
309
|
+
# When only argument +element+ is given, it must be an \REXML::Element object;
|
310
|
+
# returns a shallow copy of the given element:
|
311
|
+
#
|
312
|
+
# e0 = REXML::Element.new('foo')
|
313
|
+
# e1 = REXML::Element.new(e0) # => <foo/>
|
314
|
+
#
|
315
|
+
# When argument +parent+ is also given, it must be an REXML::Parent object:
|
316
|
+
#
|
317
|
+
# e = REXML::Element.new('foo', REXML::Parent.new)
|
318
|
+
# e.parent # => #<REXML::Parent @parent=nil, @children=[<foo/>]>
|
319
|
+
#
|
320
|
+
# When argument +context+ is also given, it must be a hash
|
321
|
+
# representing the context for the element;
|
322
|
+
# see {Element Context}[../doc/rexml/context_rdoc.html]:
|
323
|
+
#
|
324
|
+
# e = REXML::Element.new('foo', nil, {raw: :all})
|
325
|
+
# e.context # => {:raw=>:all}
|
326
|
+
#
|
59
327
|
def initialize( arg = UNDEFINED, parent=nil, context=nil )
|
60
328
|
super(parent)
|
61
329
|
|
@@ -74,6 +342,27 @@ module REXML
|
|
74
342
|
end
|
75
343
|
end
|
76
344
|
|
345
|
+
# :call-seq:
|
346
|
+
# inspect -> string
|
347
|
+
#
|
348
|
+
# Returns a string representation of the element.
|
349
|
+
#
|
350
|
+
# For an element with no attributes and no children, shows the element name:
|
351
|
+
#
|
352
|
+
# REXML::Element.new.inspect # => "<UNDEFINED/>"
|
353
|
+
#
|
354
|
+
# Shows attributes, if any:
|
355
|
+
#
|
356
|
+
# e = REXML::Element.new('foo')
|
357
|
+
# e.add_attributes({'bar' => 0, 'baz' => 1})
|
358
|
+
# e.inspect # => "<foo bar='0' baz='1'/>"
|
359
|
+
#
|
360
|
+
# Shows an ellipsis (<tt>...</tt>), if there are child elements:
|
361
|
+
#
|
362
|
+
# e.add_element(REXML::Element.new('bar'))
|
363
|
+
# e.add_element(REXML::Element.new('baz'))
|
364
|
+
# e.inspect # => "<foo bar='0' baz='1'> ... </>"
|
365
|
+
#
|
77
366
|
def inspect
|
78
367
|
rv = "<#@expanded_name"
|
79
368
|
|
@@ -89,60 +378,118 @@ module REXML
|
|
89
378
|
end
|
90
379
|
end
|
91
380
|
|
92
|
-
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
381
|
+
# :call-seq:
|
382
|
+
# clone -> new_element
|
383
|
+
#
|
384
|
+
# Returns a shallow copy of the element, containing the name and attributes,
|
385
|
+
# but not the parent or children:
|
386
|
+
#
|
387
|
+
# e = REXML::Element.new('foo')
|
388
|
+
# e.add_attributes({'bar' => 0, 'baz' => 1})
|
389
|
+
# e.clone # => <foo bar='0' baz='1'/>
|
390
|
+
#
|
97
391
|
def clone
|
98
392
|
self.class.new self
|
99
393
|
end
|
100
394
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
395
|
+
# :call-seq:
|
396
|
+
# root_node -> document or element
|
397
|
+
#
|
398
|
+
# Returns the most distant ancestor of +self+.
|
399
|
+
#
|
400
|
+
# When the element is part of a document,
|
401
|
+
# returns the root node of the document.
|
402
|
+
# Note that the root node is different from the document element;
|
403
|
+
# in this example +a+ is document element and the root node is its parent:
|
404
|
+
#
|
405
|
+
# d = REXML::Document.new('<a><b><c/></b></a>')
|
406
|
+
# top_element = d.first # => <a> ... </>
|
407
|
+
# child = top_element.first # => <b> ... </>
|
408
|
+
# d.root_node == d # => true
|
409
|
+
# top_element.root_node == d # => true
|
410
|
+
# child.root_node == d # => true
|
411
|
+
#
|
412
|
+
# When the element is not part of a document, but does have ancestor elements,
|
413
|
+
# returns the most distant ancestor element:
|
414
|
+
#
|
415
|
+
# e0 = REXML::Element.new('foo')
|
416
|
+
# e1 = REXML::Element.new('bar')
|
417
|
+
# e1.parent = e0
|
418
|
+
# e2 = REXML::Element.new('baz')
|
419
|
+
# e2.parent = e1
|
420
|
+
# e2.root_node == e0 # => true
|
421
|
+
#
|
422
|
+
# When the element has no ancestor elements,
|
423
|
+
# returns +self+:
|
424
|
+
#
|
425
|
+
# e = REXML::Element.new('foo')
|
426
|
+
# e.root_node == e # => true
|
427
|
+
#
|
428
|
+
# Related: #root, #document.
|
429
|
+
#
|
120
430
|
def root_node
|
121
431
|
parent.nil? ? self : parent.root_node
|
122
432
|
end
|
123
433
|
|
434
|
+
# :call-seq:
|
435
|
+
# root -> element
|
436
|
+
#
|
437
|
+
# Returns the most distant _element_ (not document) ancestor of the element:
|
438
|
+
#
|
439
|
+
# d = REXML::Document.new('<a><b><c/></b></a>')
|
440
|
+
# top_element = d.first
|
441
|
+
# child = top_element.first
|
442
|
+
# top_element.root == top_element # => true
|
443
|
+
# child.root == top_element # => true
|
444
|
+
#
|
445
|
+
# For a document, returns the topmost element:
|
446
|
+
#
|
447
|
+
# d.root == top_element # => true
|
448
|
+
#
|
449
|
+
# Related: #root_node, #document.
|
450
|
+
#
|
124
451
|
def root
|
125
452
|
return elements[1] if self.kind_of? Document
|
126
453
|
return self if parent.kind_of? Document or parent.nil?
|
127
454
|
return parent.root
|
128
455
|
end
|
129
456
|
|
130
|
-
#
|
131
|
-
#
|
457
|
+
# :call-seq:
|
458
|
+
# document -> document or nil
|
459
|
+
#
|
460
|
+
# If the element is part of a document, returns that document:
|
461
|
+
#
|
462
|
+
# d = REXML::Document.new('<a><b><c/></b></a>')
|
463
|
+
# top_element = d.first
|
464
|
+
# child = top_element.first
|
465
|
+
# top_element.document == d # => true
|
466
|
+
# child.document == d # => true
|
467
|
+
#
|
468
|
+
# If the element is not part of a document, returns +nil+:
|
469
|
+
#
|
470
|
+
# REXML::Element.new.document # => nil
|
471
|
+
#
|
472
|
+
# For a document, returns +self+:
|
473
|
+
#
|
474
|
+
# d.document == d # => true
|
475
|
+
#
|
476
|
+
# Related: #root, #root_node.
|
477
|
+
#
|
132
478
|
def document
|
133
479
|
rt = root
|
134
480
|
rt.parent if rt
|
135
481
|
end
|
136
482
|
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
483
|
+
# :call-seq:
|
484
|
+
# whitespace
|
485
|
+
#
|
486
|
+
# Returns +true+ if whitespace is respected for this element,
|
487
|
+
# +false+ otherwise.
|
488
|
+
#
|
489
|
+
# See {Element Context}[../doc/rexml/context_rdoc.html].
|
490
|
+
#
|
491
|
+
# The evaluation is tested against the element's +expanded_name+,
|
492
|
+
# and so is namespace-sensitive.
|
146
493
|
def whitespace
|
147
494
|
@whitespace = nil
|
148
495
|
if @context
|
@@ -159,6 +506,13 @@ module REXML
|
|
159
506
|
@whitespace
|
160
507
|
end
|
161
508
|
|
509
|
+
# :call-seq:
|
510
|
+
# ignore_whitespace_nodes
|
511
|
+
#
|
512
|
+
# Returns +true+ if whitespace nodes are ignored for the element.
|
513
|
+
#
|
514
|
+
# See {Element Context}[../doc/rexml/context_rdoc.html].
|
515
|
+
#
|
162
516
|
def ignore_whitespace_nodes
|
163
517
|
@ignore_whitespace_nodes = false
|
164
518
|
if @context
|
@@ -170,9 +524,12 @@ module REXML
|
|
170
524
|
end
|
171
525
|
end
|
172
526
|
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
527
|
+
# :call-seq:
|
528
|
+
# raw
|
529
|
+
#
|
530
|
+
# Returns +true+ if raw mode is set for the element.
|
531
|
+
#
|
532
|
+
# See {Element Context}[../doc/rexml/context_rdoc.html].
|
176
533
|
#
|
177
534
|
# The evaluation is tested against +expanded_name+, and so is namespace
|
178
535
|
# sensitive.
|
@@ -180,7 +537,7 @@ module REXML
|
|
180
537
|
@raw = (@context and @context[:raw] and
|
181
538
|
(@context[:raw] == :all or
|
182
539
|
@context[:raw].include? expanded_name))
|
183
|
-
|
540
|
+
@raw
|
184
541
|
end
|
185
542
|
|
186
543
|
#once :whitespace, :raw, :ignore_whitespace_nodes
|
@@ -189,10 +546,25 @@ module REXML
|
|
189
546
|
# Namespaces #
|
190
547
|
#################################################
|
191
548
|
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
549
|
+
# :call-seq:
|
550
|
+
# prefixes -> array_of_namespace_prefixes
|
551
|
+
#
|
552
|
+
# Returns an array of the string prefixes (names) of all defined namespaces
|
553
|
+
# in the element and its ancestors:
|
554
|
+
#
|
555
|
+
# xml_string = <<-EOT
|
556
|
+
# <root>
|
557
|
+
# <a xmlns:x='1' xmlns:y='2'>
|
558
|
+
# <b/>
|
559
|
+
# <c xmlns:z='3'/>
|
560
|
+
# </a>
|
561
|
+
# </root>
|
562
|
+
# EOT
|
563
|
+
# d = REXML::Document.new(xml_string, {compress_whitespace: :all})
|
564
|
+
# d.elements['//a'].prefixes # => ["x", "y"]
|
565
|
+
# d.elements['//b'].prefixes # => ["x", "y"]
|
566
|
+
# d.elements['//c'].prefixes # => ["x", "y", "z"]
|
567
|
+
#
|
196
568
|
def prefixes
|
197
569
|
prefixes = []
|
198
570
|
prefixes = parent.prefixes if parent
|
@@ -200,6 +572,25 @@ module REXML
|
|
200
572
|
return prefixes
|
201
573
|
end
|
202
574
|
|
575
|
+
# :call-seq:
|
576
|
+
# namespaces -> array_of_namespace_names
|
577
|
+
#
|
578
|
+
# Returns a hash of all defined namespaces
|
579
|
+
# in the element and its ancestors:
|
580
|
+
#
|
581
|
+
# xml_string = <<-EOT
|
582
|
+
# <root>
|
583
|
+
# <a xmlns:x='1' xmlns:y='2'>
|
584
|
+
# <b/>
|
585
|
+
# <c xmlns:z='3'/>
|
586
|
+
# </a>
|
587
|
+
# </root>
|
588
|
+
# EOT
|
589
|
+
# d = REXML::Document.new(xml_string)
|
590
|
+
# d.elements['//a'].namespaces # => {"x"=>"1", "y"=>"2"}
|
591
|
+
# d.elements['//b'].namespaces # => {"x"=>"1", "y"=>"2"}
|
592
|
+
# d.elements['//c'].namespaces # => {"x"=>"1", "y"=>"2", "z"=>"3"}
|
593
|
+
#
|
203
594
|
def namespaces
|
204
595
|
namespaces = {}
|
205
596
|
namespaces = parent.namespaces if parent
|
@@ -207,19 +598,26 @@ module REXML
|
|
207
598
|
return namespaces
|
208
599
|
end
|
209
600
|
|
210
|
-
#
|
211
|
-
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
601
|
+
# :call-seq:
|
602
|
+
# namespace(prefix = nil) -> string_uri or nil
|
603
|
+
#
|
604
|
+
# Returns the string namespace URI for the element,
|
605
|
+
# possibly deriving from one of its ancestors.
|
606
|
+
#
|
607
|
+
# xml_string = <<-EOT
|
608
|
+
# <root>
|
609
|
+
# <a xmlns='1' xmlns:y='2'>
|
610
|
+
# <b/>
|
611
|
+
# <c xmlns:z='3'/>
|
612
|
+
# </a>
|
613
|
+
# </root>
|
614
|
+
# EOT
|
615
|
+
# d = REXML::Document.new(xml_string)
|
616
|
+
# b = d.elements['//b']
|
617
|
+
# b.namespace # => "1"
|
618
|
+
# b.namespace('y') # => "2"
|
619
|
+
# b.namespace('nosuch') # => nil
|
620
|
+
#
|
223
621
|
def namespace(prefix=nil)
|
224
622
|
if prefix.nil?
|
225
623
|
prefix = prefix()
|
@@ -235,19 +633,24 @@ module REXML
|
|
235
633
|
return ns
|
236
634
|
end
|
237
635
|
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
243
|
-
#
|
244
|
-
#
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
636
|
+
# :call-seq:
|
637
|
+
# add_namespace(prefix, uri = nil) -> self
|
638
|
+
#
|
639
|
+
# Adds a namespace to the element; returns +self+.
|
640
|
+
#
|
641
|
+
# With the single argument +prefix+,
|
642
|
+
# adds a namespace using the given +prefix+ and the namespace URI:
|
643
|
+
#
|
644
|
+
# e = REXML::Element.new('foo')
|
645
|
+
# e.add_namespace('bar')
|
646
|
+
# e.namespaces # => {"xmlns"=>"bar"}
|
647
|
+
#
|
648
|
+
# With both arguments +prefix+ and +uri+ given,
|
649
|
+
# adds a namespace using both arguments:
|
650
|
+
#
|
651
|
+
# e.add_namespace('baz', 'bat')
|
652
|
+
# e.namespaces # => {"xmlns"=>"bar", "baz"=>"bat"}
|
653
|
+
#
|
251
654
|
def add_namespace( prefix, uri=nil )
|
252
655
|
unless uri
|
253
656
|
@attributes["xmlns"] = prefix
|
@@ -258,16 +661,28 @@ module REXML
|
|
258
661
|
self
|
259
662
|
end
|
260
663
|
|
261
|
-
#
|
262
|
-
#
|
263
|
-
#
|
664
|
+
# :call-seq:
|
665
|
+
# delete_namespace(namespace = 'xmlns') -> self
|
666
|
+
#
|
667
|
+
# Removes a namespace from the element.
|
668
|
+
#
|
669
|
+
# With no argument, removes the default namespace:
|
670
|
+
#
|
671
|
+
# d = REXML::Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
|
672
|
+
# d.to_s # => "<a xmlns:foo='bar' xmlns='twiddle'/>"
|
673
|
+
# d.root.delete_namespace # => <a xmlns:foo='bar'/>
|
674
|
+
# d.to_s # => "<a xmlns:foo='bar'/>"
|
675
|
+
#
|
676
|
+
# With argument +namespace+, removes the specified namespace:
|
677
|
+
#
|
678
|
+
# d.root.delete_namespace('foo')
|
679
|
+
# d.to_s # => "<a/>"
|
680
|
+
#
|
681
|
+
# Does nothing if no such namespace is found:
|
682
|
+
#
|
683
|
+
# d.root.delete_namespace('nosuch')
|
684
|
+
# d.to_s # => "<a/>"
|
264
685
|
#
|
265
|
-
# Evaluates to: this element
|
266
|
-
# doc = Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
|
267
|
-
# doc.root.delete_namespace
|
268
|
-
# puts doc # -> <a xmlns:foo='bar'/>
|
269
|
-
# doc.root.delete_namespace 'foo'
|
270
|
-
# puts doc # -> <a/>
|
271
686
|
def delete_namespace namespace="xmlns"
|
272
687
|
namespace = "xmlns:#{namespace}" unless namespace == 'xmlns'
|
273
688
|
attribute = attributes.get_attribute(namespace)
|
@@ -279,20 +694,40 @@ module REXML
|
|
279
694
|
# Elements #
|
280
695
|
#################################################
|
281
696
|
|
282
|
-
#
|
283
|
-
#
|
284
|
-
# element
|
285
|
-
#
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
294
|
-
#
|
295
|
-
#
|
697
|
+
# :call-seq:
|
698
|
+
# add_element(name, attributes = nil) -> new_element
|
699
|
+
# add_element(element, attributes = nil) -> element
|
700
|
+
#
|
701
|
+
# Adds a child element, optionally setting attributes
|
702
|
+
# on the added element; returns the added element.
|
703
|
+
#
|
704
|
+
# With string argument +name+, creates a new element with that name
|
705
|
+
# and adds the new element as a child:
|
706
|
+
#
|
707
|
+
# e0 = REXML::Element.new('foo')
|
708
|
+
# e0.add_element('bar')
|
709
|
+
# e0[0] # => <bar/>
|
710
|
+
#
|
711
|
+
#
|
712
|
+
# With argument +name+ and hash argument +attributes+,
|
713
|
+
# sets attributes on the new element:
|
714
|
+
#
|
715
|
+
# e0.add_element('baz', {'bat' => '0', 'bam' => '1'})
|
716
|
+
# e0[1] # => <baz bat='0' bam='1'/>
|
717
|
+
#
|
718
|
+
# With element argument +element+, adds that element as a child:
|
719
|
+
#
|
720
|
+
# e0 = REXML::Element.new('foo')
|
721
|
+
# e1 = REXML::Element.new('bar')
|
722
|
+
# e0.add_element(e1)
|
723
|
+
# e0[0] # => <bar/>
|
724
|
+
#
|
725
|
+
# With argument +element+ and hash argument +attributes+,
|
726
|
+
# sets attributes on the added element:
|
727
|
+
#
|
728
|
+
# e0.add_element(e1, {'bat' => '0', 'bam' => '1'})
|
729
|
+
# e0[1] # => <bar bat='0' bam='1'/>
|
730
|
+
#
|
296
731
|
def add_element element, attrs=nil
|
297
732
|
raise "First argument must be either an element name, or an Element object" if element.nil?
|
298
733
|
el = @elements.add(element)
|
@@ -302,52 +737,112 @@ module REXML
|
|
302
737
|
el
|
303
738
|
end
|
304
739
|
|
740
|
+
# :call-seq:
|
741
|
+
# delete_element(index) -> removed_element or nil
|
742
|
+
# delete_element(element) -> removed_element or nil
|
743
|
+
# delete_element(xpath) -> removed_element or nil
|
744
|
+
#
|
305
745
|
# Deletes a child element.
|
306
|
-
#
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
746
|
+
#
|
747
|
+
# When 1-based integer argument +index+ is given,
|
748
|
+
# removes and returns the child element at that offset if it exists;
|
749
|
+
# indexing does not include text nodes;
|
750
|
+
# returns +nil+ if the element does not exist:
|
751
|
+
#
|
752
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
753
|
+
# a = d.root # => <a> ... </>
|
754
|
+
# a.delete_element(1) # => <b/>
|
755
|
+
# a.delete_element(1) # => <c/>
|
756
|
+
# a.delete_element(1) # => nil
|
757
|
+
#
|
758
|
+
# When element argument +element+ is given,
|
759
|
+
# removes and returns that child element if it exists,
|
760
|
+
# otherwise returns +nil+:
|
761
|
+
#
|
762
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
763
|
+
# a = d.root # => <a> ... </>
|
764
|
+
# c = a[2] # => <c/>
|
765
|
+
# a.delete_element(c) # => <c/>
|
766
|
+
# a.delete_element(c) # => nil
|
767
|
+
#
|
768
|
+
# When xpath argument +xpath+ is given,
|
769
|
+
# removes and returns the element at xpath if it exists,
|
770
|
+
# otherwise returns +nil+:
|
771
|
+
#
|
772
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
773
|
+
# a = d.root # => <a> ... </>
|
774
|
+
# a.delete_element('//c') # => <c/>
|
775
|
+
# a.delete_element('//c') # => nil
|
776
|
+
#
|
316
777
|
def delete_element element
|
317
778
|
@elements.delete element
|
318
779
|
end
|
319
780
|
|
320
|
-
#
|
321
|
-
#
|
322
|
-
#
|
323
|
-
#
|
324
|
-
#
|
781
|
+
# :call-seq:
|
782
|
+
# has_elements?
|
783
|
+
#
|
784
|
+
# Returns +true+ if the element has one or more element children,
|
785
|
+
# +false+ otherwise:
|
786
|
+
#
|
787
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
788
|
+
# a = d.root # => <a> ... </>
|
789
|
+
# a.has_elements? # => true
|
790
|
+
# b = a[0] # => <b/>
|
791
|
+
# b.has_elements? # => false
|
792
|
+
#
|
325
793
|
def has_elements?
|
326
794
|
!@elements.empty?
|
327
795
|
end
|
328
796
|
|
329
|
-
#
|
330
|
-
#
|
331
|
-
#
|
332
|
-
#
|
333
|
-
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
#
|
337
|
-
#
|
338
|
-
#
|
339
|
-
# (
|
340
|
-
#
|
341
|
-
#
|
342
|
-
#
|
343
|
-
#
|
344
|
-
#
|
345
|
-
#
|
346
|
-
#
|
347
|
-
#
|
348
|
-
#
|
349
|
-
#
|
350
|
-
#
|
797
|
+
# :call-seq:
|
798
|
+
# each_element_with_attribute(attr_name, value = nil, max = 0, xpath = nil) {|e| ... }
|
799
|
+
#
|
800
|
+
# Calls the given block with each child element that meets given criteria.
|
801
|
+
#
|
802
|
+
# When only string argument +attr_name+ is given,
|
803
|
+
# calls the block with each child element that has that attribute:
|
804
|
+
#
|
805
|
+
# d = REXML::Document.new '<a><b id="1"/><c id="2"/><d id="1"/><e/></a>'
|
806
|
+
# a = d.root
|
807
|
+
# a.each_element_with_attribute('id') {|e| p e }
|
808
|
+
#
|
809
|
+
# Output:
|
810
|
+
#
|
811
|
+
# <b id='1'/>
|
812
|
+
# <c id='2'/>
|
813
|
+
# <d id='1'/>
|
814
|
+
#
|
815
|
+
# With argument +attr_name+ and string argument +value+ given,
|
816
|
+
# calls the block with each child element that has that attribute
|
817
|
+
# with that value:
|
818
|
+
#
|
819
|
+
# a.each_element_with_attribute('id', '1') {|e| p e }
|
820
|
+
#
|
821
|
+
# Output:
|
822
|
+
#
|
823
|
+
# <b id='1'/>
|
824
|
+
# <d id='1'/>
|
825
|
+
#
|
826
|
+
# With arguments +attr_name+, +value+, and integer argument +max+ given,
|
827
|
+
# calls the block with at most +max+ child elements:
|
828
|
+
#
|
829
|
+
# a.each_element_with_attribute('id', '1', 1) {|e| p e }
|
830
|
+
#
|
831
|
+
# Output:
|
832
|
+
#
|
833
|
+
# <b id='1'/>
|
834
|
+
#
|
835
|
+
# With all arguments given, including +xpath+,
|
836
|
+
# calls the block with only those child elements
|
837
|
+
# that meet the first three criteria,
|
838
|
+
# and also match the given +xpath+:
|
839
|
+
#
|
840
|
+
# a.each_element_with_attribute('id', '1', 2, '//d') {|e| p e }
|
841
|
+
#
|
842
|
+
# Output:
|
843
|
+
#
|
844
|
+
# <d id='1'/>
|
845
|
+
#
|
351
846
|
def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element
|
352
847
|
each_with_something( proc {|child|
|
353
848
|
if value.nil?
|
@@ -358,27 +853,53 @@ module REXML
|
|
358
853
|
}, max, name, &block )
|
359
854
|
end
|
360
855
|
|
361
|
-
#
|
362
|
-
#
|
363
|
-
#
|
364
|
-
#
|
365
|
-
#
|
366
|
-
#
|
367
|
-
#
|
368
|
-
#
|
369
|
-
#
|
370
|
-
#
|
371
|
-
#
|
372
|
-
#
|
373
|
-
#
|
374
|
-
#
|
375
|
-
#
|
376
|
-
#
|
377
|
-
#
|
378
|
-
#
|
379
|
-
#
|
380
|
-
#
|
381
|
-
#
|
856
|
+
# :call-seq:
|
857
|
+
# each_element_with_text(text = nil, max = 0, xpath = nil) {|e| ... }
|
858
|
+
#
|
859
|
+
# Calls the given block with each child element that meets given criteria.
|
860
|
+
#
|
861
|
+
# With no arguments, calls the block with each child element that has text:
|
862
|
+
#
|
863
|
+
# d = REXML::Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
|
864
|
+
# a = d.root
|
865
|
+
# a.each_element_with_text {|e| p e }
|
866
|
+
#
|
867
|
+
# Output:
|
868
|
+
#
|
869
|
+
# <b> ... </>
|
870
|
+
# <c> ... </>
|
871
|
+
# <d> ... </>
|
872
|
+
#
|
873
|
+
# With the single string argument +text+,
|
874
|
+
# calls the block with each element that has exactly that text:
|
875
|
+
#
|
876
|
+
# a.each_element_with_text('b') {|e| p e }
|
877
|
+
#
|
878
|
+
# Output:
|
879
|
+
#
|
880
|
+
# <b> ... </>
|
881
|
+
# <c> ... </>
|
882
|
+
#
|
883
|
+
# With argument +text+ and integer argument +max+,
|
884
|
+
# calls the block with at most +max+ elements:
|
885
|
+
#
|
886
|
+
# a.each_element_with_text('b', 1) {|e| p e }
|
887
|
+
#
|
888
|
+
# Output:
|
889
|
+
#
|
890
|
+
# <b> ... </>
|
891
|
+
#
|
892
|
+
# With all arguments given, including +xpath+,
|
893
|
+
# calls the block with only those child elements
|
894
|
+
# that meet the first two criteria,
|
895
|
+
# and also match the given +xpath+:
|
896
|
+
#
|
897
|
+
# a.each_element_with_text('b', 2, '//c') {|e| p e }
|
898
|
+
#
|
899
|
+
# Output:
|
900
|
+
#
|
901
|
+
# <c> ... </>
|
902
|
+
#
|
382
903
|
def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element
|
383
904
|
each_with_something( proc {|child|
|
384
905
|
if text.nil?
|
@@ -389,35 +910,71 @@ module REXML
|
|
389
910
|
}, max, name, &block )
|
390
911
|
end
|
391
912
|
|
392
|
-
#
|
913
|
+
# :call-seq:
|
914
|
+
# each_element {|e| ... }
|
915
|
+
#
|
916
|
+
# Calls the given block with each child element:
|
917
|
+
#
|
918
|
+
# d = REXML::Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
|
919
|
+
# a = d.root
|
920
|
+
# a.each_element {|e| p e }
|
921
|
+
#
|
922
|
+
# Output:
|
923
|
+
#
|
924
|
+
# <b> ... </>
|
925
|
+
# <c> ... </>
|
926
|
+
# <d> ... </>
|
927
|
+
# <e/>
|
928
|
+
#
|
393
929
|
def each_element( xpath=nil, &block ) # :yields: Element
|
394
930
|
@elements.each( xpath, &block )
|
395
931
|
end
|
396
932
|
|
397
|
-
#
|
398
|
-
#
|
399
|
-
#
|
400
|
-
# Returns
|
933
|
+
# :call-seq:
|
934
|
+
# get_elements(xpath)
|
935
|
+
#
|
936
|
+
# Returns an array of the elements that match the given +xpath+:
|
937
|
+
#
|
938
|
+
# xml_string = <<-EOT
|
939
|
+
# <root>
|
940
|
+
# <a level='1'>
|
941
|
+
# <a level='2'/>
|
942
|
+
# </a>
|
943
|
+
# </root>
|
944
|
+
# EOT
|
945
|
+
# d = REXML::Document.new(xml_string)
|
946
|
+
# d.root.get_elements('//a') # => [<a level='1'> ... </>, <a level='2'/>]
|
947
|
+
#
|
401
948
|
def get_elements( xpath )
|
402
949
|
@elements.to_a( xpath )
|
403
950
|
end
|
404
951
|
|
405
|
-
#
|
406
|
-
#
|
407
|
-
#
|
408
|
-
#
|
409
|
-
#
|
952
|
+
# :call-seq:
|
953
|
+
# next_element
|
954
|
+
#
|
955
|
+
# Returns the next sibling that is an element if it exists,
|
956
|
+
# +niL+ otherwise:
|
957
|
+
#
|
958
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
959
|
+
# d.root.elements['b'].next_element #-> <c/>
|
960
|
+
# d.root.elements['c'].next_element #-> nil
|
961
|
+
#
|
410
962
|
def next_element
|
411
963
|
element = next_sibling
|
412
964
|
element = element.next_sibling until element.nil? or element.kind_of? Element
|
413
965
|
return element
|
414
966
|
end
|
415
967
|
|
416
|
-
#
|
417
|
-
#
|
418
|
-
#
|
419
|
-
#
|
420
|
-
#
|
968
|
+
# :call-seq:
|
969
|
+
# previous_element
|
970
|
+
#
|
971
|
+
# Returns the previous sibling that is an element if it exists,
|
972
|
+
# +niL+ otherwise:
|
973
|
+
#
|
974
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
975
|
+
# d.root.elements['c'].previous_element #-> <b/>
|
976
|
+
# d.root.elements['b'].previous_element #-> nil
|
977
|
+
#
|
421
978
|
def previous_element
|
422
979
|
element = previous_sibling
|
423
980
|
element = element.previous_sibling until element.nil? or element.kind_of? Element
|
@@ -429,36 +986,69 @@ module REXML
|
|
429
986
|
# Text #
|
430
987
|
#################################################
|
431
988
|
|
432
|
-
#
|
989
|
+
# :call-seq:
|
990
|
+
# has_text? -> true or false
|
991
|
+
#
|
992
|
+
# Returns +true+ if the element has one or more text noded,
|
993
|
+
# +false+ otherwise:
|
994
|
+
#
|
995
|
+
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
996
|
+
# a = d.root
|
997
|
+
# a.has_text? # => true
|
998
|
+
# b = a[0]
|
999
|
+
# b.has_text? # => false
|
1000
|
+
#
|
433
1001
|
def has_text?
|
434
1002
|
not text().nil?
|
435
1003
|
end
|
436
1004
|
|
437
|
-
#
|
438
|
-
#
|
1005
|
+
# :call-seq:
|
1006
|
+
# text(xpath = nil) -> text_string or nil
|
1007
|
+
#
|
1008
|
+
# Returns the text string from the first text node child
|
1009
|
+
# in a specified element, if it exists, +nil+ otherwise.
|
1010
|
+
#
|
1011
|
+
# With no argument, returns the text from the first text node in +self+:
|
1012
|
+
#
|
1013
|
+
# d = REXML::Document.new "<p>some text <b>this is bold!</b> more text</p>"
|
1014
|
+
# d.root.text.class # => String
|
1015
|
+
# d.root.text # => "some text "
|
1016
|
+
#
|
1017
|
+
# With argument +xpath+, returns text from the first text node
|
1018
|
+
# in the element that matches +xpath+:
|
1019
|
+
#
|
1020
|
+
# d.root.text(1) # => "this is bold!"
|
439
1021
|
#
|
440
|
-
#
|
441
|
-
# separated by other children
|
442
|
-
# the first
|
1022
|
+
# Note that an element may have multiple text nodes,
|
1023
|
+
# possibly separated by other non-text children, as above.
|
1024
|
+
# Even so, the returned value is the string text from the first such node.
|
443
1025
|
#
|
444
|
-
#
|
445
|
-
#
|
446
|
-
# the Text::value documentation.
|
1026
|
+
# Note also that the text note is retrieved by method get_text,
|
1027
|
+
# and so is always normalized text.
|
447
1028
|
#
|
448
|
-
# doc = Document.new "<p>some text <b>this is bold!</b> more text</p>"
|
449
|
-
# # The element 'p' has two text elements, "some text " and " more text".
|
450
|
-
# doc.root.text #-> "some text "
|
451
1029
|
def text( path = nil )
|
452
1030
|
rv = get_text(path)
|
453
1031
|
return rv.value unless rv.nil?
|
454
1032
|
nil
|
455
1033
|
end
|
456
1034
|
|
457
|
-
#
|
458
|
-
#
|
459
|
-
#
|
460
|
-
#
|
461
|
-
#
|
1035
|
+
# :call-seq:
|
1036
|
+
# get_text(xpath = nil) -> text_node or nil
|
1037
|
+
#
|
1038
|
+
# Returns the first text node child in a specified element, if it exists,
|
1039
|
+
# +nil+ otherwise.
|
1040
|
+
#
|
1041
|
+
# With no argument, returns the first text node from +self+:
|
1042
|
+
#
|
1043
|
+
# d = REXML::Document.new "<p>some text <b>this is bold!</b> more text</p>"
|
1044
|
+
# d.root.get_text.class # => REXML::Text
|
1045
|
+
# d.root.get_text # => "some text "
|
1046
|
+
#
|
1047
|
+
# With argument +xpath+, returns the first text node from the element
|
1048
|
+
# that matches +xpath+:
|
1049
|
+
#
|
1050
|
+
# d.root.get_text(1) # => "this is bold!"
|
1051
|
+
#
|
462
1052
|
def get_text path = nil
|
463
1053
|
rv = nil
|
464
1054
|
if path
|
@@ -470,26 +1060,31 @@ module REXML
|
|
470
1060
|
return rv
|
471
1061
|
end
|
472
1062
|
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
#
|
480
|
-
#
|
481
|
-
#
|
482
|
-
#
|
483
|
-
#
|
484
|
-
#
|
485
|
-
#
|
486
|
-
#
|
487
|
-
#
|
488
|
-
#
|
489
|
-
#
|
490
|
-
#
|
491
|
-
#
|
492
|
-
#
|
1063
|
+
# :call-seq:
|
1064
|
+
# text = string -> string
|
1065
|
+
# text = nil -> nil
|
1066
|
+
#
|
1067
|
+
# Adds, replaces, or removes the first text node child in the element.
|
1068
|
+
#
|
1069
|
+
# With string argument +string+,
|
1070
|
+
# creates a new \REXML::Text node containing that string,
|
1071
|
+
# honoring the current settings for whitespace and row,
|
1072
|
+
# then places the node as the first text child in the element;
|
1073
|
+
# returns +string+.
|
1074
|
+
#
|
1075
|
+
# If the element has no text child, the text node is added:
|
1076
|
+
#
|
1077
|
+
# d = REXML::Document.new '<a><b/></a>'
|
1078
|
+
# d.root.text = 'foo' #-> '<a><b/>foo</a>'
|
1079
|
+
#
|
1080
|
+
# If the element has a text child, it is replaced:
|
1081
|
+
#
|
1082
|
+
# d.root.text = 'bar' #-> '<a><b/>bar</a>'
|
1083
|
+
#
|
1084
|
+
# With argument +nil+, removes the first text child:
|
1085
|
+
#
|
1086
|
+
# d.root.text = nil #-> '<a><b/><c/></a>'
|
1087
|
+
#
|
493
1088
|
def text=( text )
|
494
1089
|
if text.kind_of? String
|
495
1090
|
text = Text.new( text, whitespace(), nil, raw() )
|
@@ -509,17 +1104,45 @@ module REXML
|
|
509
1104
|
return self
|
510
1105
|
end
|
511
1106
|
|
512
|
-
#
|
513
|
-
#
|
514
|
-
#
|
515
|
-
#
|
516
|
-
#
|
517
|
-
#
|
518
|
-
#
|
519
|
-
#
|
520
|
-
#
|
521
|
-
#
|
522
|
-
#
|
1107
|
+
# :call-seq:
|
1108
|
+
# add_text(string) -> nil
|
1109
|
+
# add_text(text_node) -> self
|
1110
|
+
#
|
1111
|
+
# Adds text to the element.
|
1112
|
+
#
|
1113
|
+
# When string argument +string+ is given, returns +nil+.
|
1114
|
+
#
|
1115
|
+
# If the element has no child text node,
|
1116
|
+
# creates a \REXML::Text object using the string,
|
1117
|
+
# honoring the current settings for whitespace and raw,
|
1118
|
+
# then adds that node to the element:
|
1119
|
+
#
|
1120
|
+
# d = REXML::Document.new('<a><b/></a>')
|
1121
|
+
# a = d.root
|
1122
|
+
# a.add_text('foo')
|
1123
|
+
# a.to_a # => [<b/>, "foo"]
|
1124
|
+
#
|
1125
|
+
# If the element has child text nodes,
|
1126
|
+
# appends the string to the _last_ text node:
|
1127
|
+
#
|
1128
|
+
# d = REXML::Document.new('<a>foo<b/>bar</a>')
|
1129
|
+
# a = d.root
|
1130
|
+
# a.add_text('baz')
|
1131
|
+
# a.to_a # => ["foo", <b/>, "barbaz"]
|
1132
|
+
# a.add_text('baz')
|
1133
|
+
# a.to_a # => ["foo", <b/>, "barbazbaz"]
|
1134
|
+
#
|
1135
|
+
# When text node argument +text_node+ is given,
|
1136
|
+
# appends the node as the last text node in the element;
|
1137
|
+
# returns +self+:
|
1138
|
+
#
|
1139
|
+
# d = REXML::Document.new('<a>foo<b/>bar</a>')
|
1140
|
+
# a = d.root
|
1141
|
+
# a.add_text(REXML::Text.new('baz'))
|
1142
|
+
# a.to_a # => ["foo", <b/>, "bar", "baz"]
|
1143
|
+
# a.add_text(REXML::Text.new('baz'))
|
1144
|
+
# a.to_a # => ["foo", <b/>, "bar", "baz", "baz"]
|
1145
|
+
#
|
523
1146
|
def add_text( text )
|
524
1147
|
if text.kind_of? String
|
525
1148
|
if @children[-1].kind_of? Text
|
@@ -532,10 +1155,39 @@ module REXML
|
|
532
1155
|
return self
|
533
1156
|
end
|
534
1157
|
|
1158
|
+
# :call-seq:
|
1159
|
+
# node_type -> :element
|
1160
|
+
#
|
1161
|
+
# Returns symbol <tt>:element</tt>:
|
1162
|
+
#
|
1163
|
+
# d = REXML::Document.new('<a/>')
|
1164
|
+
# a = d.root # => <a/>
|
1165
|
+
# a.node_type # => :element
|
1166
|
+
#
|
535
1167
|
def node_type
|
536
1168
|
:element
|
537
1169
|
end
|
538
1170
|
|
1171
|
+
# :call-seq:
|
1172
|
+
# xpath -> string_xpath
|
1173
|
+
#
|
1174
|
+
# Returns the string xpath to the element
|
1175
|
+
# relative to the most distant parent:
|
1176
|
+
#
|
1177
|
+
# d = REXML::Document.new('<a><b><c/></b></a>')
|
1178
|
+
# a = d.root # => <a> ... </>
|
1179
|
+
# b = a[0] # => <b> ... </>
|
1180
|
+
# c = b[0] # => <c/>
|
1181
|
+
# d.xpath # => ""
|
1182
|
+
# a.xpath # => "/a"
|
1183
|
+
# b.xpath # => "/a/b"
|
1184
|
+
# c.xpath # => "/a/b/c"
|
1185
|
+
#
|
1186
|
+
# If there is no parent, returns the expanded name of the element:
|
1187
|
+
#
|
1188
|
+
# e = REXML::Element.new('foo')
|
1189
|
+
# e.xpath # => "foo"
|
1190
|
+
#
|
539
1191
|
def xpath
|
540
1192
|
path_elements = []
|
541
1193
|
cur = self
|
@@ -551,19 +1203,45 @@ module REXML
|
|
551
1203
|
# Attributes #
|
552
1204
|
#################################################
|
553
1205
|
|
554
|
-
#
|
1206
|
+
# :call-seq:
|
1207
|
+
# [index] -> object
|
1208
|
+
# [attr_name] -> attr_value
|
1209
|
+
# [attr_sym] -> attr_value
|
1210
|
+
#
|
1211
|
+
# With integer argument +index+ given,
|
1212
|
+
# returns the child at offset +index+, or +nil+ if none:
|
1213
|
+
#
|
1214
|
+
# d = REXML::Document.new '><root><a/>text<b/>more<c/></root>'
|
1215
|
+
# root = d.root
|
1216
|
+
# (0..root.size).each do |index|
|
1217
|
+
# node = root[index]
|
1218
|
+
# p "#{index}: #{node} (#{node.class})"
|
1219
|
+
# end
|
1220
|
+
#
|
1221
|
+
# Output:
|
1222
|
+
#
|
1223
|
+
# "0: <a/> (REXML::Element)"
|
1224
|
+
# "1: text (REXML::Text)"
|
1225
|
+
# "2: <b/> (REXML::Element)"
|
1226
|
+
# "3: more (REXML::Text)"
|
1227
|
+
# "4: <c/> (REXML::Element)"
|
1228
|
+
# "5: (NilClass)"
|
555
1229
|
#
|
556
|
-
#
|
557
|
-
#
|
558
|
-
#
|
1230
|
+
# With string argument +attr_name+ given,
|
1231
|
+
# returns the string value for the given attribute name if it exists,
|
1232
|
+
# otherwise +nil+:
|
559
1233
|
#
|
560
|
-
#
|
561
|
-
#
|
1234
|
+
# d = REXML::Document.new('<root attr="value"></root>')
|
1235
|
+
# root = d.root
|
1236
|
+
# root['attr'] # => "value"
|
1237
|
+
# root['nosuch'] # => nil
|
1238
|
+
#
|
1239
|
+
# With symbol argument +attr_sym+ given,
|
1240
|
+
# returns <tt>[attr_sym.to_s]</tt>:
|
1241
|
+
#
|
1242
|
+
# root[:attr] # => "value"
|
1243
|
+
# root[:nosuch] # => nil
|
562
1244
|
#
|
563
|
-
# doc = REXML::Document.new("<a attr='1'><b/><c/></a>")
|
564
|
-
# doc.root["attr"] # => "1"
|
565
|
-
# doc.root.attributes["attr"] # => "1"
|
566
|
-
# doc.root[1] # => <c/>
|
567
1245
|
def [](name_or_index)
|
568
1246
|
case name_or_index
|
569
1247
|
when String
|
@@ -575,6 +1253,36 @@ module REXML
|
|
575
1253
|
end
|
576
1254
|
end
|
577
1255
|
|
1256
|
+
|
1257
|
+
# :call-seq:
|
1258
|
+
# attribute(name, namespace = nil)
|
1259
|
+
#
|
1260
|
+
# Returns the string value for the given attribute name.
|
1261
|
+
#
|
1262
|
+
# With only argument +name+ given,
|
1263
|
+
# returns the value of the named attribute if it exists, otherwise +nil+:
|
1264
|
+
#
|
1265
|
+
# xml_string = <<-EOT
|
1266
|
+
# <root xmlns="ns0">
|
1267
|
+
# <a xmlns="ns1" attr="value"></a>
|
1268
|
+
# <b xmlns="ns2" attr="value"></b>
|
1269
|
+
# <c attr="value"/>
|
1270
|
+
# </root>
|
1271
|
+
# EOT
|
1272
|
+
# d = REXML::Document.new(xml_string)
|
1273
|
+
# root = d.root
|
1274
|
+
# a = root[1] # => <a xmlns='ns1' attr='value'/>
|
1275
|
+
# a.attribute('attr') # => attr='value'
|
1276
|
+
# a.attribute('nope') # => nil
|
1277
|
+
#
|
1278
|
+
# With arguments +name+ and +namespace+ given,
|
1279
|
+
# returns the value of the named attribute if it exists, otherwise +nil+:
|
1280
|
+
#
|
1281
|
+
# xml_string = "<root xmlns:a='a' a:x='a:x' x='x'/>"
|
1282
|
+
# document = REXML::Document.new(xml_string)
|
1283
|
+
# document.root.attribute("x") # => x='x'
|
1284
|
+
# document.root.attribute("x", "a") # => a:x='a:x'
|
1285
|
+
#
|
578
1286
|
def attribute( name, namespace=nil )
|
579
1287
|
prefix = nil
|
580
1288
|
if namespaces.respond_to? :key
|
@@ -598,29 +1306,46 @@ module REXML
|
|
598
1306
|
|
599
1307
|
end
|
600
1308
|
|
601
|
-
#
|
602
|
-
#
|
1309
|
+
# :call-seq:
|
1310
|
+
# has_attributes? -> true or false
|
1311
|
+
#
|
1312
|
+
# Returns +true+ if the element has attributes, +false+ otherwise:
|
1313
|
+
#
|
1314
|
+
# d = REXML::Document.new('<root><a attr="val"/><b/></root>')
|
1315
|
+
# a, b = *d.root
|
1316
|
+
# a.has_attributes? # => true
|
1317
|
+
# b.has_attributes? # => false
|
1318
|
+
#
|
603
1319
|
def has_attributes?
|
604
1320
|
return !@attributes.empty?
|
605
1321
|
end
|
606
1322
|
|
1323
|
+
# :call-seq:
|
1324
|
+
# add_attribute(name, value) -> value
|
1325
|
+
# add_attribute(attribute) -> attribute
|
1326
|
+
#
|
607
1327
|
# Adds an attribute to this element, overwriting any existing attribute
|
608
1328
|
# by the same name.
|
609
|
-
#
|
610
|
-
#
|
611
|
-
#
|
612
|
-
#
|
613
|
-
#
|
614
|
-
# value
|
615
|
-
#
|
616
|
-
#
|
617
|
-
#
|
618
|
-
#
|
619
|
-
#
|
620
|
-
#
|
621
|
-
#
|
622
|
-
#
|
623
|
-
#
|
1329
|
+
#
|
1330
|
+
# With string argument +name+ and object +value+ are given,
|
1331
|
+
# adds the attribute created with that name and value:
|
1332
|
+
#
|
1333
|
+
# e = REXML::Element.new
|
1334
|
+
# e.add_attribute('attr', 'value') # => "value"
|
1335
|
+
# e['attr'] # => "value"
|
1336
|
+
# e.add_attribute('attr', 'VALUE') # => "VALUE"
|
1337
|
+
# e['attr'] # => "VALUE"
|
1338
|
+
#
|
1339
|
+
# With only attribute object +attribute+ given,
|
1340
|
+
# adds the given attribute:
|
1341
|
+
#
|
1342
|
+
# a = REXML::Attribute.new('attr', 'value')
|
1343
|
+
# e.add_attribute(a) # => attr='value'
|
1344
|
+
# e['attr'] # => "value"
|
1345
|
+
# a = REXML::Attribute.new('attr', 'VALUE')
|
1346
|
+
# e.add_attribute(a) # => attr='VALUE'
|
1347
|
+
# e['attr'] # => "VALUE"
|
1348
|
+
#
|
624
1349
|
def add_attribute( key, value=nil )
|
625
1350
|
if key.kind_of? Attribute
|
626
1351
|
@attributes << key
|
@@ -629,10 +1354,29 @@ module REXML
|
|
629
1354
|
end
|
630
1355
|
end
|
631
1356
|
|
632
|
-
#
|
633
|
-
#
|
634
|
-
#
|
635
|
-
#
|
1357
|
+
# :call-seq:
|
1358
|
+
# add_attributes(hash) -> hash
|
1359
|
+
# add_attributes(array)
|
1360
|
+
#
|
1361
|
+
# Adds zero or more attributes to the element;
|
1362
|
+
# returns the argument.
|
1363
|
+
#
|
1364
|
+
# If hash argument +hash+ is given,
|
1365
|
+
# each key must be a string;
|
1366
|
+
# adds each attribute created with the key/value pair:
|
1367
|
+
#
|
1368
|
+
# e = REXML::Element.new
|
1369
|
+
# h = {'foo' => 'bar', 'baz' => 'bat'}
|
1370
|
+
# e.add_attributes(h)
|
1371
|
+
#
|
1372
|
+
# If argument +array+ is given,
|
1373
|
+
# each array member must be a 2-element array <tt>[name, value];
|
1374
|
+
# each name must be a string:
|
1375
|
+
#
|
1376
|
+
# e = REXML::Element.new
|
1377
|
+
# a = [['foo' => 'bar'], ['baz' => 'bat']]
|
1378
|
+
# e.add_attributes(a)
|
1379
|
+
#
|
636
1380
|
def add_attributes hash
|
637
1381
|
if hash.kind_of? Hash
|
638
1382
|
hash.each_pair {|key, value| @attributes[key] = value }
|
@@ -641,19 +1385,17 @@ module REXML
|
|
641
1385
|
end
|
642
1386
|
end
|
643
1387
|
|
644
|
-
#
|
645
|
-
#
|
646
|
-
#
|
647
|
-
#
|
648
|
-
#
|
649
|
-
#
|
650
|
-
#
|
651
|
-
#
|
652
|
-
#
|
653
|
-
#
|
654
|
-
#
|
655
|
-
# e.delete_attribute( 'name' ) #-> <E sur:name='Russell'/>
|
656
|
-
# e.delete_attribute( r ) #-> <E/>
|
1388
|
+
# :call-seq:
|
1389
|
+
# delete_attribute(name) -> removed_attribute or nil
|
1390
|
+
#
|
1391
|
+
# Removes a named attribute if it exists;
|
1392
|
+
# returns the removed attribute if found, otherwise +nil+:
|
1393
|
+
#
|
1394
|
+
# e = REXML::Element.new('foo')
|
1395
|
+
# e.add_attribute('bar', 'baz')
|
1396
|
+
# e.delete_attribute('bar') # => <bar/>
|
1397
|
+
# e.delete_attribute('bar') # => nil
|
1398
|
+
#
|
657
1399
|
def delete_attribute(key)
|
658
1400
|
attr = @attributes.get_attribute(key)
|
659
1401
|
attr.remove unless attr.nil?
|
@@ -663,26 +1405,80 @@ module REXML
|
|
663
1405
|
# Other Utilities #
|
664
1406
|
#################################################
|
665
1407
|
|
666
|
-
#
|
667
|
-
#
|
1408
|
+
# :call-seq:
|
1409
|
+
# cdatas -> array_of_cdata_children
|
1410
|
+
#
|
1411
|
+
# Returns a frozen array of the REXML::CData children of the element:
|
1412
|
+
#
|
1413
|
+
# xml_string = <<-EOT
|
1414
|
+
# <root>
|
1415
|
+
# <![CDATA[foo]]>
|
1416
|
+
# <![CDATA[bar]]>
|
1417
|
+
# </root>
|
1418
|
+
# EOT
|
1419
|
+
# d = REXML::Document.new(xml_string)
|
1420
|
+
# cds = d.root.cdatas # => ["foo", "bar"]
|
1421
|
+
# cds.frozen? # => true
|
1422
|
+
# cds.map {|cd| cd.class } # => [REXML::CData, REXML::CData]
|
1423
|
+
#
|
668
1424
|
def cdatas
|
669
1425
|
find_all { |child| child.kind_of? CData }.freeze
|
670
1426
|
end
|
671
1427
|
|
672
|
-
#
|
673
|
-
#
|
1428
|
+
# :call-seq:
|
1429
|
+
# comments -> array_of_comment_children
|
1430
|
+
#
|
1431
|
+
# Returns a frozen array of the REXML::Comment children of the element:
|
1432
|
+
#
|
1433
|
+
# xml_string = <<-EOT
|
1434
|
+
# <root>
|
1435
|
+
# <!--foo-->
|
1436
|
+
# <!--bar-->
|
1437
|
+
# </root>
|
1438
|
+
# EOT
|
1439
|
+
# d = REXML::Document.new(xml_string)
|
1440
|
+
# cs = d.root.comments
|
1441
|
+
# cs.frozen? # => true
|
1442
|
+
# cs.map {|c| c.class } # => [REXML::Comment, REXML::Comment]
|
1443
|
+
# cs.map {|c| c.to_s } # => ["foo", "bar"]
|
1444
|
+
#
|
674
1445
|
def comments
|
675
1446
|
find_all { |child| child.kind_of? Comment }.freeze
|
676
1447
|
end
|
677
1448
|
|
678
|
-
#
|
679
|
-
#
|
1449
|
+
# :call-seq:
|
1450
|
+
# instructions -> array_of_instruction_children
|
1451
|
+
#
|
1452
|
+
# Returns a frozen array of the REXML::Instruction children of the element:
|
1453
|
+
#
|
1454
|
+
# xml_string = <<-EOT
|
1455
|
+
# <root>
|
1456
|
+
# <?target0 foo?>
|
1457
|
+
# <?target1 bar?>
|
1458
|
+
# </root>
|
1459
|
+
# EOT
|
1460
|
+
# d = REXML::Document.new(xml_string)
|
1461
|
+
# is = d.root.instructions
|
1462
|
+
# is.frozen? # => true
|
1463
|
+
# is.map {|i| i.class } # => [REXML::Instruction, REXML::Instruction]
|
1464
|
+
# is.map {|i| i.to_s } # => ["<?target0 foo?>", "<?target1 bar?>"]
|
1465
|
+
#
|
680
1466
|
def instructions
|
681
1467
|
find_all { |child| child.kind_of? Instruction }.freeze
|
682
1468
|
end
|
683
1469
|
|
684
|
-
#
|
685
|
-
#
|
1470
|
+
# :call-seq:
|
1471
|
+
# texts -> array_of_text_children
|
1472
|
+
#
|
1473
|
+
# Returns a frozen array of the REXML::Text children of the element:
|
1474
|
+
#
|
1475
|
+
# xml_string = '<root><a/>text<b/>more<c/></root>'
|
1476
|
+
# d = REXML::Document.new(xml_string)
|
1477
|
+
# ts = d.root.texts
|
1478
|
+
# ts.frozen? # => true
|
1479
|
+
# ts.map {|t| t.class } # => [REXML::Text, REXML::Text]
|
1480
|
+
# ts.map {|t| t.to_s } # => ["text", "more"]
|
1481
|
+
#
|
686
1482
|
def texts
|
687
1483
|
find_all { |child| child.kind_of? Text }.freeze
|
688
1484
|
end
|
@@ -758,35 +1554,129 @@ module REXML
|
|
758
1554
|
# XPath search support. You are expected to only encounter this class as
|
759
1555
|
# the <tt>element.elements</tt> object. Therefore, you are
|
760
1556
|
# _not_ expected to instantiate this yourself.
|
1557
|
+
#
|
1558
|
+
# xml_string = <<-EOT
|
1559
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
1560
|
+
# <bookstore>
|
1561
|
+
# <book category="cooking">
|
1562
|
+
# <title lang="en">Everyday Italian</title>
|
1563
|
+
# <author>Giada De Laurentiis</author>
|
1564
|
+
# <year>2005</year>
|
1565
|
+
# <price>30.00</price>
|
1566
|
+
# </book>
|
1567
|
+
# <book category="children">
|
1568
|
+
# <title lang="en">Harry Potter</title>
|
1569
|
+
# <author>J K. Rowling</author>
|
1570
|
+
# <year>2005</year>
|
1571
|
+
# <price>29.99</price>
|
1572
|
+
# </book>
|
1573
|
+
# <book category="web">
|
1574
|
+
# <title lang="en">XQuery Kick Start</title>
|
1575
|
+
# <author>James McGovern</author>
|
1576
|
+
# <author>Per Bothner</author>
|
1577
|
+
# <author>Kurt Cagle</author>
|
1578
|
+
# <author>James Linn</author>
|
1579
|
+
# <author>Vaidyanathan Nagarajan</author>
|
1580
|
+
# <year>2003</year>
|
1581
|
+
# <price>49.99</price>
|
1582
|
+
# </book>
|
1583
|
+
# <book category="web" cover="paperback">
|
1584
|
+
# <title lang="en">Learning XML</title>
|
1585
|
+
# <author>Erik T. Ray</author>
|
1586
|
+
# <year>2003</year>
|
1587
|
+
# <price>39.95</price>
|
1588
|
+
# </book>
|
1589
|
+
# </bookstore>
|
1590
|
+
# EOT
|
1591
|
+
# d = REXML::Document.new(xml_string)
|
1592
|
+
# elements = d.root.elements
|
1593
|
+
# elements # => #<REXML::Elements @element=<bookstore> ... </>>
|
1594
|
+
#
|
761
1595
|
class Elements
|
762
1596
|
include Enumerable
|
763
|
-
#
|
764
|
-
#
|
1597
|
+
# :call-seq:
|
1598
|
+
# new(parent) -> new_elements_object
|
1599
|
+
#
|
1600
|
+
# Returns a new \Elements object with the given +parent+.
|
1601
|
+
# Does _not_ assign <tt>parent.elements = self</tt>:
|
1602
|
+
#
|
1603
|
+
# d = REXML::Document.new(xml_string)
|
1604
|
+
# eles = REXML::Elements.new(d.root)
|
1605
|
+
# eles # => #<REXML::Elements @element=<bookstore> ... </>>
|
1606
|
+
# eles == d.root.elements # => false
|
1607
|
+
#
|
765
1608
|
def initialize parent
|
766
1609
|
@element = parent
|
767
1610
|
end
|
768
1611
|
|
769
|
-
#
|
770
|
-
#
|
771
|
-
#
|
772
|
-
#
|
773
|
-
#
|
774
|
-
#
|
775
|
-
#
|
776
|
-
#
|
777
|
-
#
|
778
|
-
#
|
779
|
-
#
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
#
|
785
|
-
#
|
786
|
-
#
|
787
|
-
#
|
788
|
-
#
|
789
|
-
#
|
1612
|
+
# :call-seq:
|
1613
|
+
# parent
|
1614
|
+
#
|
1615
|
+
# Returns the parent element cited in creating the \Elements object.
|
1616
|
+
# This element is also the default starting point for searching
|
1617
|
+
# in the \Elements object.
|
1618
|
+
#
|
1619
|
+
# d = REXML::Document.new(xml_string)
|
1620
|
+
# elements = REXML::Elements.new(d.root)
|
1621
|
+
# elements.parent == d.root # => true
|
1622
|
+
#
|
1623
|
+
def parent
|
1624
|
+
@element
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
# :call-seq:
|
1628
|
+
# elements[index] -> element or nil
|
1629
|
+
# elements[xpath] -> element or nil
|
1630
|
+
# elements[n, name] -> element or nil
|
1631
|
+
#
|
1632
|
+
# Returns the first \Element object selected by the arguments,
|
1633
|
+
# if any found, or +nil+ if none found.
|
1634
|
+
#
|
1635
|
+
# Notes:
|
1636
|
+
# - The +index+ is 1-based, not 0-based, so that:
|
1637
|
+
# - The first element has index <tt>1</tt>
|
1638
|
+
# - The _nth_ element has index +n+.
|
1639
|
+
# - The selection ignores non-\Element nodes.
|
1640
|
+
#
|
1641
|
+
# When the single argument +index+ is given,
|
1642
|
+
# returns the element given by the index, if any; otherwise, +nil+:
|
1643
|
+
#
|
1644
|
+
# d = REXML::Document.new(xml_string)
|
1645
|
+
# eles = d.root.elements
|
1646
|
+
# eles # => #<REXML::Elements @element=<bookstore> ... </>>
|
1647
|
+
# eles[1] # => <book category='cooking'> ... </>
|
1648
|
+
# eles.size # => 4
|
1649
|
+
# eles[4] # => <book category='web' cover='paperback'> ... </>
|
1650
|
+
# eles[5] # => nil
|
1651
|
+
#
|
1652
|
+
# The node at this index is not an \Element, and so is not returned:
|
1653
|
+
#
|
1654
|
+
# eles = d.root.first.first # => <title lang='en'> ... </>
|
1655
|
+
# eles.to_a # => ["Everyday Italian"]
|
1656
|
+
# eles[1] # => nil
|
1657
|
+
#
|
1658
|
+
# When the single argument +xpath+ is given,
|
1659
|
+
# returns the first element found via that +xpath+, if any; otherwise, +nil+:
|
1660
|
+
#
|
1661
|
+
# eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>>
|
1662
|
+
# eles['/bookstore'] # => <bookstore> ... </>
|
1663
|
+
# eles['//book'] # => <book category='cooking'> ... </>
|
1664
|
+
# eles['//book [@category="children"]'] # => <book category='children'> ... </>
|
1665
|
+
# eles['/nosuch'] # => nil
|
1666
|
+
# eles['//nosuch'] # => nil
|
1667
|
+
# eles['//book [@category="nosuch"]'] # => nil
|
1668
|
+
# eles['.'] # => <bookstore> ... </>
|
1669
|
+
# eles['..'].class # => REXML::Document
|
1670
|
+
#
|
1671
|
+
# With arguments +n+ and +name+ given,
|
1672
|
+
# returns the _nth_ found element that has the given +name+,
|
1673
|
+
# or +nil+ if there is no such _nth_ element:
|
1674
|
+
#
|
1675
|
+
# eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>>
|
1676
|
+
# eles[1, 'book'] # => <book category='cooking'> ... </>
|
1677
|
+
# eles[4, 'book'] # => <book category='web' cover='paperback'> ... </>
|
1678
|
+
# eles[5, 'book'] # => nil
|
1679
|
+
#
|
790
1680
|
def []( index, name=nil)
|
791
1681
|
if index.kind_of? Integer
|
792
1682
|
raise "index (#{index}) must be >= 1" if index < 1
|
@@ -806,19 +1696,42 @@ module REXML
|
|
806
1696
|
end
|
807
1697
|
end
|
808
1698
|
|
809
|
-
#
|
810
|
-
#
|
811
|
-
#
|
812
|
-
# element
|
813
|
-
#
|
814
|
-
#
|
815
|
-
#
|
1699
|
+
# :call-seq:
|
1700
|
+
# elements[] = index, replacement_element -> replacement_element or nil
|
1701
|
+
#
|
1702
|
+
# Replaces or adds an element.
|
1703
|
+
#
|
1704
|
+
# When <tt>eles[index]</tt> exists, replaces it with +replacement_element+
|
1705
|
+
# and returns +replacement_element+:
|
1706
|
+
#
|
1707
|
+
# d = REXML::Document.new(xml_string)
|
1708
|
+
# eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>>
|
1709
|
+
# eles[1] # => <book category='cooking'> ... </>
|
1710
|
+
# eles[1] = REXML::Element.new('foo')
|
1711
|
+
# eles[1] # => <foo/>
|
1712
|
+
#
|
1713
|
+
# Does nothing (or raises an exception)
|
1714
|
+
# if +replacement_element+ is not an \Element:
|
1715
|
+
# eles[2] # => <book category='web' cover='paperback'> ... </>
|
1716
|
+
# eles[2] = REXML::Text.new('bar')
|
1717
|
+
# eles[2] # => <book category='web' cover='paperback'> ... </>
|
1718
|
+
#
|
1719
|
+
# When <tt>eles[index]</tt> does not exist,
|
1720
|
+
# adds +replacement_element+ to the element and returns
|
1721
|
+
#
|
1722
|
+
# d = REXML::Document.new(xml_string)
|
1723
|
+
# eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>>
|
1724
|
+
# eles.size # => 4
|
1725
|
+
# eles[50] = REXML::Element.new('foo') # => <foo/>
|
1726
|
+
# eles.size # => 5
|
1727
|
+
# eles[5] # => <foo/>
|
1728
|
+
#
|
1729
|
+
# Does nothing (or raises an exception)
|
1730
|
+
# if +replacement_element+ is not an \Element:
|
1731
|
+
#
|
1732
|
+
# eles[50] = REXML::Text.new('bar') # => "bar"
|
1733
|
+
# eles.size # => 5
|
816
1734
|
#
|
817
|
-
# doc = Document.new '<a/>'
|
818
|
-
# doc.root.elements[10] = Element.new('b') #-> <a><b/></a>
|
819
|
-
# doc.root.elements[1] #-> <b/>
|
820
|
-
# doc.root.elements[1] = Element.new('c') #-> <a><c/></a>
|
821
|
-
# doc.root.elements['c'] = Element.new('d') #-> <a><d/></a>
|
822
1735
|
def []=( index, element )
|
823
1736
|
previous = self[index]
|
824
1737
|
if previous.nil?
|
@@ -829,14 +1742,34 @@ module REXML
|
|
829
1742
|
return previous
|
830
1743
|
end
|
831
1744
|
|
832
|
-
#
|
1745
|
+
# :call-seq:
|
1746
|
+
# empty? -> true or false
|
1747
|
+
#
|
1748
|
+
# Returns +true+ if there are no children, +false+ otherwise.
|
1749
|
+
#
|
1750
|
+
# d = REXML::Document.new('')
|
1751
|
+
# d.elements.empty? # => true
|
1752
|
+
# d = REXML::Document.new(xml_string)
|
1753
|
+
# d.elements.empty? # => false
|
1754
|
+
#
|
833
1755
|
def empty?
|
834
1756
|
@element.find{ |child| child.kind_of? Element}.nil?
|
835
1757
|
end
|
836
1758
|
|
837
|
-
#
|
838
|
-
#
|
839
|
-
#
|
1759
|
+
# :call-seq:
|
1760
|
+
# index(element)
|
1761
|
+
#
|
1762
|
+
# Returns the 1-based index of the given +element+, if found;
|
1763
|
+
# otherwise, returns -1:
|
1764
|
+
#
|
1765
|
+
# d = REXML::Document.new(xml_string)
|
1766
|
+
# elements = d.root.elements
|
1767
|
+
# ele_1, ele_2, ele_3, ele_4 = *elements
|
1768
|
+
# elements.index(ele_4) # => 4
|
1769
|
+
# elements.delete(ele_3)
|
1770
|
+
# elements.index(ele_4) # => 3
|
1771
|
+
# elements.index(ele_3) # => -1
|
1772
|
+
#
|
840
1773
|
def index element
|
841
1774
|
rv = 0
|
842
1775
|
found = @element.find do |child|
|
@@ -848,17 +1781,47 @@ module REXML
|
|
848
1781
|
return -1
|
849
1782
|
end
|
850
1783
|
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
854
|
-
# xpath
|
855
|
-
#
|
856
|
-
#
|
857
|
-
#
|
858
|
-
#
|
859
|
-
#
|
860
|
-
#
|
861
|
-
#
|
1784
|
+
# :call-seq:
|
1785
|
+
# delete(index) -> removed_element or nil
|
1786
|
+
# delete(element) -> removed_element or nil
|
1787
|
+
# delete(xpath) -> removed_element or nil
|
1788
|
+
#
|
1789
|
+
# Removes an element; returns the removed element, or +nil+ if none removed.
|
1790
|
+
#
|
1791
|
+
# With integer argument +index+ given,
|
1792
|
+
# removes the child element at that offset:
|
1793
|
+
#
|
1794
|
+
# d = REXML::Document.new(xml_string)
|
1795
|
+
# elements = d.root.elements
|
1796
|
+
# elements.size # => 4
|
1797
|
+
# elements[2] # => <book category='children'> ... </>
|
1798
|
+
# elements.delete(2) # => <book category='children'> ... </>
|
1799
|
+
# elements.size # => 3
|
1800
|
+
# elements[2] # => <book category='web'> ... </>
|
1801
|
+
# elements.delete(50) # => nil
|
1802
|
+
#
|
1803
|
+
# With element argument +element+ given,
|
1804
|
+
# removes that child element:
|
1805
|
+
#
|
1806
|
+
# d = REXML::Document.new(xml_string)
|
1807
|
+
# elements = d.root.elements
|
1808
|
+
# ele_1, ele_2, ele_3, ele_4 = *elements
|
1809
|
+
# elements.size # => 4
|
1810
|
+
# elements[2] # => <book category='children'> ... </>
|
1811
|
+
# elements.delete(ele_2) # => <book category='children'> ... </>
|
1812
|
+
# elements.size # => 3
|
1813
|
+
# elements[2] # => <book category='web'> ... </>
|
1814
|
+
# elements.delete(ele_2) # => nil
|
1815
|
+
#
|
1816
|
+
# With string argument +xpath+ given,
|
1817
|
+
# removes the first element found via that xpath:
|
1818
|
+
#
|
1819
|
+
# d = REXML::Document.new(xml_string)
|
1820
|
+
# elements = d.root.elements
|
1821
|
+
# elements.delete('//book') # => <book category='cooking'> ... </>
|
1822
|
+
# elements.delete('//book [@category="children"]') # => <book category='children'> ... </>
|
1823
|
+
# elements.delete('//nosuch') # => nil
|
1824
|
+
#
|
862
1825
|
def delete element
|
863
1826
|
if element.kind_of? Element
|
864
1827
|
@element.delete element
|
@@ -868,12 +1831,23 @@ module REXML
|
|
868
1831
|
end
|
869
1832
|
end
|
870
1833
|
|
871
|
-
#
|
872
|
-
#
|
873
|
-
#
|
874
|
-
#
|
875
|
-
#
|
876
|
-
#
|
1834
|
+
# :call-seq:
|
1835
|
+
# delete_all(xpath)
|
1836
|
+
#
|
1837
|
+
# Removes all elements found via the given +xpath+;
|
1838
|
+
# returns the array of removed elements, if any, else +nil+.
|
1839
|
+
#
|
1840
|
+
# d = REXML::Document.new(xml_string)
|
1841
|
+
# elements = d.root.elements
|
1842
|
+
# elements.size # => 4
|
1843
|
+
# deleted_elements = elements.delete_all('//book [@category="web"]')
|
1844
|
+
# deleted_elements.size # => 2
|
1845
|
+
# elements.size # => 2
|
1846
|
+
# deleted_elements = elements.delete_all('//book')
|
1847
|
+
# deleted_elements.size # => 2
|
1848
|
+
# elements.size # => 0
|
1849
|
+
# elements.delete_all('//book') # => []
|
1850
|
+
#
|
877
1851
|
def delete_all( xpath )
|
878
1852
|
rv = []
|
879
1853
|
XPath::each( @element, xpath) {|element|
|
@@ -886,15 +1860,68 @@ module REXML
|
|
886
1860
|
return rv
|
887
1861
|
end
|
888
1862
|
|
889
|
-
#
|
890
|
-
#
|
891
|
-
#
|
892
|
-
#
|
893
|
-
#
|
894
|
-
#
|
895
|
-
#
|
896
|
-
#
|
897
|
-
#
|
1863
|
+
# :call-seq:
|
1864
|
+
# add -> new_element
|
1865
|
+
# add(name) -> new_element
|
1866
|
+
# add(element) -> element
|
1867
|
+
#
|
1868
|
+
# Adds an element; returns the element added.
|
1869
|
+
#
|
1870
|
+
# With no argument, creates and adds a new element.
|
1871
|
+
# The new element has:
|
1872
|
+
#
|
1873
|
+
# - No name.
|
1874
|
+
# - \Parent from the \Elements object.
|
1875
|
+
# - Context from the that parent.
|
1876
|
+
#
|
1877
|
+
# Example:
|
1878
|
+
#
|
1879
|
+
# d = REXML::Document.new(xml_string)
|
1880
|
+
# elements = d.root.elements
|
1881
|
+
# parent = elements.parent # => <bookstore> ... </>
|
1882
|
+
# parent.context = {raw: :all}
|
1883
|
+
# elements.size # => 4
|
1884
|
+
# new_element = elements.add # => </>
|
1885
|
+
# elements.size # => 5
|
1886
|
+
# new_element.name # => nil
|
1887
|
+
# new_element.parent # => <bookstore> ... </>
|
1888
|
+
# new_element.context # => {:raw=>:all}
|
1889
|
+
#
|
1890
|
+
# With string argument +name+, creates and adds a new element.
|
1891
|
+
# The new element has:
|
1892
|
+
#
|
1893
|
+
# - Name +name+.
|
1894
|
+
# - \Parent from the \Elements object.
|
1895
|
+
# - Context from the that parent.
|
1896
|
+
#
|
1897
|
+
# Example:
|
1898
|
+
#
|
1899
|
+
# d = REXML::Document.new(xml_string)
|
1900
|
+
# elements = d.root.elements
|
1901
|
+
# parent = elements.parent # => <bookstore> ... </>
|
1902
|
+
# parent.context = {raw: :all}
|
1903
|
+
# elements.size # => 4
|
1904
|
+
# new_element = elements.add('foo') # => <foo/>
|
1905
|
+
# elements.size # => 5
|
1906
|
+
# new_element.name # => "foo"
|
1907
|
+
# new_element.parent # => <bookstore> ... </>
|
1908
|
+
# new_element.context # => {:raw=>:all}
|
1909
|
+
#
|
1910
|
+
# With argument +element+,
|
1911
|
+
# creates and adds a clone of the given +element+.
|
1912
|
+
# The new element has name, parent, and context from the given +element+.
|
1913
|
+
#
|
1914
|
+
# d = REXML::Document.new(xml_string)
|
1915
|
+
# elements = d.root.elements
|
1916
|
+
# elements.size # => 4
|
1917
|
+
# e0 = REXML::Element.new('foo')
|
1918
|
+
# e1 = REXML::Element.new('bar', e0, {raw: :all})
|
1919
|
+
# element = elements.add(e1) # => <bar/>
|
1920
|
+
# elements.size # => 5
|
1921
|
+
# element.name # => "bar"
|
1922
|
+
# element.parent # => <bookstore> ... </>
|
1923
|
+
# element.context # => {:raw=>:all}
|
1924
|
+
#
|
898
1925
|
def add element=nil
|
899
1926
|
if element.nil?
|
900
1927
|
Element.new("", self, @element.context)
|
@@ -909,24 +1936,55 @@ module REXML
|
|
909
1936
|
|
910
1937
|
alias :<< :add
|
911
1938
|
|
912
|
-
#
|
913
|
-
#
|
914
|
-
#
|
915
|
-
#
|
916
|
-
#
|
917
|
-
#
|
918
|
-
#
|
919
|
-
#
|
920
|
-
#
|
921
|
-
#
|
922
|
-
#
|
923
|
-
#
|
924
|
-
#
|
925
|
-
#
|
1939
|
+
# :call-seq:
|
1940
|
+
# each(xpath = nil) {|element| ... } -> self
|
1941
|
+
#
|
1942
|
+
# Iterates over the elements.
|
1943
|
+
#
|
1944
|
+
# With no argument, calls the block with each element:
|
1945
|
+
#
|
1946
|
+
# d = REXML::Document.new(xml_string)
|
1947
|
+
# elements = d.root.elements
|
1948
|
+
# elements.each {|element| p element }
|
1949
|
+
#
|
1950
|
+
# Output:
|
1951
|
+
#
|
1952
|
+
# <book category='cooking'> ... </>
|
1953
|
+
# <book category='children'> ... </>
|
1954
|
+
# <book category='web'> ... </>
|
1955
|
+
# <book category='web' cover='paperback'> ... </>
|
1956
|
+
#
|
1957
|
+
# With argument +xpath+, calls the block with each element
|
1958
|
+
# that matches the given +xpath+:
|
1959
|
+
#
|
1960
|
+
# elements.each('//book [@category="web"]') {|element| p element }
|
1961
|
+
#
|
1962
|
+
# Output:
|
1963
|
+
#
|
1964
|
+
# <book category='web'> ... </>
|
1965
|
+
# <book category='web' cover='paperback'> ... </>
|
1966
|
+
#
|
926
1967
|
def each( xpath=nil )
|
927
1968
|
XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element }
|
928
1969
|
end
|
929
1970
|
|
1971
|
+
# :call-seq:
|
1972
|
+
# collect(xpath = nil) {|element| ... } -> array
|
1973
|
+
#
|
1974
|
+
# Iterates over the elements; returns the array of block return values.
|
1975
|
+
#
|
1976
|
+
# With no argument, iterates over all elements:
|
1977
|
+
#
|
1978
|
+
# d = REXML::Document.new(xml_string)
|
1979
|
+
# elements = d.root.elements
|
1980
|
+
# elements.collect {|element| element.size } # => [9, 9, 17, 9]
|
1981
|
+
#
|
1982
|
+
# With argument +xpath+, iterates over elements that match
|
1983
|
+
# the given +xpath+:
|
1984
|
+
#
|
1985
|
+
# xpath = '//book [@category="web"]'
|
1986
|
+
# elements.collect(xpath) {|element| element.size } # => [17, 9]
|
1987
|
+
#
|
930
1988
|
def collect( xpath=nil )
|
931
1989
|
collection = []
|
932
1990
|
XPath::each( @element, xpath ) {|e|
|
@@ -935,6 +1993,83 @@ module REXML
|
|
935
1993
|
collection
|
936
1994
|
end
|
937
1995
|
|
1996
|
+
# :call-seq:
|
1997
|
+
# inject(xpath = nil, initial = nil) -> object
|
1998
|
+
#
|
1999
|
+
# Calls the block with elements; returns the last block return value.
|
2000
|
+
#
|
2001
|
+
# With no argument, iterates over the elements, calling the block
|
2002
|
+
# <tt>elements.size - 1</tt> times.
|
2003
|
+
#
|
2004
|
+
# - The first call passes the first and second elements.
|
2005
|
+
# - The second call passes the first block return value and the third element.
|
2006
|
+
# - The third call passes the second block return value and the fourth element.
|
2007
|
+
# - And so on.
|
2008
|
+
#
|
2009
|
+
# In this example, the block returns the passed element,
|
2010
|
+
# which is then the object argument to the next call:
|
2011
|
+
#
|
2012
|
+
# d = REXML::Document.new(xml_string)
|
2013
|
+
# elements = d.root.elements
|
2014
|
+
# elements.inject do |object, element|
|
2015
|
+
# p [elements.index(object), elements.index(element)]
|
2016
|
+
# element
|
2017
|
+
# end
|
2018
|
+
#
|
2019
|
+
# Output:
|
2020
|
+
#
|
2021
|
+
# [1, 2]
|
2022
|
+
# [2, 3]
|
2023
|
+
# [3, 4]
|
2024
|
+
#
|
2025
|
+
# With the single argument +xpath+, calls the block only with
|
2026
|
+
# elements matching that xpath:
|
2027
|
+
#
|
2028
|
+
# elements.inject('//book [@category="web"]') do |object, element|
|
2029
|
+
# p [elements.index(object), elements.index(element)]
|
2030
|
+
# element
|
2031
|
+
# end
|
2032
|
+
#
|
2033
|
+
# Output:
|
2034
|
+
#
|
2035
|
+
# [3, 4]
|
2036
|
+
#
|
2037
|
+
# With argument +xpath+ given as +nil+
|
2038
|
+
# and argument +initial+ also given,
|
2039
|
+
# calls the block once for each element.
|
2040
|
+
#
|
2041
|
+
# - The first call passes the +initial+ and the first element.
|
2042
|
+
# - The second call passes the first block return value and the second element.
|
2043
|
+
# - The third call passes the second block return value and the third element.
|
2044
|
+
# - And so on.
|
2045
|
+
#
|
2046
|
+
# In this example, the first object index is <tt>-1</tt>
|
2047
|
+
#
|
2048
|
+
# elements.inject(nil, 'Initial') do |object, element|
|
2049
|
+
# p [elements.index(object), elements.index(element)]
|
2050
|
+
# element
|
2051
|
+
# end
|
2052
|
+
#
|
2053
|
+
# Output:
|
2054
|
+
#
|
2055
|
+
# [-1, 1]
|
2056
|
+
# [1, 2]
|
2057
|
+
# [2, 3]
|
2058
|
+
# [3, 4]
|
2059
|
+
#
|
2060
|
+
# In this form the passed object can be used as an accumulator:
|
2061
|
+
#
|
2062
|
+
# elements.inject(nil, 0) do |total, element|
|
2063
|
+
# total += element.size
|
2064
|
+
# end # => 44
|
2065
|
+
#
|
2066
|
+
# With both arguments +xpath+ and +initial+ are given,
|
2067
|
+
# calls the block only with elements matching that xpath:
|
2068
|
+
#
|
2069
|
+
# elements.inject('//book [@category="web"]', 0) do |total, element|
|
2070
|
+
# total += element.size
|
2071
|
+
# end # => 26
|
2072
|
+
#
|
938
2073
|
def inject( xpath=nil, initial=nil )
|
939
2074
|
first = true
|
940
2075
|
XPath::each( @element, xpath ) {|e|
|
@@ -950,23 +2085,39 @@ module REXML
|
|
950
2085
|
initial
|
951
2086
|
end
|
952
2087
|
|
953
|
-
#
|
954
|
-
#
|
955
|
-
#
|
956
|
-
#
|
2088
|
+
# :call-seq:
|
2089
|
+
# size -> integer
|
2090
|
+
#
|
2091
|
+
# Returns the count of \Element children:
|
2092
|
+
#
|
2093
|
+
# d = REXML::Document.new '<a>sean<b/>elliott<b/>russell<b/></a>'
|
2094
|
+
# d.root.elements.size # => 3 # Three elements.
|
2095
|
+
# d.root.size # => 6 # Three elements plus three text nodes..
|
2096
|
+
#
|
957
2097
|
def size
|
958
2098
|
count = 0
|
959
2099
|
@element.each {|child| count+=1 if child.kind_of? Element }
|
960
2100
|
count
|
961
2101
|
end
|
962
2102
|
|
963
|
-
#
|
964
|
-
#
|
965
|
-
#
|
966
|
-
#
|
967
|
-
#
|
968
|
-
#
|
969
|
-
#
|
2103
|
+
# :call-seq:
|
2104
|
+
# to_a(xpath = nil) -> array_of_elements
|
2105
|
+
#
|
2106
|
+
# Returns an array of element children (not including non-element children).
|
2107
|
+
#
|
2108
|
+
# With no argument, returns an array of all element children:
|
2109
|
+
#
|
2110
|
+
# d = REXML::Document.new '<a>sean<b/>elliott<c/></a>'
|
2111
|
+
# elements = d.root.elements
|
2112
|
+
# elements.to_a # => [<b/>, <c/>] # Omits non-element children.
|
2113
|
+
# children = d.root.children
|
2114
|
+
# children # => ["sean", <b/>, "elliott", <c/>] # Includes non-element children.
|
2115
|
+
#
|
2116
|
+
# With argument +xpath+, returns an array of element children
|
2117
|
+
# that match the xpath:
|
2118
|
+
#
|
2119
|
+
# elements.to_a('//c') # => [<c/>]
|
2120
|
+
#
|
970
2121
|
def to_a( xpath=nil )
|
971
2122
|
rv = XPath.match( @element, xpath )
|
972
2123
|
return rv.find_all{|e| e.kind_of? Element} if xpath
|
@@ -988,36 +2139,89 @@ module REXML
|
|
988
2139
|
# A class that defines the set of Attributes of an Element and provides
|
989
2140
|
# operations for accessing elements in that set.
|
990
2141
|
class Attributes < Hash
|
991
|
-
|
992
|
-
#
|
2142
|
+
|
2143
|
+
# :call-seq:
|
2144
|
+
# new(element)
|
2145
|
+
#
|
2146
|
+
# Creates and returns a new \REXML::Attributes object.
|
2147
|
+
# The element given by argument +element+ is stored,
|
2148
|
+
# but its own attributes are not modified:
|
2149
|
+
#
|
2150
|
+
# ele = REXML::Element.new('foo')
|
2151
|
+
# attrs = REXML::Attributes.new(ele)
|
2152
|
+
# attrs.object_id == ele.attributes.object_id # => false
|
2153
|
+
#
|
2154
|
+
# Other instance methods in class \REXML::Attributes may refer to:
|
2155
|
+
#
|
2156
|
+
# - +element.document+.
|
2157
|
+
# - +element.prefix+.
|
2158
|
+
# - +element.expanded_name+.
|
2159
|
+
#
|
993
2160
|
def initialize element
|
994
2161
|
@element = element
|
995
2162
|
end
|
996
2163
|
|
997
|
-
#
|
998
|
-
#
|
999
|
-
#
|
1000
|
-
# Returns
|
1001
|
-
#
|
1002
|
-
#
|
1003
|
-
#
|
2164
|
+
# :call-seq:
|
2165
|
+
# [name] -> attribute_value or nil
|
2166
|
+
#
|
2167
|
+
# Returns the value for the attribute given by +name+,
|
2168
|
+
# if it exists; otherwise +nil+.
|
2169
|
+
# The value returned is the unnormalized attribute value,
|
2170
|
+
# with entities expanded:
|
2171
|
+
#
|
2172
|
+
# xml_string = <<-EOT
|
2173
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2174
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2175
|
+
# </root>
|
2176
|
+
# EOT
|
2177
|
+
# d = REXML::Document.new(xml_string)
|
2178
|
+
# ele = d.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2179
|
+
# ele.attributes['att'] # => "<"
|
2180
|
+
# ele.attributes['bar:att'] # => "2"
|
2181
|
+
# ele.attributes['nosuch'] # => nil
|
2182
|
+
#
|
2183
|
+
# Related: get_attribute (returns an \Attribute object).
|
1004
2184
|
#
|
1005
|
-
# doc = Document.new "<a foo:att='1' bar:att='2' att='<'/>"
|
1006
|
-
# doc.root.attributes['att'] #-> '<'
|
1007
|
-
# doc.root.attributes['bar:att'] #-> '2'
|
1008
2185
|
def [](name)
|
1009
2186
|
attr = get_attribute(name)
|
1010
2187
|
return attr.value unless attr.nil?
|
1011
2188
|
return nil
|
1012
2189
|
end
|
1013
2190
|
|
2191
|
+
# :call-seq:
|
2192
|
+
# to_a -> array_of_attribute_objects
|
2193
|
+
#
|
2194
|
+
# Returns an array of \REXML::Attribute objects representing
|
2195
|
+
# the attributes:
|
2196
|
+
#
|
2197
|
+
# xml_string = <<-EOT
|
2198
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2199
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2200
|
+
# </root>
|
2201
|
+
# EOT
|
2202
|
+
# d = REXML::Document.new(xml_string)
|
2203
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2204
|
+
# attrs = ele.attributes.to_a # => [foo:att='1', bar:att='2', att='<']
|
2205
|
+
# attrs.first.class # => REXML::Attribute
|
2206
|
+
#
|
1014
2207
|
def to_a
|
1015
2208
|
enum_for(:each_attribute).to_a
|
1016
2209
|
end
|
1017
2210
|
|
1018
|
-
#
|
1019
|
-
#
|
1020
|
-
#
|
2211
|
+
# :call-seq:
|
2212
|
+
# length
|
2213
|
+
#
|
2214
|
+
# Returns the count of attributes:
|
2215
|
+
#
|
2216
|
+
# xml_string = <<-EOT
|
2217
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2218
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2219
|
+
# </root>
|
2220
|
+
# EOT
|
2221
|
+
# d = REXML::Document.new(xml_string)
|
2222
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2223
|
+
# ele.attributes.length # => 3
|
2224
|
+
#
|
1021
2225
|
def length
|
1022
2226
|
c = 0
|
1023
2227
|
each_attribute { c+=1 }
|
@@ -1025,13 +2229,28 @@ module REXML
|
|
1025
2229
|
end
|
1026
2230
|
alias :size :length
|
1027
2231
|
|
1028
|
-
#
|
1029
|
-
#
|
2232
|
+
# :call-seq:
|
2233
|
+
# each_attribute {|attr| ... }
|
2234
|
+
#
|
2235
|
+
# Calls the given block with each \REXML::Attribute object:
|
2236
|
+
#
|
2237
|
+
# xml_string = <<-EOT
|
2238
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2239
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2240
|
+
# </root>
|
2241
|
+
# EOT
|
2242
|
+
# d = REXML::Document.new(xml_string)
|
2243
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2244
|
+
# ele.attributes.each_attribute do |attr|
|
2245
|
+
# p [attr.class, attr]
|
2246
|
+
# end
|
2247
|
+
#
|
2248
|
+
# Output:
|
2249
|
+
#
|
2250
|
+
# [REXML::Attribute, foo:att='1']
|
2251
|
+
# [REXML::Attribute, bar:att='2']
|
2252
|
+
# [REXML::Attribute, att='<']
|
1030
2253
|
#
|
1031
|
-
# doc = Document.new '<a x="1" y="2"/>'
|
1032
|
-
# doc.root.attributes.each_attribute {|attr|
|
1033
|
-
# p attr.expanded_name+" => "+attr.value
|
1034
|
-
# }
|
1035
2254
|
def each_attribute # :yields: attribute
|
1036
2255
|
return to_enum(__method__) unless block_given?
|
1037
2256
|
each_value do |val|
|
@@ -1043,11 +2262,28 @@ module REXML
|
|
1043
2262
|
end
|
1044
2263
|
end
|
1045
2264
|
|
1046
|
-
#
|
1047
|
-
#
|
2265
|
+
# :call-seq:
|
2266
|
+
# each {|expanded_name, value| ... }
|
2267
|
+
#
|
2268
|
+
# Calls the given block with each expanded-name/value pair:
|
2269
|
+
#
|
2270
|
+
# xml_string = <<-EOT
|
2271
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2272
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2273
|
+
# </root>
|
2274
|
+
# EOT
|
2275
|
+
# d = REXML::Document.new(xml_string)
|
2276
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2277
|
+
# ele.attributes.each do |expanded_name, value|
|
2278
|
+
# p [expanded_name, value]
|
2279
|
+
# end
|
2280
|
+
#
|
2281
|
+
# Output:
|
2282
|
+
#
|
2283
|
+
# ["foo:att", "1"]
|
2284
|
+
# ["bar:att", "2"]
|
2285
|
+
# ["att", "<"]
|
1048
2286
|
#
|
1049
|
-
# doc = Document.new '<a x="1" y="2"/>'
|
1050
|
-
# doc.root.attributes.each {|name, value| p name+" => "+value }
|
1051
2287
|
def each
|
1052
2288
|
return to_enum(__method__) unless block_given?
|
1053
2289
|
each_attribute do |attr|
|
@@ -1055,15 +2291,25 @@ module REXML
|
|
1055
2291
|
end
|
1056
2292
|
end
|
1057
2293
|
|
1058
|
-
#
|
1059
|
-
#
|
1060
|
-
#
|
1061
|
-
#
|
1062
|
-
#
|
1063
|
-
#
|
1064
|
-
#
|
1065
|
-
#
|
1066
|
-
#
|
2294
|
+
# :call-seq:
|
2295
|
+
# get_attribute(name) -> attribute_object or nil
|
2296
|
+
#
|
2297
|
+
# Returns the \REXML::Attribute object for the given +name+:
|
2298
|
+
#
|
2299
|
+
# xml_string = <<-EOT
|
2300
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2301
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2302
|
+
# </root>
|
2303
|
+
# EOT
|
2304
|
+
# d = REXML::Document.new(xml_string)
|
2305
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2306
|
+
# attrs = ele.attributes
|
2307
|
+
# attrs.get_attribute('foo:att') # => foo:att='1'
|
2308
|
+
# attrs.get_attribute('foo:att').class # => REXML::Attribute
|
2309
|
+
# attrs.get_attribute('bar:att') # => bar:att='2'
|
2310
|
+
# attrs.get_attribute('att') # => att='<'
|
2311
|
+
# attrs.get_attribute('nosuch') # => nil
|
2312
|
+
#
|
1067
2313
|
def get_attribute( name )
|
1068
2314
|
attr = fetch( name, nil )
|
1069
2315
|
if attr.nil?
|
@@ -1097,18 +2343,29 @@ module REXML
|
|
1097
2343
|
return attr
|
1098
2344
|
end
|
1099
2345
|
|
1100
|
-
#
|
1101
|
-
#
|
1102
|
-
#
|
1103
|
-
# value
|
1104
|
-
#
|
1105
|
-
#
|
1106
|
-
#
|
1107
|
-
#
|
1108
|
-
#
|
1109
|
-
#
|
1110
|
-
#
|
1111
|
-
#
|
2346
|
+
# :call-seq:
|
2347
|
+
# [name] = value -> value
|
2348
|
+
#
|
2349
|
+
# When +value+ is non-+nil+,
|
2350
|
+
# assigns that to the attribute for the given +name+,
|
2351
|
+
# overwriting the previous value if it exists:
|
2352
|
+
#
|
2353
|
+
# xml_string = <<-EOT
|
2354
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2355
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2356
|
+
# </root>
|
2357
|
+
# EOT
|
2358
|
+
# d = REXML::Document.new(xml_string)
|
2359
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2360
|
+
# attrs = ele.attributes
|
2361
|
+
# attrs['foo:att'] = '2' # => "2"
|
2362
|
+
# attrs['baz:att'] = '3' # => "3"
|
2363
|
+
#
|
2364
|
+
# When +value+ is +nil+, deletes the attribute if it exists:
|
2365
|
+
#
|
2366
|
+
# attrs['baz:att'] = nil
|
2367
|
+
# attrs.include?('baz:att') # => false
|
2368
|
+
#
|
1112
2369
|
def []=( name, value )
|
1113
2370
|
if value.nil? # Delete the named attribute
|
1114
2371
|
attr = get_attribute(name)
|
@@ -1150,12 +2407,17 @@ module REXML
|
|
1150
2407
|
return @element
|
1151
2408
|
end
|
1152
2409
|
|
1153
|
-
#
|
1154
|
-
#
|
2410
|
+
# :call-seq:
|
2411
|
+
# prefixes -> array_of_prefix_strings
|
2412
|
+
#
|
2413
|
+
# Returns an array of prefix strings in the attributes.
|
2414
|
+
# The array does not include the default
|
1155
2415
|
# namespace declaration, if one exists.
|
1156
|
-
#
|
1157
|
-
#
|
1158
|
-
#
|
2416
|
+
#
|
2417
|
+
# xml_string = '<a xmlns="foo" xmlns:x="bar" xmlns:y="twee" z="glorp"/>'
|
2418
|
+
# d = REXML::Document.new(xml_string)
|
2419
|
+
# d.root.attributes.prefixes # => ["x", "y"]
|
2420
|
+
#
|
1159
2421
|
def prefixes
|
1160
2422
|
ns = []
|
1161
2423
|
each_attribute do |attribute|
|
@@ -1172,6 +2434,15 @@ module REXML
|
|
1172
2434
|
ns
|
1173
2435
|
end
|
1174
2436
|
|
2437
|
+
# :call-seq:
|
2438
|
+
# namespaces
|
2439
|
+
#
|
2440
|
+
# Returns a hash of name/value pairs for the namespaces:
|
2441
|
+
#
|
2442
|
+
# xml_string = '<a xmlns="foo" xmlns:x="bar" xmlns:y="twee" z="glorp"/>'
|
2443
|
+
# d = REXML::Document.new(xml_string)
|
2444
|
+
# d.root.attributes.namespaces # => {"xmlns"=>"foo", "x"=>"bar", "y"=>"twee"}
|
2445
|
+
#
|
1175
2446
|
def namespaces
|
1176
2447
|
namespaces = {}
|
1177
2448
|
each_attribute do |attribute|
|
@@ -1188,16 +2459,34 @@ module REXML
|
|
1188
2459
|
namespaces
|
1189
2460
|
end
|
1190
2461
|
|
1191
|
-
#
|
1192
|
-
#
|
1193
|
-
#
|
1194
|
-
#
|
1195
|
-
#
|
1196
|
-
#
|
1197
|
-
#
|
1198
|
-
#
|
1199
|
-
#
|
1200
|
-
#
|
2462
|
+
# :call-seq:
|
2463
|
+
# delete(name) -> element
|
2464
|
+
# delete(attribute) -> element
|
2465
|
+
#
|
2466
|
+
# Removes a specified attribute if it exists;
|
2467
|
+
# returns the attributes' element.
|
2468
|
+
#
|
2469
|
+
# When string argument +name+ is given,
|
2470
|
+
# removes the attribute of that name if it exists:
|
2471
|
+
#
|
2472
|
+
# xml_string = <<-EOT
|
2473
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2474
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2475
|
+
# </root>
|
2476
|
+
# EOT
|
2477
|
+
# d = REXML::Document.new(xml_string)
|
2478
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2479
|
+
# attrs = ele.attributes
|
2480
|
+
# attrs.delete('foo:att') # => <ele bar:att='2' att='<'/>
|
2481
|
+
# attrs.delete('foo:att') # => <ele bar:att='2' att='<'/>
|
2482
|
+
#
|
2483
|
+
# When attribute argument +attribute+ is given,
|
2484
|
+
# removes that attribute if it exists:
|
2485
|
+
#
|
2486
|
+
# attr = REXML::Attribute.new('bar:att', '2')
|
2487
|
+
# attrs.delete(attr) # => <ele att='<'/> # => <ele att='<'/>
|
2488
|
+
# attrs.delete(attr) # => <ele att='<'/> # => <ele/>
|
2489
|
+
#
|
1201
2490
|
def delete( attribute )
|
1202
2491
|
name = nil
|
1203
2492
|
prefix = nil
|
@@ -1225,19 +2514,48 @@ module REXML
|
|
1225
2514
|
@element
|
1226
2515
|
end
|
1227
2516
|
|
1228
|
-
#
|
1229
|
-
#
|
1230
|
-
#
|
2517
|
+
# :call-seq:
|
2518
|
+
# add(attribute) -> attribute
|
2519
|
+
#
|
2520
|
+
# Adds attribute +attribute+, replacing the previous
|
2521
|
+
# attribute of the same name if it exists;
|
2522
|
+
# returns +attribute+:
|
2523
|
+
#
|
2524
|
+
# xml_string = <<-EOT
|
2525
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2526
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2527
|
+
# </root>
|
2528
|
+
# EOT
|
2529
|
+
# d = REXML::Document.new(xml_string)
|
2530
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2531
|
+
# attrs = ele.attributes
|
2532
|
+
# attrs # => {"att"=>{"foo"=>foo:att='1', "bar"=>bar:att='2', ""=>att='<'}}
|
2533
|
+
# attrs.add(REXML::Attribute.new('foo:att', '2')) # => foo:att='2'
|
2534
|
+
# attrs.add(REXML::Attribute.new('baz', '3')) # => baz='3'
|
2535
|
+
# attrs.include?('baz') # => true
|
2536
|
+
#
|
1231
2537
|
def add( attribute )
|
1232
2538
|
self[attribute.name] = attribute
|
1233
2539
|
end
|
1234
2540
|
|
1235
2541
|
alias :<< :add
|
1236
2542
|
|
1237
|
-
#
|
1238
|
-
#
|
1239
|
-
#
|
1240
|
-
#
|
2543
|
+
# :call-seq:
|
2544
|
+
# delete_all(name) -> array_of_removed_attributes
|
2545
|
+
#
|
2546
|
+
# Removes all attributes matching the given +name+;
|
2547
|
+
# returns an array of the removed attributes:
|
2548
|
+
#
|
2549
|
+
# xml_string = <<-EOT
|
2550
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2551
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2552
|
+
# </root>
|
2553
|
+
# EOT
|
2554
|
+
# d = REXML::Document.new(xml_string)
|
2555
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2556
|
+
# attrs = ele.attributes
|
2557
|
+
# attrs.delete_all('att') # => [att='<']
|
2558
|
+
#
|
1241
2559
|
def delete_all( name )
|
1242
2560
|
rv = []
|
1243
2561
|
each_attribute { |attribute|
|
@@ -1247,11 +2565,23 @@ module REXML
|
|
1247
2565
|
return rv
|
1248
2566
|
end
|
1249
2567
|
|
1250
|
-
#
|
1251
|
-
#
|
1252
|
-
#
|
2568
|
+
# :call-seq:
|
2569
|
+
# get_attribute_ns(namespace, name)
|
2570
|
+
#
|
2571
|
+
# Returns the \REXML::Attribute object among the attributes
|
2572
|
+
# that matches the given +namespace+ and +name+:
|
2573
|
+
#
|
2574
|
+
# xml_string = <<-EOT
|
2575
|
+
# <root xmlns:foo="http://foo" xmlns:bar="http://bar">
|
2576
|
+
# <ele foo:att='1' bar:att='2' att='<'/>
|
2577
|
+
# </root>
|
2578
|
+
# EOT
|
2579
|
+
# d = REXML::Document.new(xml_string)
|
2580
|
+
# ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='<'/>
|
2581
|
+
# attrs = ele.attributes
|
2582
|
+
# attrs.get_attribute_ns('http://foo', 'att') # => foo:att='1'
|
2583
|
+
# attrs.get_attribute_ns('http://foo', 'nosuch') # => nil
|
1253
2584
|
#
|
1254
|
-
# Method contributed by Henrik Martensson
|
1255
2585
|
def get_attribute_ns(namespace, name)
|
1256
2586
|
result = nil
|
1257
2587
|
each_attribute() { |attribute|
|