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