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