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:



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

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.



95
96
97
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 95

def mixed=(value)
  @mixed = value
end

#ordered=(value) ⇒ Object (writeonly)

Sets the attribute ordered

Parameters:

  • value

    the value to set the attribute ordered to.



95
96
97
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 95

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
39
40
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 34

def clear_xml_parse_state!
  @import_declaration_plan = nil
  @pending_plan_root_element = nil
  @element_order = nil
  @attribute_order = 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



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
179
180
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 130

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



255
256
257
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 255

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



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

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

#mixed?Boolean

Returns:

  • (Boolean)


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

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)


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

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



61
62
63
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 61

def original_namespace_uri
  @__xml_original_namespace_uri
end

#original_namespace_uri=(value) ⇒ Object



65
66
67
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 65

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)



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
248
249
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 214

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



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

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



77
78
79
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 77

def raw_schema_location
  @raw_schema_location
end

#raw_schema_location=(value) ⇒ Object



81
82
83
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 81

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:



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

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



69
70
71
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 69

def xml_declaration
  @xml_declaration
end

#xml_declaration=(value) ⇒ Object



73
74
75
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 73

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.



45
46
47
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 45

def xml_namespace_prefix
  @__xml_namespace_prefix
end

#xml_namespace_prefix=(value) ⇒ Object



49
50
51
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 49

def xml_namespace_prefix=(value)
  @__xml_namespace_prefix = value
end

#xml_ns_prefixesObject



53
54
55
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 53

def xml_ns_prefixes
  @__xml_ns_prefixes
end

#xml_ns_prefixes=(value) ⇒ Object



57
58
59
# File 'lib/lutaml/xml/serialization/instance_methods.rb', line 57

def xml_ns_prefixes=(value)
  @__xml_ns_prefixes = value
end