REXML::Element (Class)

In: rexml/element.rb
Parent: Parent

Represents a tagged XML element. Elements are characterized by having children, attributes, and names, and can themselves be children.

Constants

UNDEFINED = "UNDEFINED";

Attributes

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.

Included Modules

Namespace

Public Class methods

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. If a Source, the source will be scanned and parsed for an Element, and all child elements will be recursively parsed as well.
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:
  • :respect_whitespace the value of this is :all or an array of strings being the names of the elements to respect whitespace for. Defaults to :all.
  • :compress_whitespace the value can be :all or an array of strings being the names of the elements to ignore whitespace on. Overrides :respect_whitespace.
  • :ignore_whitespace_nodes the value can be :all or an array of strings being the names of the elements in which to ignore whitespace-only nodes. If this is set, Text nodes which contain only whitespace will not be added to the document tree.
  • :raw can be :all, or an array of strings being the names of the elements to process in raw mode. In raw mode, special characters in text is not converted to or from entities.

[Source]

# File rexml/element.rb, line 52
                def initialize( arg = UNDEFINED, parent=nil, context=nil )
                        super(parent)

                        @elements = Elements.new(self)
                        @attributes = Attributes.new(self)
                        @context = context

                        if arg.kind_of? String
                                self.name = arg
                        elsif arg.kind_of? Element
                                self.name = arg.expanded_name
                                arg.attributes.each_attribute{ |attribute|
                                        @attributes << Attribute.new( attribute )
                                }
                                @context = arg.context
                        end
                end

Public Instance methods

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.
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'/>

[Source]

# File rexml/element.rb, line 540
                def add_attribute( key, value=nil )
                        if key.kind_of? Attribute
                                @attributes << key
                        else
                                @attributes[key] = value
                        end
                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"] ] )

[Source]

# File rexml/element.rb, line 552
                def add_attributes hash
                        if hash.kind_of? Hash
                                hash.each_pair {|key, value| @attributes[key] = value }
                        elsif hash.kind_of? Array
                                hash.each { |value| @attributes[ value[0] ] = value[1] }
                        end
                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

[Source]

# File rexml/element.rb, line 256
                def add_element element=nil, attrs=nil
                        el = @elements.add(element)
                        if attrs.kind_of? Hash
                                attrs.each do |key, value|
                                        el.attributes[key]=value if key =~ /^xmlns:/
                                end
                                attrs.each do |key, value|
                                        el.attributes[key]=value if key !~ /^xmlns:/
                                end
                        end
                        el
                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'/>

[Source]

# File rexml/element.rb, line 211
                def add_namespace( prefix, uri=nil )
                        unless uri
                                @attributes["xmlns"] = prefix
                        else
                                prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/
                                @attributes[ prefix ] = uri
                        end
                        self
                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.

[Source]

# File rexml/element.rb, line 488
                def add_text( text )
                        if text.kind_of? String 
                                if @children[-1].kind_of? Text
                                        @children[-1] << text
                                        return
                                end
                                text = Text.new( text, whitespace(), nil, raw() )
                        end
                        self << text unless text.nil?
                        return self
                end

Attributes #

[Source]

# File rexml/element.rb, line 508
                def attribute( name, namespace=nil )
                        prefix = ''
                        if namespace
                                prefix = attributes.prefixes.each { |prefix|
                                        return "#{prefix}:" if namespace( prefix ) == namespace
                                } || ''
                        end
                        attributes.get_attribute( "#{prefix}#{name}" )
                end

Get an array of all CData children. IMMUTABLE

[Source]

# File rexml/element.rb, line 584
                def cdatas
                        find_all { |child| child.kind_of? CData }.freeze
                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/>"

[Source]

# File rexml/element.rb, line 74
                def clone
                        Element.new self
                end

Get an array of all Comment children. IMMUTABLE

[Source]

# File rexml/element.rb, line 590
                def comments
                        find_all { |child| child.kind_of? Comment }.freeze
                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/>

[Source]

# File rexml/element.rb, line 573
                def delete_attribute(key)
                        attr = @attributes.get_attribute(key)
                        attr.remove unless attr.nil?
                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

[Source]

# File rexml/element.rb, line 280
                def delete_element element
                        @elements.delete element
                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/>

[Source]

# File rexml/element.rb, line 231
                def delete_namespace namespace="xmlns"
                        namespace = "xmlns:#{namespace}" unless namespace == 'xmlns'
                        attribute = attributes.get_attribute(namespace)
                        attribute.remove unless attribute.nil?
                        self
                end

Evaluates to the document to which this element belongs, or nil if this element doesn’t belong to a document.

[Source]

# File rexml/element.rb, line 93
                def document
                        root.parent if root
                end

Synonym for Element.elements.each

[Source]

# File rexml/element.rb, line 357
                def each_element( xpath=nil, &block ) # :yields: Element

                        @elements.each( xpath, &block )
                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}

[Source]

# File rexml/element.rb, line 315
                def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element

                        each_with_something( proc {|child| 
                                if value.nil?
                                        child.attributes[key] != nil
                                else
                                        child.attributes[key]==value
                                end
                        }, max, name, &block )
                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 itterate 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}

[Source]

# File rexml/element.rb, line 346
                def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element

                        each_with_something( proc {|child| 
                                if text.nil?
                                        child.has_text?
                                else
                                        child.text == text
                                end
                        }, max, name, &block )
                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

[Source]

# File rexml/element.rb, line 365
                def get_elements( xpath )
                        @elements.to_a( xpath )
                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 "

[Source]

# File rexml/element.rb, line 426
                def get_text path = nil
                        rv = nil
                        if path
                                element = @elements[ path ]
                                rv = element.get_text unless element.nil?
                        else
                                rv = @children.find { |node| node.kind_of? Text }
                        end
                        return rv
                end

