Module: Lutaml::Xml::Serialization::FormatConversion

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

Overview

XML-specific format conversion hooks for Serialize module

This module provides XML-specific serialization logic that extends the format-agnostic Lutaml::Model::Serialize::FormatConversion.

It is prepended into Serialize::ClassMethods when XML format is loaded, overriding the hook methods defined in FormatConversion.

Instance Method Summary collapse

Instance Method Details

#add_format_specific_model_methods(klass) ⇒ Object

Add XML-specific model methods (ordered, mixed, element_order, etc.) when model CustomClass is used with a plain Ruby class.

Parameters:

  • klass (Class)

    The model class



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 205

def add_format_specific_model_methods(klass)
  super
  Lutaml::Model::Utils.add_boolean_accessor_if_not_defined(klass,
                                                           :ordered)
  Lutaml::Model::Utils.add_boolean_accessor_if_not_defined(klass,
                                                           :mixed)
  Lutaml::Model::Utils.add_accessor_if_not_defined(klass,
                                                   :element_order)
  Lutaml::Model::Utils.add_accessor_if_not_defined(klass, :encoding)
  Lutaml::Model::Utils.add_accessor_if_not_defined(klass, :doctype)
  # XML namespace metadata accessors for custom model classes
  %i[xml_namespace_prefix xml_ns_prefixes original_namespace_uri
     xml_declaration raw_schema_location].each do |attr|
    Lutaml::Model::Utils.add_accessor_if_not_defined(klass, attr)
  end
end

#apply_namespace_overrides(options) ⇒ Hash

Apply namespace prefix overrides for XML serialization

Parameters:

  • options (Hash)

    The options hash

Returns:

  • (Hash)

    The modified options hash



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/format_conversion.rb', line 226

def apply_namespace_overrides(options)
  namespaces = options[:namespaces]
  return options unless namespaces.is_a?(Array)

  # Build a namespace URI to prefix mapping
  ns_prefix_map = {}
  namespaces.each do |ns_config|
    if ns_config.is_a?(Hash)
      ns_class = ns_config[:namespace]
      prefix = ns_config[:prefix]

      if ns_class.is_a?(Class) && ns_class < Lutaml::Xml::Namespace && prefix
        ns_prefix_map[ns_class.uri] = prefix.to_s
      end
    end
  end

  unless ns_prefix_map.empty?
    options[:namespace_prefix_map] = ns_prefix_map
  end
  options
end

#choice(min: 1, max: 1, format: :xml) ⇒ Object

Override choice to set format: :xml so Choice knows which format it belongs to.



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

def choice(min: 1, max: 1, format: :xml, &)
  super
end

#namespace(ns_class = nil) ⇒ Class?

Deprecated.

Use namespace inside xml do ... end blocks instead.

Class-level namespace directive for XML.

Parameters:

  • ns_class (Class, nil) (defaults to: nil)

    XmlNamespace class to associate with this model

Returns:

  • (Class, nil)

    the XmlNamespace class



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 20

def namespace(ns_class = nil)
  if ns_class
    unless ns_class.is_a?(Class) && ns_class < Lutaml::Xml::Namespace
      raise ArgumentError,
            "namespace must be an XmlNamespace class, got #{ns_class.class}"
    end

    warn_class_level_namespace_usage(ns_class)
    @namespace_class = ns_class
  end
  @namespace_class
end

#namespace_prefixString?

Get the default namespace prefix for this Model

Returns:

  • (String, nil)

    the namespace prefix



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

def namespace_prefix
  @namespace_class&.prefix_default
end

#namespace_uriString?

Get the namespace URI for this Model

Returns:

  • (String, nil)

    the namespace URI



36
37
38
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 36

def namespace_uri
  @namespace_class&.uri
end

#post_process_mapping(format) ⇒ Object

XML-specific post-processing after mapping DSL evaluation

Parameters:

  • format (Symbol)

    The format



115
116
117
118
119
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 115

def post_process_mapping(format)
  return super unless format == :xml

  check_sort_configs!
end

#pre_deserialize_hook(format, register) ⇒ Object

XML-specific pre-deserialization: resolve XML mapping imports

Parameters:

  • format (Symbol)

    The format

  • register (Symbol)

    The register



125
126
127
128
129
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 125

def pre_deserialize_hook(format, register)
  return super unless format == :xml

  mappings[:xml]&.ensure_mappings_imported!(register)
end

