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