lutaml-model 0.8.15 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d6ce7467101e1a845bcd0bfb98b0e878d55d440065a12481576a8aa5c050c98
4
- data.tar.gz: e534138d7ca3848eaa33681e286584ea385386734617f37c5fa89a7c3f752f79
3
+ metadata.gz: 0b419ac1cce55a5e56ca59dd217042047801d2420751f89ce0b875558e517f44
4
+ data.tar.gz: ed7c6b7dcd749c35d7fa434d2adf4b9e036c7329afd80c2420ef75f57f65895f
5
5
  SHA512:
6
- metadata.gz: 8e872c659c1e147598fffe00ea015ed07dbd16b795c254f4aed6df30d2c6f2c91ab51740f5112b93e67d113d5b7d7f4edef755a2d6fa848053ab885533ac1336
7
- data.tar.gz: 22a484ca450a64ff4b3b0d426f1982e0e17d90eb422534158cf02ca65b96cc5293f401fec9cbbaa39a0ccaa06c0ef987b9a7f0f02312bc6fd55233b1666191ad
6
+ metadata.gz: c923ed6933f06ca678d4b76c19b46553f1196e0b30c0f202113a792619c91c0e6b3e3885963f4b910d101722d0cee22df8bf71c0c593fc7de4f0832d9062d87d
7
+ data.tar.gz: cfc1cc06ebeb1affa7875ecc522d8625147f70ed81aa6ae2feb2b4debd92f652ce2cf565f9984e52170e65559a75f23139c85762df5018545b60187cb5974744
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-27 05:02:01 UTC using RuboCop version 1.86.0.
3
+ # on 2026-06-05 08:01:07 UTC using RuboCop version 1.87.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -11,60 +11,13 @@ Gemspec/RequiredRubyVersion:
11
11
  Exclude:
12
12
  - 'lutaml-model.gemspec'
13
13
 
14
- # Offense count: 2
15
- # This cop supports safe autocorrection (--autocorrect).
16
- # Configuration parameters: EnforcedStyle, IndentationWidth.
17
- # SupportedStyles: with_first_argument, with_fixed_indentation
18
- Layout/ArgumentAlignment:
19
- Exclude:
20
- - 'spec/lutaml/model/opal_smoke_spec.rb'
21
-
22
- # Offense count: 1
23
- # This cop supports safe autocorrection (--autocorrect).
24
- Layout/ClosingParenthesisIndentation:
25
- Exclude:
26
- - 'spec/lutaml/model/opal_smoke_spec.rb'
27
-
28
- # Offense count: 1
29
- # This cop supports safe autocorrection (--autocorrect).
30
- # Configuration parameters: EnforcedStyle, IndentationWidth.
31
- # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
32
- Layout/FirstArgumentIndentation:
33
- Exclude:
34
- - 'spec/lutaml/model/opal_smoke_spec.rb'
35
-
36
- # Offense count: 2
37
- # This cop supports safe autocorrection (--autocorrect).
38
- # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
39
- # SupportedHashRocketStyles: key, separator, table
40
- # SupportedColonStyles: key, separator, table
41
- # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
42
- Layout/HashAlignment:
43
- Exclude:
44
- - 'spec/lutaml/model/opal_smoke_spec.rb'
45
-
46
- # Offense count: 3022
14
+ # Offense count: 3052
47
15
  # This cop supports safe autocorrection (--autocorrect).
48
16
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
49
17
  # URISchemes: http, https
50
18
  Layout/LineLength:
51
19
  Enabled: false
52
20
 
53
- # Offense count: 1
54
- # This cop supports safe autocorrection (--autocorrect).
55
- # Configuration parameters: EnforcedStyle.
56
- # SupportedStyles: symmetrical, new_line, same_line
57
- Layout/MultilineMethodCallBraceLayout:
58
- Exclude:
59
- - 'spec/lutaml/model/opal_smoke_spec.rb'
60
-
61
- # Offense count: 1
62
- # This cop supports safe autocorrection (--autocorrect).
63
- # Configuration parameters: AllowInHeredoc.
64
- Layout/TrailingWhitespace:
65
- Exclude:
66
- - 'spec/lutaml/model/opal_smoke_spec.rb'
67
-
68
21
  # Offense count: 21
