Class | REXML::Element |
In: |
lib/rexml/element.rb
|
Parent: | Parent |
UNDEFINED | = | "UNDEFINED"; |
attributes | [R] | Mechanisms for accessing attributes and child elements of this element. |
context | [RW] | The context holds information about the processing environment, such as whitespace handling. |
elements | [R] | Mechanisms for accessing attributes and child elements of this element. |
Constructor
arg: | if not supplied, will be set to the default value. If a String, the name of this object will be set to the argument. If an Element, the object will be shallowly cloned; name, attributes, and namespaces will be copied. Children will not be copied. |
parent: | if supplied, must be a Parent, and will be used as the parent of this object. |
context: | If supplied, must be a hash containing context items. Context items include: |
# File lib/rexml/element.rb, line 58 58: def initialize( arg = UNDEFINED, parent=nil, context=nil ) 59: super(parent) 60: 61: @elements = Elements.new(self) 62: @attributes = Attributes.new(self) 63: @context = context 64: 65: if arg.kind_of? String 66: self.name = arg 67: elsif arg.kind_of? Element 68: self.name = arg.expanded_name 69: arg.attributes.each_attribute{ |attribute| 70: @attributes << Attribute.new( attribute ) 71: } 72: @context = arg.context 73: end 74: end
Adds an attribute to this element, overwriting any existing attribute by the same name.
key: | can be either an Attribute or a String. If an Attribute, the attribute is added to the list of Element attributes. If String, the argument is used as the name of the new attribute, and the value parameter must be supplied. |
value: | Required if key is a String, and ignored if the first argument is an Attribute. This is a String, and is used as the value of the new Attribute. This should be the unnormalized value of the attribute (without entities). |
Returns: | the Attribute added |
e = Element.new 'e' e.add_attribute( 'a', 'b' ) #-> <e a='b'/> e.add_attribute( 'x:a', 'c' ) #-> <e a='b' x:a='c'/> e.add_attribute Attribute.new('b', 'd') #-> <e a='b' x:a='c' b='d'/>
# File lib/rexml/element.rb, line 583 583: def add_attribute( key, value=nil ) 584: if key.kind_of? Attribute 585: @attributes << key 586: else 587: @attributes[key] = value 588: end 589: end
Add multiple attributes to this element.
hash: | is either a hash, or array of arrays |
el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} ) el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] )
# File lib/rexml/element.rb, line 595 595: def add_attributes hash 596: if hash.kind_of? Hash 597: hash.each_pair {|key, value| @attributes[key] = value } 598: elsif hash.kind_of? Array 599: hash.each { |value| @attributes[ value[0] ] = value[1] } 600: end 601: end
Adds a child to this element, optionally setting attributes in the element.
element: | optional. If Element, the element is added. Otherwise, a new Element is constructed with the argument (see Element.initialize). |
attrs: | If supplied, must be a Hash containing String name,value pairs, which will be used to set the attributes of the new Element. |
Returns: | the Element that was added |
el = doc.add_element 'my-tag' el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'} el = Element.new 'my-tag' doc.add_element el
# File lib/rexml/element.rb, line 295 295: def add_element element, attrs=nil 296: raise "First argument must be either an element name, or an Element object" if element.nil? 297: el = @elements.add(element) 298: attrs.each do |key, value| 299: el.attributes[key]=Attribute.new(key,value,self) 300: end if attrs.kind_of? Hash 301: el 302: end
Adds a namespace to this element.
prefix: | the prefix string, or the namespace URI if uri is not supplied |
uri: | the namespace URI. May be nil, in which prefix is used as the URI |
Evaluates to: this Element
a = Element.new("a") a.add_namespace("xmlns:foo", "bar" ) a.add_namespace("foo", "bar") # shorthand for previous line a.add_namespace("twiddle") puts a #-> <a xmlns:foo='bar' xmlns='twiddle'/>
# File lib/rexml/element.rb, line 250 250: def add_namespace( prefix, uri=nil ) 251: unless uri 252: @attributes["xmlns"] = prefix 253: else 254: prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/ 255: @attributes[ prefix ] = uri 256: end 257: self 258: end
A helper method to add a Text child. Actual Text instances can be added with regular Parent methods, such as add() and <<()
text: | if a String, a new Text instance is created and added to the parent. If Text, the object is added directly. |
Returns: | this Element |
e = Element.new('a') #-> <e/> e.add_text 'foo' #-> <e>foo</e> e.add_text Text.new(' bar') #-> <e>foo bar</e>
Note that at the end of this example, the branch has 3 nodes; the ‘e’ element and 2 Text node children.
# File lib/rexml/element.rb, line 522 522: def add_text( text ) 523: if text.kind_of? String 524: if @children[-1].kind_of? Text 525: @children[-1] << text 526: return 527: end 528: text = Text.new( text, whitespace(), nil, raw() ) 529: end 530: self << text unless text.nil? 531: return self 532: end
# File lib/rexml/element.rb, line 553 553: def attribute( name, namespace=nil ) 554: prefix = nil 555: prefix = namespaces.index(namespace) if namespace 556: prefix = nil if prefix == 'xmlns' 557: attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" ) 558: end
Creates a shallow copy of self.
d = Document.new "<a><b/><b/><c><d/></c></a>" new_a = d.root.clone puts new_a # => "<a/>"
# File lib/rexml/element.rb, line 96 96: def clone 97: self.class.new self 98: end
Removes an attribute
key: | either an Attribute or a String. In either case, the attribute is found by matching the attribute name to the argument, and then removed. If no attribute is found, no action is taken. |
Returns: | the attribute removed, or nil if this Element did not contain a matching attribute |
e = Element.new('E') e.add_attribute( 'name', 'Sean' ) #-> <E name='Sean'/> r = e.add_attribute( 'sur:name', 'Russell' ) #-> <E name='Sean' sur:name='Russell'/> e.delete_attribute( 'name' ) #-> <E sur:name='Russell'/> e.delete_attribute( r ) #-> <E/>
# File lib/rexml/element.rb, line 616 616: def delete_attribute(key) 617: attr = @attributes.get_attribute(key) 618: attr.remove unless attr.nil? 619: end
Deletes a child element.
element: | Must be an Element, String, or Integer. If Element, the element is removed. If String, the element is found (via XPath) and removed. <em>This means that any parent can remove any descendant.<em> If Integer, the Element indexed by that number will be removed. |
Returns: | the element that was removed. |
doc.delete_element "/a/b/c[@id='4']" doc.delete_element doc.elements["//k"] doc.delete_element 1
# File lib/rexml/element.rb, line 315 315: def delete_element element 316: @elements.delete element 317: end
Removes a namespace from this node. This only works if the namespace is actually declared in this node. If no argument is passed, deletes the default namespace.
Evaluates to: this element
doc = Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>" doc.root.delete_namespace puts doc # -> <a xmlns:foo='bar'/> doc.root.delete_namespace 'foo' puts doc # -> <a/>
# File lib/rexml/element.rb, line 270 270: def delete_namespace namespace="xmlns" 271: namespace = "xmlns:#{namespace}" unless namespace == 'xmlns' 272: attribute = attributes.get_attribute(namespace) 273: attribute.remove unless attribute.nil? 274: self 275: end
Synonym for Element.elements.each
# File lib/rexml/element.rb, line 392 392: def each_element( xpath=nil, &block ) # :yields: Element 393: @elements.each( xpath, &block ) 394: end
Iterates through the child elements, yielding for each Element that has a particular attribute set.
key: | the name of the attribute to search for |
value: | the value of the attribute |
max: | (optional) causes this method to return after yielding for this number of matching children |
name: | (optional) if supplied, this is an XPath that filters the children to check. |
doc = Document.new "<a><b @id='1'/><c @id='2'/><d @id='1'/><e/></a>" # Yields b, c, d doc.root.each_element_with_attribute( 'id' ) {|e| p e} # Yields b, d doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e} # Yields b doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e} # Yields d doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e}
# File lib/rexml/element.rb, line 350 350: def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element 351: each_with_something( proc {|child| 352: if value.nil? 353: child.attributes[key] != nil 354: else 355: child.attributes[key]==value 356: end 357: }, max, name, &block ) 358: end
Iterates through the children, yielding for each Element that has a particular text set.
text: | the text to search for. If nil, or not supplied, will iterate over all Element children that contain at least one Text node. |
max: | (optional) causes this method to return after yielding for this number of matching children |
name: | (optional) if supplied, this is an XPath that filters the children to check. |
doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>' # Yields b, c, d doc.each_element_with_text {|e|p e} # Yields b, c doc.each_element_with_text('b'){|e|p e} # Yields b doc.each_element_with_text('b', 1){|e|p e} # Yields d doc.each_element_with_text(nil, 0, 'd'){|e|p e}
# File lib/rexml/element.rb, line 381 381: def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element 382: each_with_something( proc {|child| 383: if text.nil? 384: child.has_text? 385: else 386: child.text == text 387: end 388: }, max, name, &block ) 389: end
Synonym for Element.to_a This is a little slower than calling elements.each directly.
xpath: | any XPath by which to search for elements in the tree |
Returns: | an array of Elements that match the supplied path |
# File lib/rexml/element.rb, line 400 400: def get_elements( xpath ) 401: @elements.to_a( xpath ) 402: end
Returns the first child Text node, if any, or nil otherwise. This method returns the actual Text node, rather than the String content.
doc = Document.new "<p>some text <b>this is bold!</b> more text</p>" # The element 'p' has two text elements, "some text " and " more text". doc.root.get_text.value #-> "some text "
# File lib/rexml/element.rb, line 461 461: def get_text path = nil 462: rv = nil 463: if path 464: element = @elements[ path ] 465: rv = element.get_text unless element.nil? 466: else 467: rv = @children.find { |node| node.kind_of? Text } 468: end 469: return rv 470: end
Evaluates to true if this element has any attributes set, false otherwise.
# File lib/rexml/element.rb, line 562 562: def has_attributes? 563: return !@attributes.empty? 564: end
Evaluates to true if this element has at least one child Element
doc = Document.new "<a><b/><c>Text</c></a>" doc.root.has_elements # -> true doc.elements["/a/b"].has_elements # -> false doc.elements["/a/c"].has_elements # -> false
# File lib/rexml/element.rb, line 324 324: def has_elements? 325: !@elements.empty? 326: end
# File lib/rexml/element.rb, line 161 161: def ignore_whitespace_nodes 162: @ignore_whitespace_nodes = false 163: if @context 164: if @context[:ignore_whitespace_nodes] 165: @ignore_whitespace_nodes = 166: (@context[:ignore_whitespace_nodes] == :all or 167: @context[:ignore_whitespace_nodes].include? expanded_name) 168: end 169: end 170: end
# File lib/rexml/element.rb, line 76 76: def inspect 77: rv = "<#@expanded_name" 78: 79: @attributes.each_attribute do |attr| 80: rv << " " 81: attr.write( rv, 0 ) 82: end 83: 84: if children.size > 0 85: rv << "> ... </>" 86: else 87: rv << "/>" 88: end 89: end
Get an array of all Instruction children. IMMUTABLE
# File lib/rexml/element.rb, line 639 639: def instructions 640: find_all { |child| child.kind_of? Instruction }.freeze 641: end
Evalutas to the URI for a prefix, or the empty string if no such namespace is declared for this element. Evaluates recursively for ancestors. Returns the default namespace, if there is one.
prefix: | the prefix to search for. If not supplied, returns the default namespace if one exists |
Returns: | the namespace URI as a String, or nil if no such namespace exists. If the namespace is undefined, returns an empty string |
doc = Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>") b = doc.elements['//b'] b.namespace # -> '1' b.namespace("y") # -> '2'
# File lib/rexml/element.rb, line 222 222: def namespace(prefix=nil) 223: if prefix.nil? 224: prefix = prefix() 225: end 226: if prefix == '' 227: prefix = "xmlns" 228: else 229: prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns' 230: end 231: ns = attributes[ prefix ] 232: ns = parent.namespace(prefix) if ns.nil? and parent 233: ns = '' if ns.nil? and prefix == 'xmlns' 234: return ns 235: end
# File lib/rexml/element.rb, line 202 202: def namespaces 203: namespaces = {} 204: namespaces = parent.namespaces if parent 205: namespaces = namespaces.merge( attributes.namespaces ) 206: return namespaces 207: end
Returns the next sibling that is an element, or nil if there is no Element sibling after this one
doc = Document.new '<a><b/>text<c/></a>' doc.root.elements['b'].next_element #-> <c/> doc.root.elements['c'].next_element #-> nil
# File lib/rexml/element.rb, line 409 409: def next_element 410: element = next_sibling 411: element = element.next_sibling until element.nil? or element.kind_of? Element 412: return element 413: end
Evaluates to an Array containing the prefixes (names) of all defined namespaces at this context node.
doc = Document.new("<a xmlns:x='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>") doc.elements['//b'].prefixes # -> ['x', 'y']
# File lib/rexml/element.rb, line 195 195: def prefixes 196: prefixes = [] 197: prefixes = parent.prefixes if parent 198: prefixes |= attributes.prefixes 199: return prefixes 200: end
Returns the previous sibling that is an element, or nil if there is no Element sibling prior to this one
doc = Document.new '<a><b/>text<c/></a>' doc.root.elements['c'].previous_element #-> <b/> doc.root.elements['b'].previous_element #-> nil
# File lib/rexml/element.rb, line 420 420: def previous_element 421: element = previous_sibling 422: element = element.previous_sibling until element.nil? or element.kind_of? Element 423: return element 424: end
Evaluates to true if raw mode is set for this element. This is the case if the context has :raw set to :all or an array containing the name of this element.
The evaluation is tested against expanded_name, and so is namespace sensitive.
# File lib/rexml/element.rb, line 178 178: def raw 179: @raw = (@context and @context[:raw] and 180: (@context[:raw] == :all or 181: @context[:raw].include? expanded_name)) 182: @raw 183: end
# File lib/rexml/element.rb, line 123 123: def root 124: return elements[1] if self.kind_of? Document 125: return self if parent.kind_of? Document or parent.nil? 126: return parent.root 127: end
Evaluates to the root node of the document that this element belongs to. If this element doesn‘t belong to a document, but does belong to another Element, the parent‘s root will be returned, until the earliest ancestor is found.
Note that this is not the same as the document element. In the following example, <a> is the document element, and the root node is the parent node of the document element. You may ask yourself why the root node is useful: consider the doctype and XML declaration, and any processing instructions before the document element… they are children of the root node, or siblings of the document element. The only time this isn‘t true is when an Element is created that is not part of any Document. In this case, the ancestor that has no parent acts as the root node.
d = Document.new '<a><b><c/></b></a>' a = d[1] ; c = a[1][1] d.root_node == d # TRUE a.root_node # namely, d c.root_node # again, d
# File lib/rexml/element.rb, line 119 119: def root_node 120: parent.nil? ? self : parent.root_node 121: end
A convenience method which returns the String value of the first child text element, if one exists, and nil otherwise.
Note that an element may have multiple Text elements, perhaps separated by other children. Be aware that this method only returns the first Text node.
This method returns the value of the first text child node, which ignores the raw setting, so always returns normalized text. See the Text::value documentation.
doc = Document.new "<p>some text <b>this is bold!</b> more text</p>" # The element 'p' has two text elements, "some text " and " more text". doc.root.text #-> "some text "
# File lib/rexml/element.rb, line 450 450: def text( path = nil ) 451: rv = get_text(path) 452: return rv.value unless rv.nil? 453: nil 454: end
Sets the first Text child of this object. See text() for a discussion about Text children.
If a Text child already exists, the child is replaced by this content. This means that Text content can be deleted by calling this method with a nil argument. In this case, the next Text child becomes the first Text child. In no case is the order of any siblings disturbed.
text: | If a String, a new Text child is created and added to this Element as the first Text child. If Text, the text is set as the first Child element. If nil, then any existing first Text child is removed. |
Returns: | this Element. |
doc = Document.new '<a><b/></a>' doc.root.text = 'Sean' #-> '<a><b/>Sean</a>' doc.root.text = 'Elliott' #-> '<a><b/>Elliott</a>' doc.root.add_element 'c' #-> '<a><b/>Elliott<c/></a>' doc.root.text = 'Russell' #-> '<a><b/>Russell<c/></a>' doc.root.text = nil #-> '<a><b/><c/></a>'
# File lib/rexml/element.rb, line 492 492: def text=( text ) 493: if text.kind_of? String 494: text = Text.new( text, whitespace(), nil, raw() ) 495: elsif text and !text.kind_of? Text 496: text = Text.new( text.to_s, whitespace(), nil, raw() ) 497: end 498: old_text = get_text 499: if text.nil? 500: old_text.remove unless old_text.nil? 501: else 502: if old_text.nil? 503: self << text 504: else 505: old_text.replace_with( text ) 506: end 507: end 508: return self 509: end
Evaluates to true if whitespace is respected for this element. This is the case if:
The evaluation is tested against expanded_name, and so is namespace sensitive.
# File lib/rexml/element.rb, line 145 145: def whitespace 146: @whitespace = nil 147: if @context 148: if @context[:respect_whitespace] 149: @whitespace = (@context[:respect_whitespace] == :all or 150: @context[:respect_whitespace].include? expanded_name) 151: end 152: @whitespace = false if (@context[:compress_whitespace] and 153: (@context[:compress_whitespace] == :all or 154: @context[:compress_whitespace].include? expanded_name) 155: ) 156: end 157: @whitespace = true unless @whitespace == false 158: @whitespace 159: end
Writes out this element, and recursively, all children.
output: | output an object which supports ’<< string’; this is where the |
document will be written.
indent: | An integer. If -1, no indenting will be used; otherwise, the indentation will be this number of spaces, and children will be indented an additional amount. Defaults to -1 |
transitive: | If transitive is true and indent is >= 0, then the output will be pretty-printed in such a way that the added whitespace does not affect the parse tree of the document |
ie_hack: | Internet Explorer is the worst piece of crap to have ever been written, with the possible exception of Windows itself. Since IE is unable to parse proper XML, we have to provide a hack to generate XML that IE‘s limited abilities can handle. This hack inserts a space before the /> on empty tags. Defaults to false |
out = '' doc.write( out ) #-> doc is written to the string 'out' doc.write( $stdout ) #-> doc written to the console
# File lib/rexml/element.rb, line 674 674: def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false) 675: Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") 676: formatter = if indent > -1 677: if transitive 678: REXML::Formatters::Transitive.new( indent, ie_hack ) 679: else 680: REXML::Formatters::Pretty.new( indent, ie_hack ) 681: end 682: else 683: REXML::Formatters::Default.new( ie_hack ) 684: end 685: formatter.write( self, output ) 686: end
# File lib/rexml/element.rb, line 538 538: def xpath 539: path_elements = [] 540: cur = self 541: path_elements << __to_xpath_helper( self ) 542: while cur.parent 543: cur = cur.parent 544: path_elements << __to_xpath_helper( cur ) 545: end 546: return path_elements.reverse.join( "/" ) 547: end
# File lib/rexml/element.rb, line 690 690: def __to_xpath_helper node 691: rv = node.expanded_name.clone 692: if node.parent 693: results = node.parent.find_all {|n| 694: n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name 695: } 696: if results.length > 1 697: idx = results.index( node ) 698: rv << "[#{idx+1}]" 699: end 700: end 701: rv 702: end