lib/xommelier/xml/element/serialization.rb in xommelier-0.1.16 vs lib/xommelier/xml/element/serialization.rb in xommelier-0.1.18
- old
+ new
@@ -24,42 +24,41 @@
def ns_element(ns, element)
[ns, element].compact.join(':')
end
- def element_xpath(xmldoc = nil, name = nil)
- ns_element(xmlns_xpath(xmldoc), name || element_name)
+ def element_xpath(xml_doc = nil, name = nil)
+ ns_element(xmlns_xpath(xml_doc), name || element_name)
end
- def xmlns_xpath(xml_document = nil)
- if xml_document
- prefix = xml_document.namespaces.key(xmlns.try(:uri))
+ def xmlns_xpath(xml_doc = nil)
+ if xml_doc
+ prefix = xml_doc.namespaces.key(xmlns.try(:uri))
(prefix =~ /:/) ? prefix[6..-1] : prefix
else
xmlns.as
end
end
end
def from_xml(xml, options = {})
- case xml
- when IO, String
+ if IO === xml || String === xml
xml = Nokogiri::XML(xml)
end
@_xml_node = options.delete(:node) { xml.at_xpath(element_xpath(xml.document, element_name)) }
validate if options[:validate]
if text? && @_xml_node.inner_html.present?
self.text = @_xml_node.inner_html
end
- self.class.attributes.each do |name, options|
- deserialize_attribute(name, options)
+ self.class.attributes.values.each do |attribute|
+ deserialize_attribute(attribute)
end
- self.class.elements.each do |name, options|
- deserialize_element(name, options)
+ self.class.elements.values.each do |element|
+ deserialize_element(element)
end
end
alias_method :from_xommelier, :from_xml
def to_xml(options = {})
@@ -70,11 +69,11 @@
xmlns = options[:ns] || self.xmlns
if options[:builder] # Non-root element
builder = options.delete(:builder)
attribute_values = {}
namespaces = builder.doc.namespaces
- prefix = options[:prefix] || builder.doc.namespaces.key(xmlns.uri)[6..-1].presence
+ prefix = options[:prefix] || namespaces.key(xmlns.uri).try(:[], 6..-1).presence
else # Root element
builder = Nokogiri::XML::Builder.new(options)
attribute_values = children_namespaces.inject({xmlns: xmlns.uri}) do |hash, ns|
hash["xmlns:#{ns.as}"] = ns.uri
hash
@@ -84,29 +83,30 @@
namespaces = attribute_values
prefix = nil
end
current_xmlns = builder.doc.namespaces[prefix ? "xmlns:#{prefix}" : 'xmlns']
attributes.each do |name, value|
- attribute_options = attribute_options(name)
- attribute_name = attribute_options[:attribute_name]
- ns = attribute_options[:ns]
+ attribute = attribute_options(name)
+ attribute_name = attribute.attribute_name
+ ns = attribute.ns
if ns.uri != current_xmlns
if ns.as == :xml
- attribute_name = "xml:#{attribute_options[:attribute_name]}"
- elsif attr_prefix = namespaces.key(ns.uri).try(:[], 6..-1).presence
- attribute_name = "#{attr_prefix}:#{attribute_options[:attribute_name]}"
+ attribute_name = "xml:#{attribute_name}"
+ elsif (attr_prefix = namespaces.key(ns.uri).try(:[], 6..-1).presence)
+ attribute_name = "#{attr_prefix}:#{attribute_name}"
end
end
serialize_attribute(attribute_name, value, attribute_values)
end
@_xml_node = (prefix ? builder[prefix] : builder).
send(element_name, attribute_values) do |xml|
- self.class.elements.each do |name, element_options|
+ self.class.elements.each do |name, element|
value = elements.fetch(name, options[:default])
if value
- serialize_element(name, value, xml,
- element_options.merge(overriden_xmlns: xmlns))
+ element.override(xmlns: xmlns) do
+ serialize_element(name, value, xml, element)
+ end
end
end
xml.text(@text) if respond_to?(:text)
end.instance_variable_get(:@node)
builder.to_xml
@@ -115,11 +115,11 @@
def to_hash
attributes.dup.tap do |hash|
@elements.each do |name, value|
options = element_options(name)
- type = options[:type]
+ type = options.type
value = Array.wrap(value)
if type < Xml::Element
value = value.map(&:to_hash)
end
if value.count > 1
@@ -166,20 +166,20 @@
protected
delegate :ns_element, to: 'self.class'
- def element_xpath(xmldoc = self.xml_document, name = nil)
- self.class.element_xpath(xmldoc, name)
+ def element_xpath(xml_doc = self.xml_document, name = nil)
+ self.class.element_xpath(xml_doc, 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]
- result += attributes.keys.map { |name| attribute_options(name)[:ns] }
- if element_options[:type] < Xml::Element
+ element = self.class.elements[name]
+ result << element.ns
+ result += attributes.keys.map { |attr_name| attribute_options(attr_name).ns }
+ if element.type < Xml::Element
Array(children).each do |child|
result += child.children_namespaces
end
end
result
@@ -196,63 +196,70 @@
def serialize_attribute(name, value, attributes)
attributes[name] = value.to_xommelier
end
- def deserialize_attribute(name, options = nil)
- options ||= self.element_options(name)
- ns = options[:ns]
+ # @param [Xommelier::Xml::Element::Structure::Attribute] attribute
+ def deserialize_attribute(attribute)
+ ns = attribute.ns
if ns.default? || ns == xmlns
- send(name, @_xml_node[options[:attribute_name]])
+ send(attribute.writer, @_xml_node[attribute.attribute_name])
else
- send(name, @_xml_node.attribute_with_ns(options[:attribute_name].to_s, ns.uri.to_s).try(:value))
+ send(attribute.writer, @_xml_node.attribute_with_ns(attribute.attribute_name, ns.uri.to_s).try(:value))
end
end
- def deserialize_element(name, options = nil)
- options ||= self.element_options(name)
- type = options[:type]
- nodes = @_xml_node.xpath("./#{ns_element(options[:ns].as, options[:element_name])}", options[:ns].to_hash)
+ # @param [Xommelier::Xml::Element::Structure::Element] element
+ def deserialize_element(element)
+ nodes = @_xml_node.xpath("./#{ns_element(element.ns.as, element.element_name)}", element.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
+ if element.multiple?
+ children = nodes.map { |node| typecast_element(node, element) }
+ send(element.plural_writer, children)
else
- send(name, typecast_element(type, nodes[0], options))
+ send(element.writer, typecast_element(nodes[0], element))
end
end
end
- def typecast_element(type, node, options)
- if type < Xml::Element
- type.from_xommelier(xml_document, options.merge(node: node))
+ # @param [Nokogiri::XML::Node] node
+ # @param [Xommelier::Xml::Element::Structure::Element] options
+ def typecast_element(node, options)
+ if options.type < Xml::Element
+ options.type.from_xommelier(xml_document, node: node)
else
- type.from_xommelier(node.text)
+ options.type.from_xommelier(node.text)
end
end
- def serialize_element(name, value, xml, options = {})
- case options[:count]
- when :any, :many
- single_element = options.merge(count: :one)
- value.each { |item| serialize_element(name, item, xml, single_element) }
+ # @param [Object] name
+ # @param [Object] value
+ # @param [Object] xml
+ # @param [Xommelier::Xml::Element::Structure::Element] element
+ def serialize_element(name, value, xml, element)
+ if element.multiple?
+ element.override(multiple: false) do
+ value.each do |item|
+ serialize_element(name, item, xml, element)
+ end
+ end
else
- xmlns = options[:overriden_xmlns] || self.xmlns
- prefix = if options[:prefix]
- options[:prefix]
- elsif options[:ns].try(:!=, xmlns)
- xml.doc.namespaces.key(options[:ns].uri)[6..-1].presence
- else
- nil
+ xmlns = element.overridden_xmlns || self.xmlns
+ prefix = if xmlns != element.ns
+ xml.doc.namespaces.key(element.ns.uri)[6..-1].presence
end
case value
when Xommelier::Xml::Element
- value.to_xommelier(builder: xml, element_name: options[:element_name], prefix: prefix, ns: options[:ns])
+ value.to_xommelier(
+ builder: xml,
+ element_name: element.element_name,
+ prefix: prefix,
+ ns: element.ns
+ )
else
- element_name = options[:element_name].to_s
- element_name << '_' if %w(text class id).include?(element_name)
- (prefix ? xml[prefix] : xml).send(element_name) { xml.text(value.to_xommelier) }
+ (prefix ? xml[prefix] : xml).send(element.serializable_element_name) do
+ xml.text(value.to_xommelier)
+ end
end
end
end
end
end