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.
Construct a new XML element and include it in an existing XMLElement tree.
# File lib/taskjuggler/XMLElement.rb, line 21 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
Add a new child or a set of new childs to the element.
# File lib/taskjuggler/XMLElement.rb, line 69 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 else raise "Elements must be of type XMLElement not #{arg.class}" end self end
Return the value of attribute attribute.
# File lib/taskjuggler/XMLElement.rb, line 103 def [](attribute) @attributes[attribute] end
Add or change attribute to value.
# File lib/taskjuggler/XMLElement.rb, line 96 def []=(attribute, value) raise ArgumentError, "Attribute value #{value} is not a String" unless value.is_a?(String) @attributes[attribute] = value end
Return the element and all sub elements as properly formatted XML.
# File lib/taskjuggler/XMLElement.rb, line 109 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
Escape special characters in input String str.
# File lib/taskjuggler/XMLElement.rb, line 134 def escape(str, quotes = false) out = '' str.each_utf8_char do |c| case c when '&' out << '&' when '"' out << '\"' else out << c end end out end
# File lib/taskjuggler/XMLElement.rb, line 149 def indentation(indent) ' ' * indent end