69
22
  # Configuration parameters: AllowedMethods.
70
23
  # AllowedMethods: enums
@@ -76,21 +29,15 @@ Lint/ConstantDefinitionInBlock:
76
29
  - 'spec/lutaml/xml/type_namespace_prefix_spec.rb'
77
30
  - 'spec/lutaml/xml/xml_space_type_spec.rb'
78
31
 
79
- # Offense count: 36
32
+ # Offense count: 35
80
33
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
81
34
  Lint/DuplicateBranch:
82
35
  Enabled: false
83
36
 
84
- # Offense count: 22
37
+ # Offense count: 3
85
38
  Lint/DuplicateMethods:
86
39
  Exclude:
87
40
  - 'lib/lutaml/xml/mapping.rb'
88
- - 'spec/lutaml/model/liquid_compatibility_spec.rb'
89
- - 'spec/lutaml/xml/namespace_no_hoisting_spec.rb'
90
- - 'spec/lutaml/xml/namespace_scope_declare_spec.rb'
91
- - 'spec/lutaml/xml/namespace_scope_vcard_spec.rb'
92
- - 'spec/lutaml/xml/prefix_control_spec.rb'
93
- - 'spec/lutaml/xml/type_namespace_examples_spec.rb'
94
41
 
95
42
  # Offense count: 1
96
43
  # This cop supports safe autocorrection (--autocorrect).
@@ -156,18 +103,12 @@ Lint/UnusedMethodArgument:
156
103
  - 'lib/lutaml/xml/unqualified_inheritance_strategy.rb'
157
104
  - 'spec/support/xml/xsd/code_example_validator.rb'
158
105
 
159
- # Offense count: 1
160
- # This cop supports safe autocorrection (--autocorrect).
161
- Lint/UselessAssignment:
162
- Exclude:
163
- - 'spec/lutaml/xml/opal_xml_spec.rb'
164
-
165
106
  # Offense count: 1
166
107
  Lint/UselessConstantScoping:
167
108
  Exclude:
168
109
  - 'lib/lutaml/xml/mapping_rule.rb'
169
110
 
170
- # Offense count: 345
111
+ # Offense count: 346
171
112
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
172
113
  Metrics/AbcSize:
173
114
  Enabled: false
@@ -183,12 +124,12 @@ Metrics/BlockLength:
183
124
  Metrics/BlockNesting:
184
125
  Max: 6
185
126
 
186
- # Offense count: 308
127
+ # Offense count: 307
187
128
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
188
129
  Metrics/CyclomaticComplexity:
189
130
  Enabled: false
190
131
 
191
- # Offense count: 553
132
+ # Offense count: 554
192
133
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
193
134
  Metrics/MethodLength:
194
135
  Max: 514
@@ -196,10 +137,10 @@ Metrics/MethodLength:
196
137
  # Offense count: 81
197
138
  # Configuration parameters: CountKeywordArgs.
198
139
  Metrics/ParameterLists:
199
- Max: 24
200
140
  MaxOptionalParameters: 5
141
+ Max: 25
201
142
 
202
- # Offense count: 262
143
+ # Offense count: 261
203
144
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
204
145
  Metrics/PerceivedComplexity:
205
146
  Enabled: false
@@ -291,7 +232,7 @@ RSpec/BeforeAfterAll:
291
232
  RSpec/ContextWording:
292
233
  Enabled: false
293
234
 
294
- # Offense count: 98
235
+ # Offense count: 101
295
236
  # Configuration parameters: IgnoredMetadata.
296
237
  RSpec/DescribeClass:
297
238
  Enabled: false
@@ -302,7 +243,7 @@ RSpec/DescribeMethod:
302
243
  - 'spec/lutaml/xml/schema/xsd/schema_helper_methods_spec.rb'
303
244
  - 'spec/lutaml/xml/serializable_namespace_spec.rb'
304
245
 
305
- # Offense count: 1301
246
+ # Offense count: 1328
306
247
  # Configuration parameters: CountAsOne.