Evaluates to true if this element has any attributes set, false otherwise.

[Source]

# File rexml/element.rb, line 520
                def has_attributes?
                        return !@attributes.empty?
                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

[Source]

# File rexml/element.rb, line 289
                def has_elements?
                        !@elements.empty?
                end

Evaluates to true if this element has at least one Text child

[Source]

# File rexml/element.rb, line 397
                def has_text?
                        not text().nil?
                end

[Source]

# File rexml/element.rb, line 122
                def ignore_whitespace_nodes
                        @ignore_whitespace_nodes = false
                        if @context
                                if @context[:ignore_whitespace_nodes]
                                        @ignore_whitespace_nodes = 
                                                (@context[:ignore_whitespace_nodes] == :all or
                                                 @context[:ignore_whitespace_nodes].include? expanded_name)
                                end
                        end
                end

Get an array of all Instruction children. IMMUTABLE

[Source]

# File rexml/element.rb, line 596
                def instructions
                        find_all { |child| child.kind_of? Instruction }.freeze
                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'

[Source]

# File rexml/element.rb, line 183
                def namespace(prefix=nil)
                        if prefix.nil?
                                prefix = prefix()
                        end
                        if prefix == ''
                                prefix = "xmlns"
                        else
                                prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
                        end
                        ns = attributes[ prefix ]
                        ns = parent.namespace(prefix) if ns.nil? and parent
                        ns = '' if ns.nil? and prefix == 'xmlns'
                        return ns
                end

[Source]

# File rexml/element.rb, line 163
                def namespaces
                        namespaces = []
                        namespaces = parent.namespaces if parent
                        namespaces |= attributes.namespaces
                        return namespaces
                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

[Source]

# File rexml/element.rb, line 374
                def next_element
                        element = next_sibling
                        element = element.next_sibling until element.nil? or element.kind_of? Element 
                        return element
                end

[Source]

# File rexml/element.rb, line 500
    def node_type
      :element
    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']

[Source]

# File rexml/element.rb, line 156
                def prefixes
                        prefixes = []
                        prefixes = parent.prefixes if parent
                        prefixes |= attributes.prefixes
                        return prefixes
                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

[Source]

# File rexml/element.rb, line 385
                def previous_element
                        element = previous_sibling
                        element = element.previous_sibling until element.nil? or element.kind_of? Element
                        return element
                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.

[Source]

# File rexml/element.rb, line 139
                def raw
                        @raw = (@context and @context[:raw] and
                        (@context[:raw] == :all or
                        @context[:raw].include? expanded_name))
                        @raw
                end

Evaluates to the root element 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.

 d = Document.new '<a><b><c/></b></a>'
 a = d[1] ; c = a[1][1]
 d.root        # These all evaluate to the same Element,
 a.root        # namely, <a>
 c.root        #

[Source]

# File rexml/element.rb, line 87
                def root
                        parent.nil? ? self : parent.root
                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 "

[Source]

# File rexml/element.rb, line 415
                def text( path = nil )
                        rv = get_text(path)
                        return rv.value unless rv.nil?
                        nil
                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>'

[Source]

# File rexml/element.rb, line 457
                def text=( text )
      if text.kind_of? String
        text = Text.new( text, whitespace(), nil, raw() )
      elsif text and !text.kind_of? Text
        text = Text.new( text.to_s, whitespace(), nil, raw() )
      end
        
                        old_text = get_text
                        if text.nil?
                                old_text.remove unless old_text.nil?
                        else
                                if old_text.nil?
                                        self << text
                                else
                                        old_text.replace_with( text )
                                end
                        end
                        return self
                end

Get an array of all Text children. IMMUTABLE

[Source]

# File rexml/element.rb, line 602
                def texts
                        find_all { |child| child.kind_of? Text }.freeze
                end

Evaluates to true if whitespace is respected for this element. This is the case if:

  1. Neither :respect_whitespace nor :compress_whitespace has any value
  2. The context has :respect_whitespace set to :all or an array containing the name of this element, and :compress_whitespace isn’t set to :all or an array containing the name of this element.

The evaluation is tested against expanded_name, and so is namespace sensitive.

[Source]

# File rexml/element.rb, line 106
                def whitespace
                        @whitespace = nil
                        if @context
                                if @context[:respect_whitespace]
                                        @whitespace = (@context[:respect_whitespace] == :all or
                                                                                                 @context[:respect_whitespace].include? expanded_name)
                                end
                                @whitespace = false if (@context[:compress_whitespace] and
                                        (@context[:compress_whitespace] == :all or
                                         @context[:compress_whitespace].include? expanded_name)
                                )
                        end
                        @whitespace = true unless @whitespace == false
                        @whitespace
                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

[Source]

# File rexml/element.rb, line 628
                def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false)
                        #print "ID:#{indent}"

                        writer << "<#@expanded_name"

                        @attributes.each_attribute do |attr|
                                writer << " "
                                attr.write( writer, indent )
                        end unless @attributes.empty?

                        if @children.empty?
        if transitive and indent>-1
          writer << "\n"
          indent( writer, indent )
        elsif ie_hack
          writer << " " 
        end
                                writer << "/" 
                        else
                                if transitive and indent>-1 and !@children[0].kind_of? Text
                                        writer << "\n"
                                        indent writer, indent+1
                                end
                                writer << ">"
                                write_children( writer, indent, transitive, ie_hack )
                                writer << "</#{expanded_name}"
                        end
                        if transitive and indent>-1 and !@children.empty?
                                writer << "\n"
                                indent -= 1 if next_sibling.nil?
                                indent(writer, indent)
                        end
                        writer << ">"
                end

[Validate]