lutaml-model 0.8.14 → 0.8.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +14 -73
  3. data/Gemfile +3 -5
  4. data/README.adoc +188 -25
  5. data/docs/_guides/xml-mapping.adoc +178 -24
  6. data/docs/_pages/importable_models.adoc +7 -1
  7. data/lib/lutaml/jsonld/transform.rb +44 -13
  8. data/lib/lutaml/model/attribute.rb +4 -0
  9. data/lib/lutaml/model/liquefiable.rb +9 -0
  10. data/lib/lutaml/model/liquid/indexed_access.rb +33 -0
  11. data/lib/lutaml/model/liquid.rb +1 -0
  12. data/lib/lutaml/model/version.rb +1 -1
  13. data/lib/lutaml/model.rb +2 -1
  14. data/lib/lutaml/rdf/mapping.rb +10 -1
  15. data/lib/lutaml/rdf/member_rule.rb +29 -4
  16. data/lib/lutaml/turtle/transform.rb +55 -35
  17. data/lib/lutaml/xml/adapter/plan_based_builder.rb +3 -1
  18. data/lib/lutaml/xml/adapter/xml_serializer.rb +15 -5
  19. data/lib/lutaml/xml/adapter.rb +2 -1
  20. data/lib/lutaml/xml/builder/base.rb +2 -1
  21. data/lib/lutaml/xml/data_model.rb +19 -3
  22. data/lib/lutaml/xml/mapping.rb +3 -1
  23. data/lib/lutaml/xml/mapping_rule.rb +28 -2
  24. data/lib/lutaml/xml/model_transform.rb +9 -1
  25. data/lib/lutaml/xml/serialization/instance_methods.rb +16 -9
  26. data/lib/lutaml/xml/transformation/element_builder.rb +1 -3
  27. data/lib/lutaml/xml/transformation/rule_applier.rb +21 -0
  28. data/lib/lutaml/xml/transformation/rule_compiler.rb +12 -3
  29. data/lutaml-model.gemspec +1 -1
  30. data/spec/lutaml/jsonld/transform_spec.rb +149 -0
  31. data/spec/lutaml/model/liquid/indexed_access_spec.rb +135 -0
  32. data/spec/lutaml/model/mixed_content_spec.rb +48 -7
  33. data/spec/lutaml/model/raw_element_spec.rb +533 -0
  34. data/spec/lutaml/rdf/mapping_spec.rb +71 -6
  35. data/spec/lutaml/rdf/member_rule_spec.rb +103 -1
  36. data/spec/lutaml/turtle/transform_spec.rb +144 -0
  37. metadata +9 -6
@@ -10,7 +10,7 @@ module Lutaml
10
10
  mapping = extract_turtle_mapping(options)
11
11
  return "" unless mapping
12
12
 
13
- if !mapping.rdf_subject && mapping.rdf_predicates.any? && mapping.rdf_members.empty?
13
+ if !mapping.rdf_subject && mapping.has_types_or_predicates? && mapping.rdf_members.empty?
14
14
  raise MissingSubjectError,
15
15
  "Turtle mapping requires a subject block"
16
16
  end
@@ -18,7 +18,7 @@ module Lutaml
18
18
  graph = build_graph(mapping, instance)
19
19
  return "" if graph.empty?
20
20
 
21
- prefixes = build_prefixes(mapping, instance)
21
+ prefixes = collect_all_prefixes(mapping, instance)
22
22
  RDF::Turtle::Writer.buffer(prefixes: prefixes) do |writer|
23
23
  graph.each_statement { |stmt| writer << stmt }
24
24
  end.strip
@@ -37,6 +37,12 @@ module Lutaml
37
37
  build_instance(attrs, options)
38
38
  end
39
39
 
40
+ protected
41
+
42
+ def additional_resource_triples(_instance, _subject_uri, _mapping)
43
+ []
44
+ end
45
+
40
46
  private
41
47
 