307
248
  RSpec/ExampleLength:
308
249
  Max: 68
@@ -377,7 +318,7 @@ RSpec/MultipleDescribes:
377
318
  - 'spec/lutaml/xml/namespace_resolution_strategy_spec.rb'
378
319
  - 'spec/lutaml/xml/xml_space_type_spec.rb'
379
320
 
380
- # Offense count: 1515
321
+ # Offense count: 1560
381
322
  RSpec/MultipleExpectations:
382
323
  Max: 21
383
324
 
@@ -544,10 +485,10 @@ Style/StringConcatenation:
544
485
  - 'lib/lutaml/model/schema/xml_compiler/simple_type.rb'
545
486
  - 'lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb'
546
487
 
547
- # Offense count: 1
488
+ # Offense count: 3
548
489
  # This cop supports safe autocorrection (--autocorrect).
549
490
  # Configuration parameters: EnforcedStyleForMultiline.
550
491
  # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
551
492
  Style/TrailingCommaInArguments:
552
493
  Exclude:
553
- - 'spec/lutaml/model/opal_smoke_spec.rb'
494
+ - 'spec/lutaml/model/raw_element_spec.rb'
data/README.adoc CHANGED
@@ -3554,7 +3554,14 @@ the current value is the same as the default value.
3554
3554
 
3555
3555
 
3556
3556
 
3557
- === Attribute as raw string
3557
+ === Attribute as raw string (deprecated)
3558
+
3559
+ [WARNING]
3560
+ ====
3561
+ `attribute :name, :string, raw: true` is deprecated.
3562
+ Use `map_element "name", to: :name, raw: :content` instead.
3563
+ See <<xml-raw-element>> for the full raw XML capture documentation.
3564
+ ====
3558
3565
 
3559
3566
  An attribute can be set to read the value as raw string for XML, by using the `raw: true` option.
3560
3567
 
@@ -7969,42 +7976,186 @@ end
7969
7976
  ====
7970
7977
 
7971
7978
 
7972
- [[xml-map-all]]
7973
- ==== Mapping entire XML element into an attribute
7974
7979
 
7975
- The `map_all` tag in XML mapping captures and maps all content within an XML
7976
- element into a single attribute in the target Ruby object.
7980
+ [[xml-raw-element]]
7981
+ ==== Capturing raw XML content
7977
7982
 
7978
- The use case for `map_all` is to tell Lutaml::Model to not parse the content of
7979
- the XML element at all, and instead handle it as an XML string.
7983
+ Lutaml::Model provides several mechanisms for capturing XML content as raw strings.
7984
+ Use these when you need to embed foreign XML vocabularies (SVG, MathML, XSL-FO) or
7985
+ preserve markup that your model doesn't need to parse.
7980
7986
 
7981
- NOTE: The corresponding method for key-value formats is at <<key-value-map-all>>.
7987
+ ===== `raw: :element` on `map_element` full element capture (recommended)
7982
7988
 
7983
- WARNING: Notice that usage of mapping all will lead to incompatibility between
7984
- serialization formats, i.e. the raw string content will not be portable as
7985
- objects are across different formats.
7989
+ The `raw: :element` option captures a specific mapped element as a complete XML
7990
+ string, including its opening tag, attributes, children, and closing tag.
7991
+ This provides **lossless round-trip** fidelity — the captured string is
7992
+ self-contained and serialized verbatim.
7993
+
7994
+ .Syntax
7995
+ [source,ruby]
7996
+ ----
7997
+ xml do
7998
+ map_element "svg", to: :svg_data, raw: :element
7999
+ end
8000
+ ----
8001
+
8002
+ .Capturing an SVG element as raw XML
8003
+ [example]
8004
+ ====
8005
+ [source,ruby]
8006
+ ----
8007
+ class SvgContainer < Lutaml::Model::Serializable
8008
+ attribute :name, :string
8009
+ attribute :svg_data, :string
8010
+
8011
+ xml do
8012
+ element "container"
8013
+ map_element "name", to: :name
8014
+ map_element "svg", to: :svg_data, raw: :element
8015
+ end
8016
+ end
8017
+ ----
7986
8018
 