#pre_serialize_hook(format, register) ⇒ Object

XML-specific pre-serialization: resolve XML mapping imports

Parameters:

  • format (Symbol)

    The format

  • register (Symbol)

    The register



195
196
197
198
199
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 195

def pre_serialize_hook(format, register)
  return super unless format == :xml

  mappings[:xml]&.ensure_mappings_imported!(register)
end

#prepare_to_options(format, instance, options) ⇒ Hash

XML-specific options preparation for serialization

Parameters:

  • format (Symbol)

    The format

  • instance (Object)

    The model instance

  • options (Hash)

    The options hash

Returns:

  • (Hash)

    The modified options hash



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
181
182
183
184
185
186
187
188
189
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 155

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

  options[:mapper_class] = self

  # Handle prefix option for XML
  if options.key?(:prefix)
    prefix_option = options[:prefix]
    mappings_for(:xml)

    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

  # Apply namespace prefix overrides for XML format
  if options[:namespaces]
    options = apply_namespace_overrides(options)
  end

  # Retrieve stored declaration plan from model instance for namespace preservation
  if instance.is_a?(Lutaml::Model::Serialize) &&
      !options.key?(:stored_xml_declaration_plan)
    stored_plan = instance.import_declaration_plan
    options[:stored_xml_declaration_plan] = stored_plan if stored_plan
  end

  options
end

#process_mapping(format, *args) ⇒ Object

Override process_mapping for XML format to handle mapping class inheritance.

When xml SomeMapping is called with a mapping class argument, inherits mappings from the class instead of using a DSL block.

Parameters:

  • format (Symbol)

    The format

  • args (Array)

    Additional arguments (mapping class for XML)

  • block (Proc)

    The DSL block



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

def process_mapping(format, *args, &)
  if format == :xml && args.any? && args.first.is_a?(Class) && args.first < Lutaml::Xml::Mapping
    process_xml_mapping_class_inheritance(args.first, &)
  else
    super
  end
end

#validate_document(format, doc, options, register) ⇒ Object

XML-specific document validation: root mapping, encoding, doctype

Parameters:

  • format (Symbol)

    The format

  • doc (Object)

    The parsed document

  • options (Hash)

    Options hash (modified in place)

  • register (Symbol)

    The register

Raises:



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 137

def validate_document(format, doc, options, register)
  return super unless format == :xml

  valid = root?(register) || options[:from_collection]
  raise Lutaml::Model::TypeOnlyMappingError.new(self) unless valid

  options[:encoding] = doc.encoding
  if doc.is_a?(Lutaml::Xml::Document) && doc.doctype
    options[:doctype] = doc.doctype
  end
end

#validate_xml(xml) ⇒ Array<Lutaml::Xml::Error::SchemaValidationError>

Validate a raw XML string against the configured schemas without instantiating a model — the explicit input-side counterpart to the validate/validate! output-side check.

Parameters:

  • xml (String)

    an XML document

Returns:



80
81
82
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 80

def validate_xml(xml)
  XsdValidator.validate(xml, xml_schema_paths)
end

#validate_xml!(xml) ⇒ Object

Raises:



86
87
88
89
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 86

def validate_xml!(xml)
  errors = validate_xml(xml)
  raise Lutaml::Model::ValidationError.new(errors) if errors.any?
end

#validate_xml_with(*paths) ⇒ Object

Configure one or more XSD schemas that the model's generated XML must conform to. Checked during validate/validate! (issue #264). Repeated calls (including in subclasses) append.

Relative paths resolve against the file that declares the macro, so a model works regardless of the process working directory.

Parameters:

  • paths (Array<String, Pathname>)

    paths to XSD schema files



55
56
57
58
59
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 55

def validate_xml_with(*paths)
  base = File.dirname(caller_locations(1, 1).first.path)
  @own_xml_schema_paths = own_xml_schema_paths +
    paths.flatten.map { |path| File.expand_path(path.to_s, base) }
end

#xml_schema_pathsArray<String>

All configured XSD schema paths, parent-first: inherited paths come before paths declared on this class.

Returns:

  • (Array<String>)


65
66
67
68
69
70
71
72
# File 'lib/lutaml/xml/serialization/format_conversion.rb', line 65

def xml_schema_paths
  inherited = if superclass.respond_to?(:xml_schema_paths)
                superclass.xml_schema_paths
              else
                []
              end
  inherited + own_xml_schema_paths
end