Module: Lutaml::Xml::Serialization::InstanceMethods

Defined in:
lib/lutaml/xml/serialization/instance_methods.rb

Overview

XML-specific instance methods for Serialize.

Prepended into Lutaml::Model::Serialize when XML is loaded. Provides XML-specific instance-level behavior:

  • XML instance attributes (element_order, schema_location, encoding, doctype, ordered, mixed)

  • xml_declaration_plan writer / import_declaration_plan method

  • XML-specific format options preparation

  • XML root mapping validation

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#attribute_orderObject

Returns the value of attribute attribute_order.



19
20
21
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 19

def attribute_order
  @attribute_order
end

#doctypeObject

Returns the value of attribute doctype.



19
20
21
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 19

def doctype
  @doctype
end

#element_orderObject

Returns the value of attribute element_order.



19
20
21
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 19

def element_order
  @element_order
end

#encodingObject

Returns the value of attribute encoding.



19
20
21
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 19

def encoding
  @encoding
end

#import_declaration_planDeclarationPlan?

Build or return the cached declaration plan.

When import_declaration_plan: :lazy (default), builds the plan from the stored element reference on first call. No-op when no pending element exists (:eager already set, :skip, or programmatic creation).

Returns:



90
91
92
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 90

def import_declaration_plan
  @import_declaration_plan ||= build_pending_declaration_plan
end

#mixed=(value) ⇒ Object (writeonly)

Sets the attribute mixed

Parameters:

  • value

    the value to set the attribute mixed to.



93
94
95
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 93

def mixed=(value)
  @mixed = value
end

#ordered=(value) ⇒ Object (writeonly)

Sets the attribute ordered

Parameters:

  • value

    the value to set the attribute ordered to.



93
94
95
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 93

def ordered=(value)
  @ordered = value
end

#pending_plan_root_elementObject

Store root element reference for truly lazy plan building. Set in :lazy mode during deserialization; consumed on first to_xml. Released after plan is built to allow GC of the DOM tree.



25
26
27
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 25

def pending_plan_root_element
  @pending_plan_root_element
end

#schema_locationObject

Returns the value of attribute schema_location.



19
20
21
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 19

def schema_location
  @schema_location
end

Instance Method Details

#clear_xml_parse_state!self

Clear all internal XML parse state on this instance.

Call before re-serializing a previously-parsed instance when the serialization context has changed (e.g. different namespace config, different XML document structure).

Returns:

  • (self)


34
35
36
37
38
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 34

def clear_xml_parse_state!
  @import_declaration_plan = nil
  @pending_plan_root_element = nil
  self
end

#each_mixed_contentself, Enumerator

Iterate over content in document order.

Yields String (text nodes) and Lutaml::Model::Serializable (inline elements). Works for both:

- Mixed content: text + elements interleaved
- Ordered content: elements only, but in specific sequence

Returns self when called with a block, Enumerator when called without.

Examples:

para.each_mixed_content { |item| puts item.inspect }
# For mixed content => "Hello ", #<Emphasis>, "!"
# For ordered only => #<Item "first">, #<Item "second">

Returns:

  • (self, Enumerator)

    self if block given, Enumerator otherwise



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 128

def each_mixed_content
  return to_enum(:each_mixed_content) unless block_given?
  # Only iterate for mixed or ordered content
  return unless element_order && (mixed? || ordered?)

  # Get the XML mapping for this class
  xml_mapping = self.class.mappings_for(:xml, lutaml_register)
  return unless xml_mapping

  # Build lookup: element name -> attribute name
  # @elements maps namespaced names to MappingRule or Array<MappingRule>
  # Note: rule.name is a Symbol but el.name from element_order is a String
  # We store both to handle the mismatch
  element_to_attr = {}
  xml_mapping.mapping_elements_hash.each_value do |rule_or_array|
    Array(rule_or_array).each do |rule|
      element_to_attr[rule.name] = rule.to
      if rule.name.is_a?(Symbol)
        element_to_attr[rule.name.to_s] =
          rule.to
      end
    end
  end

  # Track current index for each collection attribute
  # Using ::Hash to avoid conflict with Lutaml::Model::Hash
  collection_indices = ::Hash.new(0)

  element_order.each do |el|
    if el.text?
      # Text node - yield the text content (skip whitespace-only)
      text = el.text_content
      yield(text) if text && !text.strip.empty?
    elsif el.element?
      # Element node - look up mapped collection and get next item
      attr_name = element_to_attr[el.name]
      next unless attr_name

      collection = send(attr_name)
      next unless collection.is_a?(Array)

      index = collection_indices[attr_name]
      collection_indices[attr_name] += 1

      obj = collection[index]
      yield(obj) if obj
    end
  end

  self
end

#format_element_sequences(register) ⇒ Array?

XML-specific element sequences for validation