42
48
  def extract_turtle_mapping(options)
@@ -47,63 +53,70 @@ module Lutaml
47
53
  graph = RDF::Graph.new
48
54
 
49
55
  has_resource_data =
50
- mapping.rdf_type.any? ||
51
- mapping.rdf_predicates.any? ||
56
+ mapping.has_types_or_predicates? ||
52
57
  mapping.rdf_members.any?(&:linked?)
53
58
 
54
59
  if has_resource_data
55
- subject_uri = resolve_subject(mapping, instance)
56
- build_resource_triples(graph, mapping, instance, subject_uri)
60
+ subject_uri = if mapping.rdf_subject
61
+ RDF::URI(resolve_subject_uri(mapping, instance))
62
+ else
63
+ RDF::Node.new
64
+ end
65
+
66
+ emit_type_statements(graph, subject_uri, mapping)
67
+ emit_predicate_statements(graph, subject_uri, instance, mapping)
68
+ emit_member_link_statements(graph, subject_uri, instance, mapping)
69
+ additional_resource_triples(instance, subject_uri,
70
+ mapping).each do |stmt|
71
+ graph << stmt
72
+ end
57
73
  end
58
74
 
59
- build_member_subgraphs(graph, mapping, instance)
75
+ emit_child_resources(graph, instance, mapping)
60
76
 
61
77
  graph
62
78
  end
63
79
 
64
- def resolve_subject(mapping, instance)
65
- if mapping.rdf_subject
66
- RDF::URI(resolve_subject_uri(mapping, instance))
67
- else
68
- RDF::Node.new
69
- end
70
- end
71
-
72
- def build_resource_triples(graph, mapping, instance, subject_uri)
80
+ def emit_type_statements(graph, subject_uri, mapping)
73
81
  mapping.rdf_type.each do |type_value|
74
82
  type_uri = RDF::URI(resolve_single_type_uri(mapping, type_value))
75
83
  graph << RDF::Statement.new(subject_uri, RDF.type, type_uri)
76
84
  end
85
+ end
77
86
 
87
+ def emit_predicate_statements(graph, subject_uri, instance, mapping)
78
88
  mapping.rdf_predicates.each do |rule|
79
89
  value = instance.public_send(rule.to)
80
90
  next if value.nil?
81
91
 
82
92
  Array(value).each do |v|
93
+ next if v.is_a?(String) && v.empty?
94
+
83
95
  object = build_rdf_object(v, rule, mapping.namespace_set)
84
96
  graph << RDF::Statement.new(subject_uri, RDF::URI(rule.uri), object)
85
97
  end
86
98
  end
99
+ end
87
100
 
101
+ def emit_member_link_statements(graph, subject_uri, instance, mapping)
88
102
  mapping.rdf_members.each do |member_rule|
89
103
  next unless member_rule.linked?
90
104
 
91
105
  each_member(instance, member_rule) do |member|
92
106
  member_mapping = member_mapping_for(member, :turtle)
93
- next unless member_mapping
107
+ next unless member_mapping&.rdf_subject
108
+
109
+ child_uri = RDF::URI(resolve_subject_uri(member_mapping, member))
110
+ resolver = mapping.namespace_set.method(:resolve_compact_iri)
111
+ link_uri = RDF::URI(member_rule.resolve_link_uri(member, resolver))
112
+ next unless link_uri
94
113
 
95
- member_subject = RDF::URI(resolve_subject_uri(member_mapping,
96
- member))
97
- graph << RDF::Statement.new(
98
- subject_uri,
99
- RDF::URI(member_rule.linked_predicate_uri),
100
- member_subject,
101
- )
114
+ graph << RDF::Statement.new(subject_uri, link_uri, child_uri)
102
115
  end
103
116
  end
104
117
  end
105
118
 
106
- def build_member_subgraphs(graph, mapping, instance)
119
+ def emit_child_resources(graph, instance, mapping)
107
120
  mapping.rdf_members.each do |member_rule|
