lib/xommelier/xml/element/serialization.rb in xommelier-0.1.1 vs lib/xommelier/xml/element/serialization.rb in xommelier-0.1.2

- old
+ new

@@ -1,7 +1,8 @@ require 'xommelier/xml/element' require 'active_support/concern' +require 'active_support/core_ext/object/blank' require 'nokogiri' module Xommelier module Xml class Element @@ -26,11 +27,12 @@ "#{xmlns_xpath(xmldoc)}:#{name || element_name}" end def xmlns_xpath(xml_document = nil) if xml_document - xml_document.namespaces.key(xmlns.uri) + prefix = xml_document.namespaces.key(xmlns.uri) + (prefix =~ /:/) ? prefix[6..-1] : prefix else xmlns.as end end end @@ -60,35 +62,57 @@ options = SERIALIZATION_OPTIONS.merge(options) element_name = options.delete(:element_name) { self.element_name } if options[:builder] # Non-root element builder = options.delete(:builder) attribute_values = {} + prefix = builder.doc.namespaces.key(xmlns.uri)[6..-1].presence else # Root element builder = Nokogiri::XML::Builder.new(options) - attribute_values = {xmlns: xmlns.to_s} + attribute_values = children_namespaces.inject({xmlns: xmlns.uri}) do |hash, ns| + hash["xmlns:#{ns.as}"] = ns.uri + hash + end + attribute_values.delete("xmlns:#{xmlns.as.to_s}") + prefix = nil end + current_xmlns = builder.doc.namespaces[prefix ? "xmlns:#{prefix}" : 'xmlns'] attributes.each do |name, value| + if (ns = self.class.attributes[name][:ns]).uri != current_xmlns && attr_prefix = builder.doc.namespaces.key(ns.uri).try(:[], 6..-1).presence + name = "#{attr_prefix}:#{name}" + end serialize_attribute(name, value, attribute_values) end - builder.send(element_name, attribute_values) do |xml| - elements.each do |name, value| - serialize_element(name, value, xml) + (prefix ? builder[prefix] : builder). + send(element_name, attribute_values) do |xml| + elements.each do |name, value| + serialize_element(name, value, xml) + end + if respond_to?(:text) + xml.text @text + end end - if respond_to?(:text) - xml.text @text - end - end builder.to_xml end alias_method :to_xommelier, :to_xml protected def element_xpath(xmldoc = self.xml_document, name = nil) self.class.element_xpath(xmldoc, name) end + def children_namespaces(namespaces = Set[xmlns]) + elements.inject(namespaces) do |result, (name, children)| + element_options = self.class.elements[name] + result << element_options[:ns] + if element_options[:type] < Xml::Element + Array(children).each { |child| result += child.children_namespaces } + end + result + end + end + def xml_document @_xml_node.document end def xmlns_xpath(xml_document = self.xml_document) @@ -100,16 +124,11 @@ end def deserialize_element(name, options = nil) options ||= self.element_options(name) type = options[:type] - xpath = if type < Xommelier::Xml::Element - type.element_xpath(xml_document, name) - else - element_xpath(xml_document, name) - end - nodes = @_xml_node.xpath("./#{xpath}") + nodes = @_xml_node.xpath("./#{options[:ns].as}:#{options[:element_name]}", options[:ns].to_hash) if nodes.any? case options[:count] when :any, :many children = nodes.map { |node| typecast_element(type, node, options) } send options[:plural], children @@ -134,12 +153,12 @@ single_element = options.merge(count: :one) value.each { |item| serialize_element(name, item, xml, single_element) } else case value when Xommelier::Xml::Element - value.to_xommelier(builder: xml, element_name: name) + value.to_xommelier(builder: xml, element_name: options[:element_name]) else - xml.send(name) { xml.text value.to_xommelier } + xml.send(options[:element_name]) { xml.text value.to_xommelier } end end end end end