Parameters:

  • register (Symbol, nil)

    The register context

Returns:

  • (Array, nil)

    Element sequences from XML mapping



253
254
255
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 253

def format_element_sequences(register)
  self.class.mappings_for(:xml, register)&.element_sequence
end

#initialize(attrs = {}, options = {}) ⇒ Object

Override initialize to extract XML-specific attrs



181
182
183
184
185
186
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 181

def initialize(attrs = {}, options = {})
  super
  set_ordering(attrs)
  set_schema_location(attrs)
  set_doctype(attrs)
end

#mixed?Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
110
111
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 104

def mixed?
  klass = self.class
  if klass.is_a?(Class) && klass.include?(Lutaml::Model::Serialize)
    klass.mappings_for(:xml, lutaml_register)&.mixed_content? || false
  else
    !!@mixed
  end
end

#ordered?Boolean

Returns:

  • (Boolean)


95
96
97
98
99
100
101
102
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 95

def ordered?
  klass = self.class
  if klass.is_a?(Class) && klass.include?(Lutaml::Model::Serialize)
    klass.mappings_for(:xml, lutaml_register)&.ordered? || false
  else
    !!@ordered
  end
end

#original_namespace_uriObject



59
60
61
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 59

def original_namespace_uri
  @__xml_original_namespace_uri
end

#original_namespace_uri=(value) ⇒ Object



63
64
65
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 63

def original_namespace_uri=(value)
  @__xml_original_namespace_uri = value
end

#prepare_instance_format_options(format, options) ⇒ Object

XML-specific instance options preparation

Parameters:

  • format (Symbol)

    The format

  • options (Hash)

    Options hash (modified in place)



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 212

def prepare_instance_format_options(format, options)
  return super unless format == :xml

  # Force eager plan building when adapter is being overridden,
  # to dereference adapter-specific native nodes before the switch.
  if @pending_plan_root_element && options[:_adapter_override]
    import_declaration_plan
  end

  # Handle prefix option (converts to use_prefix for transformation phase)
  if options.key?(:prefix)
    prefix_option = options[:prefix]
    case prefix_option
    when true
      options[:use_prefix] = true
    when String
      options[:use_prefix] = prefix_option
    when false, :default, nil
      options[:use_prefix] = false
    end
    options.delete(:prefix)
  end

  options[:parse_encoding] = encoding if encoding
  options[:doctype] = doctype if doctype

  # Pass XML declaration info for XML Declaration Preservation
  if instance_variable_defined?(:@xml_declaration) && @xml_declaration
    options[:xml_declaration] = @xml_declaration
  end

  # Pass stored DeclarationPlan for format preservation.
  if import_declaration_plan
    options[:stored_xml_declaration_plan] = import_declaration_plan
  end
end

#pretty_print_instance_variablesObject

Extend INTERNAL_ATTRIBUTES with XML-specific ones



189
190
191
192
193
194
195
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 189

def pretty_print_instance_variables
  xml_internals = %i[@import_declaration_plan @pending_plan_root_element
                     @__xml_namespace_prefix
                     @__xml_ns_prefixes @__xml_original_namespace_uri
                     @xml_declaration @raw_schema_location]
  super - xml_internals
end

#raw_schema_locationObject



75
76
77
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 75

def raw_schema_location
  @raw_schema_location
end

#raw_schema_location=(value) ⇒ Object



79
80
81
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 79

def raw_schema_location=(value)
  @raw_schema_location = value
end

#validate_root_mapping!(format, options) ⇒ Object

XML-specific root mapping validation

Parameters:

  • format (Symbol)

    The format

  • options (Hash)

    Options hash

Raises:



201
202
203
204
205
206
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 201

def validate_root_mapping!(format, options)
  return super unless format == :xml
  return if options[:collection] || self.class.root?(lutaml_register)

  raise Lutaml::Model::NoRootMappingError.new(self.class)
end

#xml_declarationObject



67
68
69
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 67

def xml_declaration
  @xml_declaration
end

#xml_declaration=(value) ⇒ Object



71
72
73
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 71

def xml_declaration=(value)
  @xml_declaration = value
end

#xml_namespace_prefixObject

XML namespace metadata for doubly-defined and alias support. These carry information from deserialization to serialization. Accessor methods use the @__ prefixed ivars for backward compatibility.



43
44
45
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 43

def xml_namespace_prefix
  @__xml_namespace_prefix
end

#xml_namespace_prefix=(value) ⇒ Object



47
48
49
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 47

def xml_namespace_prefix=(value)
  @__xml_namespace_prefix = value
end

#xml_ns_prefixesObject



51
52
53
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 51

def xml_ns_prefixes
  @__xml_ns_prefixes
end

#xml_ns_prefixes=(value) ⇒ Object



55
56
57
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 55

def xml_ns_prefixes=(value)
  @__xml_ns_prefixes = value
end