108
121
  each_member(instance, member_rule) do |member|
109
122
  member_mapping = member_mapping_for(member, :turtle)
@@ -144,7 +157,14 @@ module Lutaml
144
157
  end
145
158
  end
146
159
 
147
- def build_prefixes(mapping, instance)
160
+ def collect_all_prefixes(mapping, instance)
161
+ ns_set = collect_namespaces_recursive(mapping, instance)
162
+ ns_set.each.with_object({}) do |ns, h|
163
+ h[ns.prefix.to_sym] = ns.uri if ns.prefix && ns.uri
164
+ end
165
+ end
166
+
167
+ def collect_namespaces_recursive(mapping, instance)
148
168
  ns_set = mapping.namespace_set
149
169
 
150
170
  mapping.rdf_members.each do |member_rule|
@@ -153,12 +173,12 @@ module Lutaml
153
173
  next unless member_mapping
154
174
 
155
175
  ns_set = ns_set.merge(member_mapping.namespace_set)
176
+ child_ns = collect_namespaces_recursive(member_mapping, member)
177
+ ns_set = ns_set.merge(child_ns)
156
178
  end
157
179
  end
158
180
 
159
- ns_set.each.with_object({}) do |ns, h|
160
- h[ns.prefix.to_sym] = ns.uri if ns.prefix && ns.uri
161
- end
181
+ ns_set
162
182
  end
163
183
 
164
184
  def extract_attributes(graph, mapping)
@@ -175,6 +195,12 @@ module Lutaml
175
195
  attrs
176
196
  end
177
197
 
198
+ def find_subjects_by_types(graph, type_uris)
199
+ type_uris.flat_map do |type_uri|
200
+ graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
201
+ end.uniq
202
+ end
203
+
178
204
  def extract_predicate_attributes(graph, subject, mapping, attrs)
179
205
  mapping.rdf_predicates.each do |rule|
180
206
  stmts = graph.query([subject, RDF::URI(rule.uri), nil])
@@ -187,12 +213,6 @@ module Lutaml
187
213
  end
188
214
  end
189
215
 
190
- def find_subjects_by_types(graph, type_uris)
191
- type_uris.flat_map do |type_uri|
192
- graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
193
- end.uniq
194
- end
195
-
196
216
  def literal_to_ruby(rdf_object, rule, namespace_set)
197
217
  case rdf_object
198
218
  when RDF::URI
@@ -332,6 +332,8 @@ module Lutaml
332
332
  xml_mapping: xml_mapping)
333
333
  when Lutaml::Xml::DataModel::XmlComment
334
334
  inner_xml.add_comment(child.content)
335
+ when Lutaml::Xml::DataModel::XmlRawFragment
336
+ inner_xml.add_xml_fragment(inner_xml, child.content)
335
337
  when String
336
338
  if element.cdata
337
339
  inner_xml.cdata(child.to_s)
@@ -764,7 +766,7 @@ module Lutaml
764
766
  xml.create_and_add_element(rule.name,
765
767
  attributes: attributes.empty? ? nil : attributes,
766
768
  prefix: resolved_prefix)
767
- elsif rule.raw_mapping?
769
+ elsif rule.raw_mapping? || rule.raw == :element
768
770
  xml.add_xml_fragment(xml, value)
769
771
  elsif value.is_a?(::Hash) && attribute&.type(register) == Lutaml::Model::Type::Hash
