rexml 3.2.0 → 3.2.5

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.

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
- # Represents a tagged XML element. Elements are characterized by
19
- # having children, attributes, and names, and can themselves be
20
- # children.
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
- # Constructor
34
- # arg::
35
- # if not supplied, will be set to the default value.
36
- # If a String, the name of this object will be set to the argument.
37
- # If an Element, the object will be shallowly cloned; name,
38
- # attributes, and namespaces will be copied. Children will +not+ be
39
- # copied.
40
- # parent::
41
- # if supplied, must be a Parent, and will be used as
42
- # the parent of this object.
43
- # context::
44
- # If supplied, must be a hash containing context items. Context items
45
- # include:
46
- # * <tt>:respect_whitespace</tt> the value of this is :+all+ or an array of
47
- # strings being the names of the elements to respect
48
- # whitespace for. Defaults to :+all+.
49
- # * <tt>:compress_whitespace</tt> the value can be :+all+ or an array of
50
- # strings being the names of the elements to ignore whitespace on.
51
- # Overrides :+respect_whitespace+.
52
- # * <tt>:ignore_whitespace_nodes</tt> the value can be :+all+ or an array
53
- # of strings being the names of the elements in which to ignore
54
- # whitespace-only nodes. If this is set, Text nodes which contain only
55
- # whitespace will not be added to the document tree.
56
- # * <tt>:raw</tt> can be :+all+, or an array of strings being the names of
57
- # the elements to process in raw mode. In raw mode, special
58
- # characters in text is not converted to or from entities.
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
- # Creates a shallow copy of self.
94
- # d = Document.new "<a><b/><b/><c><d/></c></a>"
95
- # new_a = d.root.clone
96
- # puts new_a # => "<a/>"
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
- # Evaluates to the root node of the document that this element
102
- # belongs to. If this element doesn't belong to a document, but does
103
- # belong to another Element, the parent's root will be returned, until the
104
- # earliest ancestor is found.
105
- #
106
- # Note that this is not the same as the document element.
107
- # In the following example, <a> is the document element, and the root
108
- # node is the parent node of the document element. You may ask yourself
109
- # why the root node is useful: consider the doctype and XML declaration,
110
- # and any processing instructions before the document element... they
111
- # are children of the root node, or siblings of the document element.
112
- # The only time this isn't true is when an Element is created that is
113
- # not part of any Document. In this case, the ancestor that has no
114
- # parent acts as the root node.
115
- # d = Document.new '<a><b><c/></b></a>'
116
- # a = d[1] ; c = a[1][1]
117
- # d.root_node == d # TRUE
118
- # a.root_node # namely, d
119
- # c.root_node # again, d
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
- # Evaluates to the document to which this element belongs, or nil if this
131
- # element doesn't belong to a document.
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
- # Evaluates to +true+ if whitespace is respected for this element. This
138
- # is the case if:
139
- # 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value
140
- # 2. The context has :+respect_whitespace+ set to :+all+ or
141
- # an array containing the name of this element, and
142
- # :+compress_whitespace+ isn't set to :+all+ or an array containing the
143
- # name of this element.
144
- # The evaluation is tested against +expanded_name+, and so is namespace
145
- # sensitive.
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
- # Evaluates to +true+ if raw mode is set for this element. This
174
- # is the case if the context has :+raw+ set to :+all+ or
175
- # an array containing the name of this element.
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
- @raw
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
- # Evaluates to an +Array+ containing the prefixes (names) of all defined
193
- # namespaces at this context node.
194
- # doc = Document.new("<a xmlns:x='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
195
- # doc.elements['//b'].prefixes # -> ['x', 'y']
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
- # Evaluates to the URI for a prefix, or the empty string if no such
211
- # namespace is declared for this element. Evaluates recursively for
212
- # ancestors. Returns the default namespace, if there is one.
213
- # prefix::
214
- # the prefix to search for. If not supplied, returns the default
215
- # namespace if one exists
216
- # Returns::
217
- # the namespace URI as a String, or nil if no such namespace
218
- # exists. If the namespace is undefined, returns an empty string
219
- # doc = Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
220
- # b = doc.elements['//b']
221
- # b.namespace # -> '1'
222
- # b.namespace("y") # -> '2'
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
- # Adds a namespace to this element.
239
- # prefix::
240
- # the prefix string, or the namespace URI if +uri+ is not
241
- # supplied
242
- # uri::
243
- # the namespace URI. May be nil, in which +prefix+ is used as
244
- # the URI
245
- # Evaluates to: this Element
246
- # a = Element.new("a")
247
- # a.add_namespace("xmlns:foo", "bar" )
248
- # a.add_namespace("foo", "bar") # shorthand for previous line
249
- # a.add_namespace("twiddle")
250
- # puts a #-> <a xmlns:foo='bar' xmlns='twiddle'/>
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
- # Removes a namespace from this node. This only works if the namespace is
262
- # actually declared in this node. If no argument is passed, deletes the
263
- # default namespace.
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
- # Adds a child to this element, optionally setting attributes in
283
- # the element.
284
- # element::
285
- # optional. If Element, the element is added.
286
- # Otherwise, a new Element is constructed with the argument (see
287
- # Element.initialize).
288
- # attrs::
289
- # If supplied, must be a Hash containing String name,value
290
- # pairs, which will be used to set the attributes of the new Element.
291
- # Returns:: the Element that was added
292
- # el = doc.add_element 'my-tag'
293
- # el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'}
294
- # el = Element.new 'my-tag'
295
- # doc.add_element el
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
- # element::
307
- # Must be an +Element+, +String+, or +Integer+. If Element,
308
- # the element is removed. If String, the element is found (via XPath)
309
- # and removed. <em>This means that any parent can remove any
310
- # descendant.<em> If Integer, the Element indexed by that number will be
311
- # removed.
312
- # Returns:: the element that was removed.
313
- # doc.delete_element "/a/b/c[@id='4']"
314
- # doc.delete_element doc.elements["//k"]
315
- # doc.delete_element 1
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
- # Evaluates to +true+ if this element has at least one child Element
321
- # doc = Document.new "<a><b/><c>Text</c></a>"
322
- # doc.root.has_elements # -> true
323
- # doc.elements["/a/b"].has_elements # -> false
324
- # doc.elements["/a/c"].has_elements # -> false
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
- # Iterates through the child elements, yielding for each Element that
330
- # has a particular attribute set.
331
- # key::
332
- # the name of the attribute to search for
333
- # value::
334
- # the value of the attribute
335
- # max::
336
- # (optional) causes this method to return after yielding
337
- # for this number of matching children
338
- # name::
339
- # (optional) if supplied, this is an XPath that filters
340
- # the children to check.
341
- #
342
- # doc = Document.new "<a><b @id='1'/><c @id='2'/><d @id='1'/><e/></a>"
343
- # # Yields b, c, d
344
- # doc.root.each_element_with_attribute( 'id' ) {|e| p e}
345
- # # Yields b, d
346
- # doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e}
347
- # # Yields b
348
- # doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e}
349
- # # Yields d
350
- # doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e}
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
- # Iterates through the children, yielding for each Element that
362
- # has a particular text set.
363
- # text::
364
- # the text to search for. If nil, or not supplied, will iterate
365
- # over all +Element+ children that contain at least one +Text+ node.
366
- # max::
367
- # (optional) causes this method to return after yielding
368
- # for this number of matching children
369
- # name::
370
- # (optional) if supplied, this is an XPath that filters
371
- # the children to check.
372
- #
373
- # doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
374
- # # Yields b, c, d
375
- # doc.each_element_with_text {|e|p e}
376
- # # Yields b, c
377
- # doc.each_element_with_text('b'){|e|p e}
378
- # # Yields b
379
- # doc.each_element_with_text('b', 1){|e|p e}
380
- # # Yields d
381
- # doc.each_element_with_text(nil, 0, 'd'){|e|p e}
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
- # Synonym for Element.elements.each
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
- # Synonym for Element.to_a
398
- # This is a little slower than calling elements.each directly.
399
- # xpath:: any XPath by which to search for elements in the tree
400
- # Returns:: an array of Elements that match the supplied path
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
- # Returns the next sibling that is an element, or nil if there is
406
- # no Element sibling after this one
407
- # doc = Document.new '<a><b/>text<c/></a>'
408
- # doc.root.elements['b'].next_element #-> <c/>
409
- # doc.root.elements['c'].next_element #-> nil
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
- # Returns the previous sibling that is an element, or nil if there is
417
- # no Element sibling prior to this one
418
- # doc = Document.new '<a><b/>text<c/></a>'
419
- # doc.root.elements['c'].previous_element #-> <b/>
420
- # doc.root.elements['b'].previous_element #-> nil
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
- # Evaluates to +true+ if this element has at least one Text child
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
- # A convenience method which returns the String value of the _first_
438
- # child text element, if one exists, and +nil+ otherwise.
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 the first text node
1018
+ # in the element that matches +xpath+:
1019
+ #
1020
+ # d.root.text(1) # => "this is bold!"
439
1021
  #
