# File lib/happymapper.rb, line 145 def to_xml(parent_node = nil, default_namespace = nil) # # Create a tag that uses the tag name of the class that has no contents # but has the specified namespace or uses the default namespace # current_node = XML::Node.new(self.class.tag_name) if parent_node # # if #to_xml has been called with a parent_node that means this method # is being called recursively (or a special case) and we want to return # the parent_node with the new node as a child # parent_node << current_node else # # If #to_xml has been called without a Node (and namespace) that # means we want to return an xml document # write_out_to_xml = true end # # Add all the registered namespaces to the current node and the current node's # root element. Without adding it to the root element it is not possible to # parse or use xpath to find elements. # if self.class.instance_variable_get('@registered_namespaces') # Given a node, continue moving up to parents until there are no more parents find_root_node = lambda {|node| while node.parent? ; node = node.parent ; end ; node } root_node = find_root_node.call(current_node) # Add the registered namespace to the found root node only if it does not already have one defined self.class.instance_variable_get('@registered_namespaces').each_pair do |prefix,href| XML::Namespace.new(current_node,prefix,href) XML::Namespace.new(root_node,prefix,href) unless root_node.namespaces.find_by_prefix(prefix) end end # # Determine the tag namespace if one has been specified. This value takes # precendence over one that is handed down to composed sub-classes. # tag_namespace = current_node.namespaces.find_by_prefix(self.class.namespace) || default_namespace # Set the namespace of the current node to the specified namespace current_node.namespaces.namespace = tag_namespace if tag_namespace # # Add all the attribute tags to the current node with their namespace, if one # is defined, or the namespace handed down to the node. # self.class.attributes.each do |attribute| attribute_namespace = current_node.namespaces.find_by_prefix(attribute.options[:namespace]) || default_namespace value = send(attribute.method_name) # # If the attribute has a :on_save attribute defined that is a proc or # a defined method, then call those with the current value. # if on_save_operation = attribute.options[:on_save] if on_save_operation.is_a?(Proc) value = on_save_operation.call(value) elsif respond_to?(on_save_operation) value = send(on_save_operation,value) end end current_node[ "#{attribute_namespace ? "#{attribute_namespace.prefix}:" : ""}#{attribute.tag}" ] = value.to_s end # # All all the elements defined (e.g. has_one, has_many, element) ... # self.class.elements.each do |element| tag = element.tag || element.name element_namespace = current_node.namespaces.find_by_prefix(element.options[:namespace]) || tag_namespace value = send(element.name) # # If the element defines an :on_save lambda/proc then we will call that # operation on the specified value. This allows for operations to be # performed to convert the value to a specific value to be saved to the xml. # if on_save_operation = element.options[:on_save] if on_save_operation.is_a?(Proc) value = on_save_operation.call(value) elsif respond_to?(on_save_operation) value = send(on_save_operation,value) end end # # Normally a nil value would be ignored, however if specified then # an empty element will be written to the xml # if value.nil? && element.options[:state_when_nil] current_node << XML::Node.new(tag,nil,element_namespace) end # # To allow for us to treat both groups of items and singular items # equally we wrap the value and treat it as an array. # if value.nil? values = [] elsif value.respond_to?(:to_ary) && !element.options[:single] values = value.to_ary else values = [value] end values.each do |item| if item.is_a?(HappyMapper) # # Other HappyMapper items that are convertable should not be called # with the current node and the namespace defined for the element. # item.to_xml(current_node,element_namespace) elsif item # # When a value exists we should append the value for the tag # current_node << XML::Node.new(tag,item.to_s,element_namespace) else # # Normally a nil value would be ignored, however if specified then # an empty element will be written to the xml # current_node << XML.Node.new(tag,nil,element_namespace) if element.options[:state_when_nil] end end end # # Generate xml from a document if no node was passed as a parameter. Otherwise # this method is being called recursively (or special case) and we should # return the node with this node attached as a child. # if write_out_to_xml document = XML::Document.new document.root = current_node document.to_s else parent_node end end