7987
- This is useful in the case where the content of an XML element is not to be
7988
- handled by a Lutaml::Model::Serializable object.
8019
+ [source,xml]
8020
+ ----
8021
+ <container>
8022
+ <name>diagram</name>
8023
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
8024
+ <rect x="0" y="0" width="100" height="100" fill="red"/>
8025
+ </svg>
8026
+ </container>
8027
+ ----
7989
8028
 
7990
- This feature is commonly used with custom methods or a custom model object to
7991
- handle the content.
8029
+ [source,ruby]
8030
+ ----
8031
+ > doc = SvgContainer.from_xml(xml)
8032
+ > doc.name
8033
+ # => "diagram"
8034
+ > doc.svg_data
8035
+ # => "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n <rect x=\"0\" y=\"0\" width=\"100\" height=\"100\" fill=\"red\"/>\n</svg>"
8036
+ ----
7992
8037
 
7993
- This includes:
8038
+ The captured string round-trips correctly -- serializing the model back to XML
8039
+ outputs the raw element verbatim without escaping or wrapping.
7994
8040
 
7995
- * nested tags
7996
- * attributes
7997
- * text nodes
8041
+ `raw: :element` also works with collection attributes:
7998
8042
 
7999
- The `map_all` tag is **exclusive** and cannot be combined with other mappings
8000
- (`map_element`, `map_content`) except for `map_attribute` for the same element,
8001
- ensuring it captures the entire inner XML content.
8043
+ [source,ruby]
8044
+ ----
8045
+ class MultiFragment < Lutaml::Model::Serializable
8046
+ attribute :fragments, :string, collection: true
8002
8047
 
8003
- NOTE: An error is raised if `map_all` is defined alongside any other mapping in
8004
- the same XML mapping context.
8048
+ xml do
8049
+ element "container"
8050
+ map_element "fragment", to: :fragments, raw: :element
8051
+ end
8052
+ end
8053
+ ----
8054
+ ====
8005
8055
 
8006
- Syntax:
8056
+ ===== `raw: :content` on `map_element` — inner content capture
8057
+
8058
+ The `raw: :content` option captures only the *inner XML* of the matched element,
8059
+ without the wrapper tags. The wrapper element is reconstructed from the mapping rule
8060
+ during serialization.
8061
+
8062
+ .Syntax
8063
+ [source,ruby]
8064
+ ----
8065
+ xml do
8066
+ map_element "street", to: :street, raw: :content
8067
+ end
8068
+ ----
8069
+
8070
+ .Capturing inner XML content
8071
+ [example]
8072
+ ====
8073
+ [source,ruby]
8074
+ ----
8075
+ class Address < Lutaml::Model::Serializable
8076
+ attribute :street, :string
8077
+
8078
+ xml do
8079
+ element "address"
8080
+ map_element "street", to: :street, raw: :content
8081
+ end
8082
+ end
8083
+ ----
8084
+
8085
+ [source,xml]
8086
+ ----
8087
+ <address><street><b>123</b> Main St</street></address>
8088
+ ----
8089
+
8090
+ [source,ruby]
8091
+ ----
8092
+ > doc = Address.from_xml(xml)
8093
+ > doc.street
8094
+ # => "<b>123</b> Main St"
8095
+ ----
8096
+ ====
8097
+
8098
+ NOTE: `raw: :content` is **lossy** — namespace prefixes declared on the wrapper
8099
+ element are not captured. For lossless capture, use `raw: :element` instead.
8100
+
8101
+ ===== Namespace behavior
8102
+
8103
+ Both `raw: :element` and `raw: :content` match elements by local name regardless
8104
+ of namespace or prefix:
8105
+
8106
+ * Elements with no namespace (`<svg>`)
8107
+ * Elements with an `xmlns` declaration on themselves (`<svg xmlns="...">`)
8108
+ * Elements inheriting a default namespace from a parent
8109
+ * Elements with an explicit namespace prefix (`<ns:svg>`)
8110
+
8111
+ This is intentional — raw capture is designed to handle foreign XML vocabularies
8112
+ without needing model classes for them.
8113
+
8114
+ ===== Round-trip fidelity comparison
8115
+
8116
+ | Aspect | `raw: :element` | `raw: :content` |
8117
+ |--------|----------------|-----------------|
8118
+ | Element name | Preserved (in string) | Reconstructed from rule |
8119
+ | Element attributes | Preserved (in string) | Lost unless separately mapped |
8120
+ | Inner content | Preserved (in string) | Preserved (in string) |
8121
+ | Namespace prefixes | Safe (declared in string) | May break if declared on wrapper |
8122
+ | Fidelity | **Lossless** | **Lossy** |
8123
+
8124
+ ===== Wrapper model pattern for attribute extraction
8125
+
8126
+ Raw capture stores the element as a string. If you need to inspect or modify
8127
+ attributes on the captured element, use a wrapper model with `map_all`:
8007
8128
 