440
- # <em>Note that an element may have multiple Text elements, perhaps
441
- # separated by other children</em>. Be aware that this method only returns
442
- # the first Text node.
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
- # This method returns the +value+ of the first text child node, which
445
- # ignores the +raw+ setting, so always returns normalized text. See
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
- # Returns the first child Text node, if any, or +nil+ otherwise.
458
- # This method returns the actual +Text+ node, rather than the String content.
459
- # doc = Document.new "<p>some text <b>this is bold!</b> more text</p>"
460
- # # The element 'p' has two text elements, "some text " and " more text".
461
- # doc.root.get_text.value #-> "some text "
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
- # Sets the first Text child of this object. See text() for a
474
- # discussion about Text children.
475
- #
476
- # If a Text child already exists, the child is replaced by this
477
- # content. This means that Text content can be deleted by calling
478
- # this method with a nil argument. In this case, the next Text
479
- # child becomes the first Text child. In no case is the order of
480
- # any siblings disturbed.
481
- # text::
482
- # If a String, a new Text child is created and added to
483
- # this Element as the first Text child. If Text, the text is set
484
- # as the first Child element. If nil, then any existing first Text
485
- # child is removed.
486
- # Returns:: this Element.
487
- # doc = Document.new '<a><b/></a>'
488
- # doc.root.text = 'Sean' #-> '<a><b/>Sean</a>'
489
- # doc.root.text = 'Elliott' #-> '<a><b/>Elliott</a>'
490
- # doc.root.add_element 'c' #-> '<a><b/>Elliott<c/></a>'
491
- # doc.root.text = 'Russell' #-> '<a><b/>Russell<c/></a>'
492
- # doc.root.text = nil #-> '<a><b/><c/></a>'
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
- # A helper method to add a Text child. Actual Text instances can
513
- # be added with regular Parent methods, such as add() and <<()
514
- # text::
515
- # if a String, a new Text instance is created and added
516
- # to the parent. If Text, the object is added directly.
517
- # Returns:: this Element
518
- # e = Element.new('a') #-> <e/>
519
- # e.add_text 'foo' #-> <e>foo</e>
520
- # e.add_text Text.new(' bar') #-> <e>foo bar</e>
521
- # Note that at the end of this example, the branch has <b>3</b> nodes; the 'e'
522
- # element and <b>2</b> Text node children.
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
- # Fetches an attribute value or a child.
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
- # If String or Symbol is specified, it's treated as attribute
557
- # name. Attribute value as String or +nil+ is returned. This case
558
- # is shortcut of +attributes[name]+.
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
- # If Integer is specified, it's treated as the index of
561
- # child. It returns Nth child.
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
- # Evaluates to +true+ if this element has any attributes set, false
602
- # otherwise.
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
- # key::
610
- # can be either an Attribute or a String. If an Attribute,
611
- # the attribute is added to the list of Element attributes. If String,
612
- # the argument is used as the name of the new attribute, and the value
613
- # parameter must be supplied.
614
- # value::
615
- # Required if +key+ is a String, and ignored if the first argument is
616
- # an Attribute. This is a String, and is used as the value
617
- # of the new Attribute. This should be the unnormalized value of the
618
- # attribute (without entities).
619
- # Returns:: the Attribute added
620
- # e = Element.new 'e'
621
- # e.add_attribute( 'a', 'b' ) #-> <e a='b'/>
622
- # e.add_attribute( 'x:a', 'c' ) #-> <e a='b' x:a='c'/>
623
- # e.add_attribute Attribute.new('b', 'd') #-> <e a='b' x:a='c' b='d'/>
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
- # Add multiple attributes to this element.
633
- # hash:: is either a hash, or array of arrays
634
- # el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} )
635
- # el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] )
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
- # Removes an attribute
645
- # key::
646
- # either an Attribute or a String. In either case, the
647
- # attribute is found by matching the attribute name to the argument,
648
- # and then removed. If no attribute is found, no action is taken.
649
- # Returns::
650
- # the attribute removed, or nil if this Element did not contain
651
- # a matching attribute
652
- # e = Element.new('E')
653
- # e.add_attribute( 'name', 'Sean' ) #-> <E name='Sean'/>
654
- # r = e.add_attribute( 'sur:name', 'Russell' ) #-> <E name='Sean' sur:name='Russell'/>
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
- # Get an array of all CData children.
667
- # IMMUTABLE
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
- # Get an array of all Comment children.
673
- # IMMUTABLE
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
- # Get an array of all Instruction children.
679
- # IMMUTABLE
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
- # Get an array of all Text children.
685
- # IMMUTABLE
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
- # Constructor
764
- # parent:: the parent Element
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
- # Fetches a child element. Filters only Element children, regardless of
770
- # the XPath match.
771
- # index::
772
- # the search parameter. This is either an Integer, which
773
- # will be used to find the index'th child Element, or an XPath,
774
- # which will be used to search for the Element. <em>Because
775
- # of the nature of XPath searches, any element in the connected XML
776
- # document can be fetched through any other element.</em> <b>The
777
- # Integer index is 1-based, not 0-based.</b> This means that the first
778
- # child element is at index 1, not 0, and the +n+th element is at index
779
- # +n+, not <tt>n-1</tt>. This is because XPath indexes element children
780
- # starting from 1, not 0, and the indexes should be the same.
781
- # name::
782
- # optional, and only used in the first argument is an
783
- # Integer. In that case, the index'th child Element that has the
784
- # supplied name will be returned. Note again that the indexes start at 1.
785
- # Returns:: the first matching Element, or nil if no child matched
786
- # doc = Document.new '<a><b/><c id="1"/><c id="2"/><d/></a>'
787
- # doc.root.elements[1] #-> <b/>
788
- # doc.root.elements['c'] #-> <c id="1"/>
789
- # doc.root.elements[2,'c'] #-> <c id="2"/>
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
- # Sets an element, replacing any previous matching element. If no
810
- # existing element is found ,the element is added.
811
- # index:: Used to find a matching element to replace. See []().
812
- # element::
813
- # The element to replace the existing element with
814
- # the previous element
815
- # Returns:: nil if no previous element was found.
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
- # Returns +true+ if there are no +Element+ children, +false+ otherwise
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
- # Returns the index of the supplied child (starting at 1), or -1 if
838
- # the element is not a child
839
- # element:: an +Element+ child
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
- # Deletes a child Element
852
- # element::
853
- # Either an Element, which is removed directly; an
854
- # xpath, where the first matching child is removed; or an Integer,
855
- # where the n'th Element is removed.
856
- # Returns:: the removed child
857
- # doc = Document.new '<a><b/><c/><c id="1"/></a>'
858
- # b = doc.root.elements[1]
859
- # doc.root.elements.delete b #-> <a><c/><c id="1"/></a>
860
- # doc.elements.delete("a/c[@id='1']") #-> <a><c/></a>
861
- # doc.root.elements.delete 1 #-> <a/>
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
- # Removes multiple elements. Filters for Element children, regardless of
872
- # XPath matching.
873
- # xpath:: all elements matching this String path are removed.
874
- # Returns:: an Array of Elements that have been removed
875
- # doc = Document.new '<a><c/><c/><c/><c/></a>'
876
- # deleted = doc.elements.delete_all 'a/c' #-> [<c/>, <c/>, <c/>, <c/>]
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
- # Adds an element
890
- # element::
891
- # if supplied, is either an Element, String, or
892
- # Source (see Element.initialize). If not supplied or nil, a
893
- # new, default Element will be constructed
894
- # Returns:: the added Element
895
- # a = Element.new('a')
896
- # a.elements.add(Element.new('b')) #-> <a><b/></a>
897
- # a.elements.add('c') #-> <a><b/><c/></a>
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
- # Iterates through all of the child Elements, optionally filtering
913
- # them by a given XPath
914
- # xpath::
915
- # optional. If supplied, this is a String XPath, and is used to
916
- # filter the children, so that only matching children are yielded. Note
917
- # that XPaths are automatically filtered for Elements, so that
918
- # non-Element children will not be yielded
919
- # doc = Document.new '<a><b/><c/><d/>sean<b/><c/><d/></a>'
920
- # doc.root.elements.each {|e|p e} #-> Yields b, c, d, b, c, d elements
921
- # doc.root.elements.each('b') {|e|p e} #-> Yields b, b elements
922
- # doc.root.elements.each('child::node()') {|e|p e}
923
- # #-> Yields <b/>, <c/>, <d/>, <b/>, <c/>, <d/>
924
- # XPath.each(doc.root, 'child::node()', &block)
925
- # #-> Yields <b/>, <c/>, <d/>, sean, <b/>, <c/>, <d/>
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
- # Returns the number of +Element+ children of the parent object.
954
- # doc = Document.new '<a>sean<b/>elliott<b/>russell<b/></a>'
955
- # doc.root.size #-> 6, 3 element and 3 text nodes
956
- # doc.root.elements.size #-> 3
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
- # Returns an Array of Element children. An XPath may be supplied to
964
- # filter the children. Only Element children are returned, even if the
965
- # supplied XPath matches non-Element children.
966
- # doc = Document.new '<a>sean<b/>elliott<c/></a>'
967
- # doc.root.elements.to_a #-> [ <b/>, <c/> ]
968
- # doc.root.elements.to_a("child::node()") #-> [ <b/>, <c/> ]
969
- # XPath.match(doc.root, "child::node()") #-> [ sean, <b/>, elliott, <c/> ]
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
- # Constructor
992
- # element:: the Element of which this is an Attribute
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
- # Fetches an attribute value. If you want to get the Attribute itself,
998
- # use get_attribute()
999
- # name:: an XPath attribute name. Namespaces are relevant here.
1000
- # Returns::
1001
- # the String value of the matching attribute, or +nil+ if no
1002
- # matching attribute was found. This is the unnormalized value
1003
- # (with entities expanded).
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='&lt;'/>
2175
+ # </root>
2176
+ # EOT
2177
+ # d = REXML::Document.new(xml_string)
2178
+ # ele = d.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
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='&lt;'/>"
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='&lt;'/>
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='&lt;'/>
2204
+ # attrs = ele.attributes.to_a # => [foo:att='1', bar:att='2', att='&lt;']
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
- # Returns the number of attributes the owning Element contains.
1019
- # doc = Document "<a x='1' y='2' foo:x='3'/>"
1020
- # doc.root.attributes.length #-> 3
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='&lt;'/>
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='&lt;'/>
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
- # Iterates over the attributes of an Element. Yields actual Attribute
1029
- # nodes, not String values.
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='&lt;'/>
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='&lt;'/>
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='&lt;']
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
- # Iterates over each attribute of an Element, yielding the expanded name
1047
- # and value as a pair of Strings.
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='&lt;'/>
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='&lt;'/>
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
- # Fetches an attribute
1059
- # name::
1060
- # the name by which to search for the attribute. Can be a
1061
- # <tt>prefix:name</tt> namespace name.
1062
- # Returns:: The first matching attribute, or nil if there was none. This
1063
- # value is an Attribute node, not the String value of the attribute.
1064
- # doc = Document.new '<a x:foo="1" foo="2" bar="3"/>'
1065
- # doc.root.attributes.get_attribute("foo").value #-> "2"
1066
- # doc.root.attributes.get_attribute("x:foo").value #-> "1"
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='&lt;'/>
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='&lt;'/>
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='&lt;'
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
- # Sets an attribute, overwriting any existing attribute value by the
1101
- # same name. Namespace is significant.
1102
- # name:: the name of the attribute
1103
- # value::
1104
- # (optional) If supplied, the value of the attribute. If
1105
- # nil, any existing matching attribute is deleted.
1106
- # Returns::
1107
- # Owning element
1108
- # doc = Document.new "<a x:foo='1' foo='3'/>"
1109
- # doc.root.attributes['y:foo'] = '2'
1110
- # doc.root.attributes['foo'] = '4'
1111
- # doc.root.attributes['x:foo'] = nil
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='&lt;'/>
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='&lt;'/>
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
- # Returns an array of Strings containing all of the prefixes declared
1154
- # by this set of # attributes. The array does not include the default
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
- # doc = Document.new("<a xmlns='foo' xmlns:x='bar' xmlns:y='twee' "+
1157
- # "z='glorp' p:k='gru'/>")
1158
- # prefixes = doc.root.attributes.prefixes #-> ['x', 'y']
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
- # Removes an attribute
1192
- # attribute::
1193
- # either a String, which is the name of the attribute to remove --
1194
- # namespaces are significant here -- or the attribute to remove.
1195
- # Returns:: the owning element
1196
- # doc = Document.new "<a y:foo='0' x:foo='1' foo='3' z:foo='4'/>"
1197
- # doc.root.attributes.delete 'foo' #-> <a y:foo='0' x:foo='1' z:foo='4'/>"
1198
- # doc.root.attributes.delete 'x:foo' #-> <a y:foo='0' z:foo='4'/>"
1199
- # attr = doc.root.attributes.get_attribute('y:foo')
1200
- # doc.root.attributes.delete attr #-> <a z:foo='4'/>"
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='&lt;'/>
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='&lt;'/>
2479
+ # attrs = ele.attributes
2480
+ # attrs.delete('foo:att') # => <ele bar:att='2' att='&lt;'/>
2481
+ # attrs.delete('foo:att') # => <ele bar:att='2' att='&lt;'/>
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='&lt;'/> # => <ele att='&lt;'/>
2488
+ # attrs.delete(attr) # => <ele att='&lt;'/> # => <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
- # Adds an attribute, overriding any existing attribute by the
1229
- # same name. Namespaces are significant.
1230
- # attribute:: An Attribute
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='&lt;'/>
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='&lt;'/>
2531
+ # attrs = ele.attributes
2532
+ # attrs # => {"att"=>{"foo"=>foo:att='1', "bar"=>bar:att='2', ""=>att='&lt;'}}
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
- # Deletes all attributes matching a name. Namespaces are significant.
1238
- # name::
1239
- # A String; all attributes that match this path will be removed
1240
- # Returns:: an Array of the Attributes that were removed
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='&lt;'/>
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='&lt;'/>
2556
+ # attrs = ele.attributes
2557
+ # attrs.delete_all('att') # => [att='&lt;']
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
- # The +get_attribute_ns+ method retrieves a method by its namespace
1251
- # and name. Thus it is possible to reliably identify an attribute
1252
- # even if an XML processor has changed the prefix.
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='&lt;'/>
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='&lt;'/>
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|