770
772
  xml.create_and_add_element(rule.name,
@@ -49,7 +49,10 @@ module Lutaml
49
49
  encoding = determine_encoding(options)
50
50
  builder_options = {}
51
51
  builder_options[:encoding] = encoding if encoding
52
- builder_options[:line_ending] = options[:line_ending] if options.key?(:line_ending)
52
+ if options.key?(:line_ending)
53
+ builder_options[:line_ending] =
54
+ options[:line_ending]
55
+ end
53
56
  builder_options[:indent] = options[:indent] if options.key?(:indent)
54
57
 
55
58
  # Pass doctype to builder for document-level insertion
@@ -66,15 +69,20 @@ module Lutaml
66
69
  if options[:standalone] == :preserve
67
70
  # Keep original standalone from parsed declaration (may be nil)
68
71
  else
69
- builder_options[:xml_declaration][:standalone] = standalone_value(options[:standalone])
72
+ builder_options[:xml_declaration][:standalone] =
73
+ standalone_value(options[:standalone])
70
74
  end
71
75
  end
72
76
  if options[:declaration].is_a?(String)
73
- builder_options[:xml_declaration][:version] = options[:declaration]
77
+ builder_options[:xml_declaration][:version] =
78
+ options[:declaration]
74
79
  elsif options[:declaration] == true
75
80
  builder_options[:xml_declaration][:version] = "1.0"
76
81
  end
77
- builder_options[:xml_declaration][:encoding] = encoding if options.key?(:encoding) && encoding
82
+ if options.key?(:encoding) && encoding
83
+ builder_options[:xml_declaration][:encoding] =
84
+ encoding
85
+ end
78
86
  elsif options[:encoding] && !options[:encoding].nil?
79
87
  builder_options[:force_declaration] = true
80
88
  end
@@ -221,7 +229,7 @@ module Lutaml
221
229
  end
222
230
 
223
231
  def text_content_for_xml(value)
224
- ::Moxml::Adapter::Base.preprocess_entities(value.to_s)
232
+ ::Moxml.preprocess_entities(value.to_s)
225
233
  end
226
234
 
227
235
  def build_plan_node(xml, xml_element, element_node, plan: nil,
@@ -287,6 +295,8 @@ module Lutaml
287
295
  previous_child_had_xmlns_blank ||= child_node.needs_xmlns_blank
288
296
  when Lutaml::Xml::DataModel::XmlComment
289
297
  xml.add_comment(xml_child.content)
298
+ when Lutaml::Xml::DataModel::XmlRawFragment
299
+ xml.add_xml_fragment(xml, xml_child.content)
290
300
  when String
291
301
  if xml_element.cdata
292
302
  xml.cdata(xml_child.to_s)
@@ -10,7 +10,8 @@ module Lutaml
10
10
  autoload :XmlParser, "#{__dir__}/adapter/xml_parser"
11
11
  autoload :XmlSerializer, "#{__dir__}/adapter/xml_serializer"
12
12
  autoload :PlanBasedBuilder, "#{__dir__}/adapter/plan_based_builder"
13
- autoload :NamespaceUriCollector, "#{__dir__}/adapter/namespace_uri_collector"
13
+ autoload :NamespaceUriCollector,
14
+ "#{__dir__}/adapter/namespace_uri_collector"
14
15
  autoload :OgaAdapter, "#{__dir__}/adapter/oga_adapter"
15
16
  Lutaml::Model::RuntimeCompatibility.autoload_native(
16
17
  self,
@@ -172,7 +172,8 @@ module Lutaml
172
172
  result = if @declaration_mode == :none && !has_document_level_nodes?
173
173
  @doc.root.to_xml(declaration: false, expand_empty: false)
174
174
  else
175
- @doc.to_xml(declaration: @declaration_mode == :default, expand_empty: false)
175
+ @doc.to_xml(declaration: @declaration_mode == :default,
176
+ expand_empty: false)
176
177
  end
177
178
 
178
179
  result = result.encode(encoding) if encoding && result.encoding.to_s != encoding
@@ -87,10 +87,10 @@ module Lutaml
87
87
  # @raise [TypeError] if child is not a supported type
88
88
  def add_child(child)
89
89
  unless child.is_a?(XmlElement) || child.is_a?(String) ||
90
- child.is_a?(XmlComment)
90
+ child.is_a?(XmlComment) || child.is_a?(XmlRawFragment)
91
91
  raise TypeError,
92
- "XmlElement#add_child expects XmlElement, String, or " \
93
- "XmlComment, got #{child.class}"
92
+ "XmlElement#add_child expects XmlElement, String, " \
93
+ "XmlComment, or XmlRawFragment, got #{child.class}"
94
94
  end
95
95
 
96
96
  @children << child
@@ -261,6 +261,22 @@ module Lutaml
261
261
  end
262
262
  end
263
263
 
264
+ # Represents a raw XML fragment that should be serialized as-is.
265
+ #
266
+ # Used by raw_element mappings to embed complete XML elements (e.g., SVG,
267
+ # MathML) without parsing, wrapping, or escaping.
268
+ class XmlRawFragment
269
+ attr_reader :content
270
+
271
+ def initialize(content)
272
+ @content = content.to_s
273
+ end
274
+
275
+ def to_s
276
+ @content
277
+ end
278
+ end
279
+
264
280
  # Represents an XML comment in the data model tree.
265
281
  # Stored as a child of XmlElement alongside String (text) and XmlElement children.
266
282
  class XmlComment
@@ -510,7 +510,8 @@ module Lutaml
510
510
  form: nil,
511
511
  documentation: nil,
512
512
  xsd_type: (xsd_type_provided = false
513
- nil)
513
+ nil),
514
+ raw: nil
514
515
  )
515
516
  validate!(
516
517
  name, to, with, render_nil, render_empty, type: TYPES[:element]
@@ -562,6 +563,7 @@ module Lutaml
562
563
  value_map: value_map,
563
564
  form: form,
564
565
  documentation: documentation,
566
+ raw: raw,
565
567
  )
566
568
  # Store rules with the same element name in an array to support
567
569
  # multiple mapping rules for the same element name with different target types
@@ -10,7 +10,8 @@ module Lutaml
10
10
  :as_list,
11
11
  :delimiter,
12
12
  :form,
13
- :documentation
13
+ :documentation,
14
+ :raw
14
15
 
15
16
  # Writers for deep_dup (preserves exact object references)
16
17
  attr_accessor :namespace, :prefix, :namespace_class
@@ -39,7 +40,8 @@ module Lutaml
39
40
  as_list: nil,
40
41
  delimiter: nil,
41
42
  form: nil,
42
- documentation: nil
43
+ documentation: nil,
44
+ raw: nil
43
45
  )