8129
+ [source,ruby]
8130
+ ----
8131
+ class SvgInner < Lutaml::Model::Serializable
8132
+ attribute :raw, :string
8133
+
8134
+ xml do
8135
+ element "svg"
8136
+ map_all to: :raw
8137
+ end
8138
+ end
8139
+
8140
+ class Container < Lutaml::Model::Serializable
8141
+ attribute :svg_data, SvgInner
8142
+
8143
+ xml do
8144
+ element "container"
8145
+ map_element "svg", to: :svg_data
8146
+ end
8147
+ end
8148
+ ----
8149
+
8150
+ ===== `map_all` — root inner XML capture
8151
+
8152
+ The `map_all` directive captures the entire inner XML of the root element into
8153
+ a single attribute. It is **exclusive** — it cannot be combined with other
8154
+ `map_element` or `map_content` mappings (only `map_attribute` is allowed).
8155
+
8156
+ NOTE: The corresponding method for key-value formats is at <<key-value-map-all>>.
8157
+
8158
+ .Syntax
8008
8159
  [source,ruby]
8009
8160
  ----
8010
8161
  xml do
@@ -8039,6 +8190,18 @@ end
8039
8190
  ----
8040
8191
  ====
8041
8192
 
8193
+ ===== Deprecated: `attribute :x, :string, raw: true`
8194
+
8195
+ [WARNING]
8196
+ ====
8197
+ `attribute :name, :string, raw: true` is deprecated. Use
8198
+ `map_element "name", to: :name, raw: :content` instead.
8199
+ ====
8200
+
8201
+ This legacy syntax captures the inner XML of the matched element.
8202
+ It is equivalent to `raw: :content` on the mapping. Existing code continues
8203
+ to work but emits a deprecation warning.
8204
+
8042
8205
 
8043
8206
  ==== Mapping CDATA nodes
8044
8207
 
@@ -1097,42 +1097,184 @@ end
1097
1097
  ====
1098
1098
 
1099
1099
 
1100
- [[xml-map-all]]
1101
- ==== Mapping entire XML element into an attribute
1102
1100
 
1103
- The `map_all` tag in XML mapping captures and maps all content within an XML
1104
- element into a single attribute in the target Ruby object.
1101
+ [[xml-raw-element]]
1102
+ ==== Capturing raw XML content
1105
1103
 
1106
- The use case for `map_all` is to tell Lutaml::Model to not parse the content of
1107
- the XML element at all, and instead handle it as an XML string.
1104
+ Lutaml::Model provides several mechanisms for capturing XML content as raw strings.
1105
+ Use these when you need to embed foreign XML vocabularies (SVG, MathML, XSL-FO) or
1106
+ preserve markup that your model doesn't need to parse.
1108
1107
 
1109
- NOTE: The corresponding method for key-value formats is at <<key-value-map-all>>.
1108
+ ===== `raw: :element` on `map_element` -- full element capture (recommended)
1110
1109
 
1111
- WARNING: Notice that usage of mapping all will lead to incompatibility between
1112
- serialization formats, i.e. the raw string content will not be portable as
1113
- objects are across different formats.
1110
+ The `raw: :element` option captures a specific mapped element as a complete XML
1111
+ string, including its opening tag, attributes, children, and closing tag.
1112
+ This provides **lossless round-trip** fidelity -- the captured string is
1113
+ self-contained and serialized verbatim.
1114
1114
 
