class TaskJuggler::XMLElement

This class models an XML node that may contain other XML nodes. XML element trees can be constructed with the class constructor and converted into XML.

Public Class Methods

new(name, attributes = {}, selfClosing = false) { |block| ... } click to toggle source

Construct a new XML element and include it in an existing XMLElement tree.

# File lib/taskjuggler/XMLElement.rb, line 23
def initialize(name, attributes = {}, selfClosing = false, &block)
  if (name.nil? && attributes.length > 0) ||
     (!name.nil? && !name.is_a?(String))
    raise ArgumentError, "Name must be nil or a String "
  end
  @name = name
  attributes.each do |n, v|
    if n.nil? || v.nil?
      raise ArgumentError,
        "Attribute name (#{n}) or value (#{v}) may not be nil"
    end
    unless v.is_a?(String)
      raise ArgumentError,
        "Attribute value of #{n} must be a String"
    end
  end
  @attributes = attributes
  # This can be set to true if <name /> is legal for this element.
  @selfClosing = selfClosing

  @children = block ? yield(block) : []
  # Allow blocks with single elements not to be Arrays. They will be
  # automatically converted into Arrays here.
  unless @children.is_a?(Array)
    @children = [ @children ]
  else
    @children.flatten!
  end

  # Convert all children that are text String objects into XMLText
  # objects.
  @children.collect! do |c|
    c.is_a?(String) ? XMLText.new(c) : c
  end

  # Make sure we have no nil objects in the list.
  @children.delete_if { |c| c.nil? }

  # Now all children must be XMLElement objects.
  @children.each do |c|
    unless c.is_a?(XMLElement)
      raise ArgumentError,
        "Element must be of type XMLElement, not #{c.class}: #{c.inspect}"
    end
  end
end

Public Instance Methods

<<(arg) click to toggle source

Add a new child or a set of new childs to the element.

# File lib/taskjuggler/XMLElement.rb, line 71
def <<(arg)
  # If the argument is an array, we have to insert each element
  # individually.
  if arg.is_a?(XMLElement)
    @children << arg
  elsif arg.is_a?(String)
    @children << XMLText.new(arg)
  elsif arg.is_a?(Array)
    # Delete all nil entries
    arg.delete_if { |i| i.nil? }
    # Check that the rest are really all XMLElement objects.
    arg.each do |i|
      unless i.is_a?(XMLElement)
        raise ArgumentError,
          "Element must be of type XMLElement, not #{i.class}: #{i.inspect}"
      end
    end
    @children += arg
  elsif arg.nil?
    # Do nothing. Insertions of nil are simply ignored.
  else
    raise "Elements must be of type XMLElement not #{arg.class}"
  end
  self
end
[](attribute) click to toggle source

Return the value of attribute attribute.

# File lib/taskjuggler/XMLElement.rb, line 105
def [](attribute)
  @attributes[attribute]
end
[]=(attribute, value) click to toggle source

Add or change attribute to value.

# File lib/taskjuggler/XMLElement.rb, line 98
def []=(attribute, value)
  raise ArgumentError,
    "Attribute value #{value} is not a String" unless value.is_a?(String)
  @attributes[attribute] = value
end
to_s(indent = 0) click to toggle source

Return the element and all sub elements as properly formatted XML.

# File lib/taskjuggler/XMLElement.rb, line 111
def to_s(indent = 0)
  out = '<' + @name
  @attributes.keys.sort.each do |attrName|
    out << " #{attrName}=\"#{escape(@attributes[attrName], true)}\""
  end
  if @children.empty? && @selfClosing
    out << '/>'
  else
    out << '>'
    @children.each do |child|
      # We only insert newlines for multiple childs and after a tag has been
      # closed.
      if @children.size > 1 && !child.is_a?(XMLText) && out[-1] == ?>
        out << "\n" + indentation(indent + 1)
      end
      out << child.to_s(indent + 1)
    end
    out << "\n" + indentation(indent) if @children.size > 1 && out[-1] == ?>
    out << '</' + @name + '>'
  end
end

Protected Instance Methods

escape(str, quotes = false) click to toggle source

Escape special characters in input String str.

# File lib/taskjuggler/XMLElement.rb, line 136
def escape(str, quotes = false)
  out = ''
  str.each_utf8_char do |c|
    case c
    when '&'
      out << '&amp;'
    when '"'
      out << '\"'
    else
      out << c
    end
  end
  out
end
indentation(indent) click to toggle source
# File lib/taskjuggler/XMLElement.rb, line 151
def indentation(indent)
  ' ' * indent
end