Module: Lutaml::Xml::TransformationSupport::ElementBuilder

Includes:
ValueSerializer
Included in:
RuleApplier
Defined in:
lib/lutaml/xml/transformation/element_builder.rb

Overview

Module for creating XML elements from values.

Handles:

  • Nested model transformation

  • Polymorphic type resolution

  • Namespace determination

  • Simple value serialization

Instance Method Summary collapse

Methods included from ValueSerializer

#serialize_value

Instance Method Details

#create_element_for_value(rule, value, options, model_class, register_id, register) ⇒ ::Lutaml::Xml::DataModel::XmlElement?

Create an element for a value

Parameters:

  • rule (CompiledRule)

    The rule

  • value (Object)

    The value

  • options (Hash)

    Options including parent context

  • model_class (Class)

    The model class

  • register_id (Symbol, nil)

    The register ID

  • register (Register, nil)

    The register

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/lutaml/xml/transformation/element_builder.rb', line 25

def create_element_for_value(rule, value, options, model_class,
register_id, register)
  # Only treat as nested model when the attribute type is a Serializable
  # class AND the value is not a nil/empty marker from collection handlers.
  # Nil and empty string markers should create simple elements, not attempt
  # nested model transformation.
  is_nested_model = rule.attribute_type.is_a?(Class) &&
    rule.attribute_type < Lutaml::Model::Serialize &&
    !value.nil? &&
    !(value.is_a?(String) && value.empty?)

  if is_nested_model
    create_nested_model_element(rule, value, options, register)
  else
    create_simple_value_element(rule, value, options, model_class,
                                register_id)
  end
end

#determine_element_namespace(rule, parent_namespace_class, parent_element_form_default) ⇒ Class?

Determine element namespace with MECE priority

Priority:

1. Type xml_namespace (explicit type-level namespace)
2. Rule namespace_class (explicit mapping-level namespace)
   - BUT: if parent has element_form_default :unqualified AND
     the namespace is the same as parent's, override to blank
3. Form override unqualified (form: :unqualified forces blank namespace)
4. Parent inheritance (element_form_default: :qualified)
5. Form override qualified (form: :qualified forces namespace inheritance)
6. Blank namespace (no inheritance)

Parameters:

  • rule (CompiledRule)

    The rule

  • parent_namespace_class (Class, nil)

    Parent’s namespace class

  • parent_element_form_default (Symbol, nil)

    Parent’s element_form_default

Returns:

  • (Class, nil)

    The namespace class to use



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/lutaml/xml/transformation/element_builder.rb', line 60

def determine_element_namespace(rule, parent_namespace_class,
parent_element_form_default)
  # Priority 1: Type declares namespace (HIGHEST)
  attr_type = rule.attribute_type
  if attr_type.is_a?(Class) && attr_type <= Lutaml::Model::Type::Value && attr_type.namespace_class
    return attr_type.namespace_class
  end

  # Priority 2: Explicit namespace on mapping rule
  # BUT: if parent has element_form_default :unqualified AND
  # the namespace is the same as parent's, override to blank namespace
  # W3C: elementFormDefault only applies to locally declared elements
  # in the same namespace. Elements from other namespaces are always qualified.
  if rule.namespace_class
    if parent_element_form_default == :unqualified &&
        rule.namespace_class == parent_namespace_class
      # Parent schema says unqualified, and this is the same namespace
      # Override to blank namespace (nil)
      nil
    else
      rule.namespace_class
    end
  elsif rule.form == :unqualified
    # Priority 3: Form override unqualified
    nil
  elsif parent_element_form_default == :qualified && parent_namespace_class
    # Priority 4: Inherit parent's namespace (element_form_default: :qualified)
    # BUT: W3C elementFormDefault only applies to locally declared elements.
    # Children WITHOUT their own namespace declaration should NOT inherit parent's ns.
    # Only inherit if the child model explicitly declares a namespace.
    attr_type = rule.attribute_type
    if attr_type.is_a?(Class) && attr_type.include?(Lutaml::Model::Serialize)
      attr_mapping = attr_type.mappings_for(:xml)
      attr_ns = attr_mapping&.namespace_class
      attr_ns_param = attr_mapping&.send(:namespace_param)
      # Use child's explicit namespace if it differs from parent's
      # If child has no namespace declaration (nil) or explicit blank (:blank),
      # do NOT inherit parent's namespace - return nil
      if attr_ns && attr_ns != parent_namespace_class
        attr_ns
      elsif attr_ns_param.nil? && attr_ns.nil?
        # Child has NO namespace declaration at all - do not apply element_form_default
        nil
      else
        parent_namespace_class
      end
    else
      parent_namespace_class
    end
  elsif rule.form == :qualified && parent_namespace_class
    # Priority 5: Form override qualified
    parent_namespace_class
  end
end