1115
- This is useful in the case where the content of an XML element is not to be
1116
- handled by a Lutaml::Model::Serializable object.
1115
+ .Syntax
1116
+ [source,ruby]
1117
+ ----
1118
+ xml do
1119
+ map_element "svg", to: :svg_data, raw: :element
1120
+ end
1121
+ ----
1117
1122
 
1118
- This feature is commonly used with custom methods or a custom model object to
1119
- handle the content.
1123
+ .Capturing an SVG element as raw XML
1124
+ [example]
1125
+ ====
1126
+ [source,ruby]
1127
+ ----
1128
+ class SvgContainer < Lutaml::Model::Serializable
1129
+ attribute :name, :string
1130
+ attribute :svg_data, :string
1120
1131
 
1121
- This includes:
1132
+ xml do
1133
+ element "container"
1134
+ map_element "name", to: :name
1135
+ map_element "svg", to: :svg_data, raw: :element
1136
+ end
1137
+ end
1138
+ ----
1122
1139
 
1123
- * nested tags
1124
- * attributes
1125
- * text nodes
1140
+ [source,xml]
1141
+ ----
1142
+ <container>
1143
+ <name>diagram</name>
1144
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
1145
+ <rect x="0" y="0" width="100" height="100" fill="red"/>
1146
+ </svg>
1147
+ </container>
1148
+ ----
1126
1149
 
1127
- The `map_all` tag is **exclusive** and cannot be combined with other mappings
1128
- (`map_element`, `map_content`) except for `map_attribute` for the same element,
1129
- ensuring it captures the entire inner XML content.
1150
+ [source,ruby]
1151
+ ----
1152
+ > doc = SvgContainer.from_xml(xml)
1153
+ > doc.name
1154
+ # => "diagram"
1155
+ > doc.svg_data
1156
+ # => "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n <rect x=\"0\" y=\"0\" width=\"100\" height=\"100\" fill=\"red\"/>\n</svg>"
1157
+ ----
1130
1158
 
1131
- NOTE: An error is raised if `map_all` is defined alongside any other mapping in
1132
- the same XML mapping context.
1159
+ The captured string round-trips correctly -- serializing the model back to XML
1160
+ outputs the raw element verbatim without escaping or wrapping.
1133
1161
 
1134
- Syntax:
1162
+ `raw: :element` also works with collection attributes:
1135
1163
 