44
46
  super(
45
47
  name,
@@ -76,6 +78,7 @@ module Lutaml
76
78
  @delimiter = delimiter
77
79
  @form = validate_form(form)
78
80
  @documentation = documentation
81
+ @raw = validate_raw(raw)
79
82
 
80
83
  # Memoize prefixed_name at initialization for performance
81
84
  # This is safe because prefix and name are immutable after initialization
@@ -103,6 +106,10 @@ module Lutaml
103
106
  @static_namespace_option ||= { default_namespace: namespace }.freeze
104
107
  end
105
108
 
109
+ def raw_element?
110
+ @raw == :element
111
+ end
112
+
106
113
  def content_mapping?
107
114
  name.nil?
108
115
  end
@@ -225,6 +232,7 @@ module Lutaml
225
232
  delimiter: @delimiter,
226
233
  form: @form,
227
234
  documentation: @documentation,
235
+ raw: @raw,
228
236
  ).tap do |dup_rule|
229
237
  # Manually preserve the exact @namespace_class object to avoid
230
238
  # recreating anonymous classes (which would have different object_ids)
@@ -573,6 +581,24 @@ form_default = :unqualified)
573
581
 
574
582
  form
575
583
  end
584
+
585
+ def validate_raw(raw)
586
+ return nil if raw.nil? || raw == false
587
+
588
+ valid_raw = %i[element content]
589
+ if raw == true
590
+ warn "[DEPRECATED] raw: true on map_element is deprecated, " \
591
+ "use raw: :element instead."
592
+ return :element
593
+ end
594
+
595
+ unless valid_raw.include?(raw)
596
+ raise ArgumentError,
597
+ "raw must be :element or :content, got #{raw.inspect}"
598
+ end
599
+
600
+ raw
601
+ end
576
602
  end
