Module: Lutaml::Xml::Adapter::XmlSerializer

Included in:
BaseAdapter
Defined in:
lib/lutaml/xml/adapter/xml_serializer.rb

Overview

Handles the XML serialization pipeline.

Responsible for converting model instances and XmlElement trees into XML output via builder objects. Includes the top-level ‘to_xml` entry point and supporting methods for rendering XmlElement structures with namespace declaration plans.

Instance Method Summary collapse

Instance Method Details

#add_value(xml, value, attribute, cdata: false) ⇒ Object

Add text content to XML builder

Parameters:

  • xml (Builder)

    the XML builder

  • value (Object)

    the value to add

  • attribute (Attribute, nil)

    the attribute definition

  • cdata (Boolean) (defaults to: false)

    whether to use CDATA



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/lutaml/xml/adapter/xml_serializer.rb', line 19

def add_value(xml, value, attribute, cdata: false)
  if !value.nil?
    if attribute.nil?
      # For delegated attributes where attribute is nil, just use the raw value
      xml.add_text(xml, value.to_s, cdata: cdata)
    elsif attribute.transform.is_a?(Class) && attribute.transform < Lutaml::Model::ValueTransformer
      # Value has already been transformed, use it directly
      xml.add_text(xml, value.to_s, cdata: cdata)
    else
      # Normal serialization through attribute type system
      serialized_value = attribute.serialize(value, :xml, register)
      if attribute.raw?
        xml.add_xml_fragment(xml, value)
      elsif serialized_value.is_a?(Hash)
        serialized_value.each do |key, val|
          xml.create_and_add_element(key) do |element|
            element.text(val)
          end
        end
      else
        xml.add_text(xml, serialized_value, cdata: cdata)
      end
    end
  end
end

#build_serializable_xml(xml, options) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/lutaml/xml/adapter/xml_serializer.rb', line 93

def build_serializable_xml(xml, options)
  original_model = nil
  xml_element = transformable_xml_element(options) do |model|
    original_model = model
  end

  if xml_element
    render_xml_element(xml, xml_element, original_model, options)
  else
    render_legacy_model(xml, options)
  end
end

#build_xml_element_with_plan(builder, xml_element, plan, options = {}) ⇒ Object

Build XML from XmlDataModel::XmlElement structure with a declaration plan

Parameters:

  • builder (Builder)

    XML builder

  • xml_element (XmlDataModel::XmlElement)

    root element

  • plan (DeclarationPlan)

    the declaration plan

  • options (Hash) (defaults to: {})

    serialization options



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/lutaml/xml/adapter/xml_serializer.rb', line 112

def build_xml_element_with_plan(builder, xml_element, plan,
    options = {})
  # Add processing instructions before the root element
  if xml_element.is_a?(Lutaml::Xml::DataModel::XmlElement)
    xml_element.processing_instructions.each do |pi|
      builder.add_processing_instruction(pi.target, pi.content)
    end
  end

  build_plan_node(builder, xml_element, plan.root_node, plan: plan,
                                                        options: options)
end

#to_xml(options = {}) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
# File 'lib/lutaml/xml/adapter/xml_serializer.rb', line 45

def to_xml(options = {})
  # Accept xml_declaration from options if present (for model serialization)
  @xml_declaration = options[:xml_declaration] if options[:xml_declaration]

  encoding = determine_encoding(options)
  builder_options = {}
  builder_options[:encoding] = encoding if encoding
  builder_options[:line_ending] = options[:line_ending] if options.key?(:line_ending)
  builder_options[:indent] = options[:indent] if options.key?(:indent)

  # Pass doctype to builder for document-level insertion
  doctype_to_use = options[:doctype] || @doctype
  if doctype_to_use && !options[:omit_doctype]
    builder_options[:doctype] = doctype_to_use
  end

  # Pass declaration info to builder
  if should_include_declaration?(options)
    builder_options[:include_declaration] = true
    builder_options[:xml_declaration] = @xml_declaration || {}
    if options.key?(:standalone)
      if options[:standalone] == :preserve
        # Keep original standalone from parsed declaration (may be nil)
      else
        builder_options[:xml_declaration][:standalone] = standalone_value(options[:standalone])
      end
    end
    if options[:declaration].is_a?(String)
      builder_options[:xml_declaration][:version] = options[:declaration]
    elsif options[:declaration] == true
      builder_options[:xml_declaration][:version] = "1.0"
    end
    builder_options[:xml_declaration][:encoding] = encoding if options.key?(:encoding) && encoding
  elsif options[:encoding] && !options[:encoding].nil?
    builder_options[:force_declaration] = true
  end

  builder = self.class::BUILDER_CLASS.build(builder_options) do |xml|
    if root.is_a?(self.class::PARSED_ELEMENT_CLASS)
      root.build_xml(xml)
    else
      build_serializable_xml(xml, options)
    end
  end

  builder.to_xml
end