1164
+ [source,ruby]
1165
+ ----
1166
+ class MultiFragment < Lutaml::Model::Serializable
1167
+ attribute :fragments, :string, collection: true
1168
+
1169
+ xml do
1170
+ element "container"
1171
+ map_element "fragment", to: :fragments, raw: :element
1172
+ end
1173
+ end
1174
+ ----
1175
+ ====
1176
+
1177
+ ===== `raw: :content` on `map_element` -- inner content capture
1178
+
1179
+ The `raw: :content` option captures only the *inner XML* of the matched element,
1180
+ without the wrapper tags. The wrapper element is reconstructed from the mapping rule
1181
+ during serialization.
1182
+
1183
+ .Syntax
1184
+ [source,ruby]
1185
+ ----
1186
+ xml do
1187
+ map_element "street", to: :street, raw: :content
1188
+ end
1189
+ ----
1190
+
1191
+ .Capturing inner XML content
1192
+ [example]
1193
+ ====
1194
+ [source,ruby]
1195
+ ----
1196
+ class Address < Lutaml::Model::Serializable
1197
+ attribute :street, :string
1198
+
1199
+ xml do
1200
+ element "address"
1201
+ map_element "street", to: :street, raw: :content
1202
+ end
1203
+ end
1204
+ ----
1205
+
1206
+ [source,xml]
1207
+ ----
1208
+ <address><street><b>123</b> Main St</street></address>
1209
+ ----
1210
+
1211
+ [source,ruby]
1212
+ ----
1213
+ > doc = Address.from_xml(xml)
1214
+ > doc.street
1215
+ # => "<b>123</b> Main St"
1216
+ ----
1217
+ ====
1218
+
1219
+ NOTE: `raw: :content` is **lossy** -- namespace prefixes declared on the wrapper
1220
+ element are not captured. For lossless capture, use `raw: :element` instead.
1221
+
1222
+ ===== Namespace behavior
1223
+
1224
+ Both `raw: :element` and `raw: :content` match elements by local name regardless
1225
+ of namespace or prefix:
1226
+
1227
+ * Elements with no namespace (`<svg>`)
1228
+ * Elements with an `xmlns` declaration on themselves (`<svg xmlns="...">`)
1229
+ * Elements inheriting a default namespace from a parent
1230
+ * Elements with an explicit namespace prefix (`<ns:svg>`)
1231
+
1232
+ This is intentional -- raw capture is designed to handle foreign XML vocabularies
1233
+ without needing model classes for them.
1234
+
1235
+ ===== Round-trip fidelity comparison
1236
+
1237
+ | Aspect | `raw: :element` | `raw: :content` |
1238
+ |--------|----------------|-----------------|
1239
+ | Element name | Preserved (in string) | Reconstructed from rule |
1240
+ | Element attributes | Preserved (in string) | Lost unless separately mapped |
1241
+ | Inner content | Preserved (in string) | Preserved (in string) |
1242
+ | Namespace prefixes | Safe (declared in string) | May break if declared on wrapper |
1243
+ | Fidelity | **Lossless** | **Lossy** |
1244
+
1245
+ ===== Wrapper model pattern for attribute extraction
1246
+
1247
+ Raw capture stores the element as a string. If you need to inspect or modify
1248
+ attributes on the captured element, use a wrapper model with `map_all`:
1249
+
1250
+ [source,ruby]
1251
+ ----
1252
+ class SvgInner < Lutaml::Model::Serializable
1253
+ attribute :raw, :string
1254
+
1255
+ xml do
1256
+ element "svg"
1257
+ map_all to: :raw
1258
+ end
1259
+ end
1260
+
1261
+ class Container < Lutaml::Model::Serializable
1262
+ attribute :svg_data, SvgInner
1263
+
1264
+ xml do
1265
+ element "container"
1266
+ map_element "svg", to: :svg_data
1267
+ end
1268
+ end
1269
+ ----
1270
+
1271
+ ===== `map_all` -- root inner XML capture
1272
+
1273
+ The `map_all` directive captures the entire inner XML of the root element into
1274
+ a single attribute. It is **exclusive** -- it cannot be combined with other
1275
+ `map_element` or `map_content` mappings (only `map_attribute` is allowed).
1276
+
1277
+ .Syntax
1136
1278
  [source,ruby]
1137
1279
  ----
1138
1280
  xml do
@@ -1167,6 +1309,18 @@ end
1167
1309
  ----
1168
1310
  ====
1169
1311
 
1312
+ ===== Deprecated: `attribute :x, :string, raw: true`
1313
+
1314
+ [WARNING]
1315
+ ====
1316
+ `attribute :name, :string, raw: true` is deprecated. Use
1317
+ `map_element "name", to: :name, raw: :content` instead.
1318
+ ====
1319
+
1320
+ This legacy syntax captures the inner XML of the matched element.
1321
+ It is equivalent to `raw: :content` on the mapping. Existing code continues
1322
+ to work but emits a deprecation warning.
1323
+
1170
1324
 
1171
1325
  ==== Mapping CDATA nodes
1172
1326
 
@@ -546,7 +546,13 @@ the current value is the same as the default value.
546
546
 
547
547
 
548
548
 
549
- === Attribute as raw string
549
+ === Attribute as raw string (deprecated)
550
+
551
+ [WARNING]
552
+ ====
553
+ `attribute :name, :string, raw: true` is deprecated.
554
+ Use `map_element "name", to: :name, raw: :content` instead.
555
+ ====
550
556
 
551
557
  An attribute can be set to read the value as raw string for XML, by using the `raw: true` option.
552
558