577
603
  end
578
604
  end
@@ -668,6 +668,12 @@ _effective_register)
668
668
  !child_ns_prefix && rule_names.any? do |rn|
669
669
  ((colon = rn.rindex(":")) ? rn[(colon + 1)..] : rn) == child.unprefixed_name
670
670
  end
671
+ elsif !rule_namespace_set && (!child_ns_prefix || rule.raw == :element)
672
+ # For simple types (String, etc.) with no namespace constraint,
673
+ # match by unprefixed name. Handles elements in foreign namespaces
674
+ # (e.g., SVG inside <image>). raw_element rules match regardless
675
+ # of prefix — the intent is to capture any element with that name.
676
+ child.unprefixed_name == rule_name_str
671
677
  else
672
678
  false
673
679
  end
@@ -765,7 +771,9 @@ _effective_register)
765
771
  end
766
772
 
767
773
  values << cast_result
768
- elsif attr.raw?
774
+ elsif rule.raw == :element
775
+ values << child.to_xml
776
+ elsif rule.raw == :content || attr.raw?
769
777
  values << inner_xml_of(child)
770
778
  else
771
779
  return nil if rule.render_nil_as_nil? && child.nil_element?
@@ -155,23 +155,30 @@ module Lutaml
155
155
  # Using ::Hash to avoid conflict with Lutaml::Model::Hash
156
156
  collection_indices = ::Hash.new(0)
157
157
 
158
+ content_is_mixed = mixed?
159
+
158
160
  element_order.each do |el|
159
161
  if el.text?
160
- # Text node - yield the text content (skip whitespace-only)
161
162
  text = el.text_content
162
- yield(text) if text && !text.strip.empty?
163
+ if text && !text.empty? && (content_is_mixed || !text.strip.empty?)
164
+ # Mixed content: all text is significant (e.g. "Hello " before <b>)
165
+ # Ordered-only: skip whitespace-only text (indentation between elements)
166
+ yield(text)
167
+ end
163
168
  elsif el.element?
164
169
  # Element node - look up mapped collection and get next item
165
170
  attr_name = element_to_attr[el.name]
166
171
  next unless attr_name
167
172
 
168
- collection = send(attr_name)
169
- next unless collection.is_a?(Array)
170
-
171
- index = collection_indices[attr_name]
172
- collection_indices[attr_name] += 1
173
-
174
- obj = collection[index]
173
+ val = send(attr_name)
174
+ obj = if val.is_a?(Array)
175
+ index = collection_indices[attr_name]
176
+ collection_indices[attr_name] += 1
177
+ val[index]
178
+ elsif val.is_a?(Lutaml::Model::Serializable)
179
+ collection_indices[attr_name] += 1
180
+ collection_indices[attr_name] == 1 ? val : nil
181
+ end
175
182
  yield(obj) if obj
176
183
  end
177
184
  end
@@ -112,8 +112,6 @@ parent_element_form_default)
112
112
  end
113
113
  end
114
114
 
115
- private
116
-
117
115
  # Create element for nested model
118
116
  #
119
117
  # @param rule [CompiledRule] The rule
@@ -212,7 +210,7 @@ child_transformation)
212
210
  # with different URIs) -> child has its own ns, use child's prefix_default
213
211
  # - Child's namespace is self-declared through its attribute TYPE (different from parent)
214
212
  # -> child's XmlElement gets its own ns, use child's prefix_default
215
- child_ns_class = if value.class.respond_to?(:mappings_for)
213
+ child_ns_class = if value.is_a?(::Lutaml::Model::Serialize)
216
214
  value.class.mappings_for(:xml)&.namespace_class
217
215
  end
218
216
  ns_prefix = nil
@@ -84,6 +84,12 @@ register_id, register)
84
84
  return
