lib/lutaml/model/xml_adapter.rb in lutaml-model-0.2.1 vs lib/lutaml/model/xml_adapter.rb in lutaml-model-0.3.0
- old
+ new
@@ -1,12 +1,15 @@
# lib/lutaml/model/xml_adapter.rb
require_relative "xml_namespace"
+require_relative "mapping_hash"
module Lutaml
module Model
module XmlAdapter
+ XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace".freeze
+
class Document
attr_reader :root
def initialize(root)
@root = root
@@ -31,12 +34,99 @@
declaration += " encoding=\"#{encoding}\"" if encoding
declaration += "?>\n"
declaration
end
- # rubocop:disable Metrics/AbcSize
- # rubocop:disable Metrics/MethodLength
+ def to_h
+ parse_element(@root)
+ end
+
+ def order
+ @root.order
+ end
+
+ def handle_nested_elements(builder, value, rule = nil)
+ options = {}
+
+ if rule&.namespace_set?
+ options[:namespace_prefix] = rule.prefix
+ end
+
+ case value
+ when Array
+ value.each { |val| build_element(builder, val, options) }
+ else
+ build_element(builder, value, options)
+ end
+ end
+
+ def parse_element(element)
+ result = Lutaml::Model::MappingHash.new
+ result.item_order = element.order
+
+ element.children.each_with_object(result) do |child, hash|
+ value = child.text? ? child.text : parse_element(child)
+
+ if hash[child.unprefixed_name]
+ hash[child.unprefixed_name] =
+ [hash[child.unprefixed_name], value].flatten
+ else
+ hash[child.unprefixed_name] = value
+ end
+ end
+
+ element.attributes.each_value do |attr|
+ result[attr.unprefixed_name] = attr.value
+ end
+
+ result
+ end
+
+ def build_element(xml, element, _options = {})
+ if element.ordered?
+ build_ordered_element(xml, element, _options)
+ else
+ build_unordered_element(xml, element, _options)
+ end
+ end
+
+ def build_namespace_attributes(klass, processed = {})
+ xml_mappings = klass.mappings_for(:xml)
+ attributes = klass.attributes
+
+ attrs = {}
+
+ if xml_mappings.namespace_prefix
+ attrs["xmlns:#{xml_mappings.namespace_prefix}"] =
+ xml_mappings.namespace_uri
+ end
+
+ xml_mappings.mappings.each do |mapping_rule|
+ processed[klass] ||= {}
+
+ next if processed[klass][mapping_rule.name]
+
+ processed[klass][mapping_rule.name] = true
+
+ type = if mapping_rule.delegate
+ attributes[mapping_rule.delegate].type.attributes[mapping_rule.to].type
+ else
+ attributes[mapping_rule.to].type
+ end
+
+ if type <= Lutaml::Model::Serialize
+ attrs = attrs.merge(build_namespace_attributes(type, processed))
+ end
+
+ if mapping_rule.namespace
+ attrs["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
+ end
+ end
+
+ attrs
+ end
+
def build_attributes(element, xml_mapping)
attrs = namespace_attributes(xml_mapping)
xml_mapping.attributes.each_with_object(attrs) do |mapping_rule, hash|
if mapping_rule.namespace
@@ -50,13 +140,23 @@
if mapping_rule.namespace
hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
end
end
end
- # rubocop:enable Metrics/AbcSize
- # rubocop:enable Metrics/MethodLength
+ def attribute_definition_for(element, rule)
+ return element.class.attributes[rule.to] unless rule.delegate
+
+ element.send(rule.delegate).class.attributes[rule.to]
+ end
+
+ def attribute_value_for(element, rule)
+ return element.send(rule.to) unless rule.delegate
+
+ element.send(rule.delegate).send(rule.to)
+ end
+
def namespace_attributes(xml_mapping)
return {} unless xml_mapping.namespace_uri
key = ["xmlns", xml_mapping.namespace_prefix].compact.join(":")
{ key => xml_mapping.namespace_uri }
@@ -68,11 +168,10 @@
:children,
:text,
:namespace_prefix,
:parent_document
- # rubocop:disable Metrics/ParameterLists
def initialize(
name,
attributes = {},
children = [],
text = nil,
@@ -84,14 +183,13 @@
@attributes = attributes # .map { |k, v| Attribute.new(k, v) }
@children = children
@text = text
@parent_document = parent_document
end
- # rubocop:enable Metrics/ParameterLists
def name
- if namespace_prefix && namespaces[namespace_prefix]
+ if namespace_prefix
"#{namespace_prefix}:#{@name}"
else
@name
end
end
@@ -142,19 +240,33 @@
n = name.to_s.split(":")
return if n.length <= 1
n.first
end
+
+ def order
+ children.each_with_object([]) do |child, arr|
+ arr << child.unprefixed_name
+ end
+ end
end
class Attribute
attr_reader :name, :value, :namespace, :namespace_prefix
def initialize(name, value, namespace: nil, namespace_prefix: nil)
@name = name
@value = value
@namespace = namespace
@namespace_prefix = namespace_prefix
+ end
+
+ def unprefixed_name
+ if namespace_prefix
+ name.split(":").last
+ else
+ name
+ end
end
end
end
end
end