85
85
  end
86
86
 
87
+ # raw: :element — value is a complete XML element string, inject directly
88
+ if rule.raw == :element
89
+ add_raw_element_fragments(parent, value)
90
+ return
91
+ end
92
+
87
93
  # Extract parent's namespace info for element_form_default inheritance
88
94
  parent_ns_class = parent.namespace_class
89
95
  # Only pass element_form_default VALUE if it was explicitly set
@@ -201,6 +207,21 @@ register_id)
201
207
 
202
208
  private
203
209
 
210
+ # Add raw element fragments to parent, handling single values and collections.
211
+ #
212
+ # @param parent [XmlElement] Parent element
213
+ # @param value [Object, Array] Raw XML string(s)
214
+ def add_raw_element_fragments(parent, value)
215
+ return if value.nil?
216
+
217
+ items = value.is_a?(Array) ? value : [value]
218
+ items.each do |item|
219
+ next if item.nil? || item.to_s.empty?
220
+
221
+ parent.add_child(::Lutaml::Xml::DataModel::XmlRawFragment.new(item.to_s))
222
+ end
223
+ end
224
+
204
225
  # Check if rule is custom-method-only (no real attribute)
205
226
  #
206
227
  # @param rule [CompiledRule] The rule
@@ -253,6 +253,15 @@ _register)
253
253
 
254
254
  private
255
255
 
256
+ # Resolve the unified raw mode from mapping rule and attribute
257
+ #
258
+ # @param mapping_rule [Xml::MappingRule] The mapping rule
259
+ # @param attr [Attribute, nil] The attribute (nil for custom methods)
260
+ # @return [Symbol, nil] :element, :content, or nil
261
+ def resolve_raw_mode(mapping_rule, attr)
262
+ mapping_rule.raw || (attr&.raw? ? :content : nil)
263
+ end
264
+
256
265
  # Infer attribute name from mapping rule or custom methods
257
266
  #
258
267
  # @param mapping_rule [Xml::MappingRule] The mapping rule
@@ -321,7 +330,7 @@ register_id, register, attr_name, custom_methods_value)
321
330
  mapping_type: :element,
322
331
  cdata: mapping_rule.cdata,
323
332
  mixed_content: mapping_rule.mixed_content?,
324
- raw: attr.raw?,
333
+ raw: resolve_raw_mode(mapping_rule, attr),
325
334
  render_default: mapping_rule.render_default,
326
335
  value_map: value_map,
327
336
  custom_methods: custom_methods_value,
@@ -350,7 +359,7 @@ custom_methods_value)
350
359
  mapping_type: :element,
351
360
  cdata: mapping_rule.cdata,
352
361
  mixed_content: mapping_rule.mixed_content?,
353
- raw: false,
362
+ raw: mapping_rule.raw,
354
363
  render_default: mapping_rule.render_default,
355
364
  value_map: value_map,
356
365
  custom_methods: custom_methods_value,
@@ -401,7 +410,7 @@ register_id, register, custom_methods_value)
401
410
  mapping_type: :element,
402
411
  cdata: mapping_rule.cdata,
403
412
  mixed_content: mapping_rule.mixed_content?,
404
- raw: attr.raw?,
413
+ raw: resolve_raw_mode(mapping_rule, attr),
405
414
  render_default: mapping_rule.render_default,
406
415
  value_map: value_map,
407
416
  custom_methods: custom_methods_value,
data/lutaml-model.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency "canon"
37
37
  spec.add_dependency "concurrent-ruby"
38
38
  spec.add_dependency "liquid", ">= 4.0", "< 6.0"
39
- spec.add_dependency "moxml", ">= 0.1.22"
39
+ spec.add_dependency "moxml", "~> 0.1.23"
40
40
  spec.add_dependency "ostruct"
41
41
  spec.add_dependency "rubyzip", "~> 2.3"
42
42
  spec.add_dependency "thor"