lutaml-model 0.3.0 → 0.3.1
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 +4 -4
- data/README.adoc +995 -138
- data/lib/lutaml/model/error/invalid_value_error.rb +18 -0
- data/lib/lutaml/model/error.rb +8 -0
- data/lib/lutaml/model/key_value_mapping.rb +9 -1
- data/lib/lutaml/model/mapping_rule.rb +5 -2
- data/lib/lutaml/model/serialize.rb +220 -150
- data/lib/lutaml/model/toml_adapter/toml_rb_adapter.rb +2 -2
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +15 -7
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +16 -8
- data/lib/lutaml/model/xml_adapter.rb +31 -12
- data/lib/lutaml/model/yaml_adapter.rb +11 -3
- data/lib/lutaml/model.rb +7 -0
- metadata +4 -2
@@ -0,0 +1,18 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
class InvalidValueError < Error
|
4
|
+
def initialize(attr_name, value, allowed_values)
|
5
|
+
@attr_name = attr_name
|
6
|
+
@value = value
|
7
|
+
@allowed_values = allowed_values
|
8
|
+
|
9
|
+
super()
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#{@attr_name} is `#{@value}`, must be one of the " \
|
14
|
+
"following [#{@allowed_values.join(', ')}]"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -10,13 +10,21 @@ module Lutaml
|
|
10
10
|
@mappings = []
|
11
11
|
end
|
12
12
|
|
13
|
-
def map(
|
13
|
+
def map(
|
14
|
+
name,
|
15
|
+
to:,
|
16
|
+
render_nil: false,
|
17
|
+
with: {},
|
18
|
+
delegate: nil,
|
19
|
+
child_mappings: nil
|
20
|
+
)
|
14
21
|
@mappings << KeyValueMappingRule.new(
|
15
22
|
name,
|
16
23
|
to: to,
|
17
24
|
render_nil: render_nil,
|
18
25
|
with: with,
|
19
26
|
delegate: delegate,
|
27
|
+
child_mappings: child_mappings,
|
20
28
|
)
|
21
29
|
end
|
22
30
|
|
@@ -7,7 +7,8 @@ module Lutaml
|
|
7
7
|
:render_nil,
|
8
8
|
:custom_methods,
|
9
9
|
:delegate,
|
10
|
-
:mixed_content
|
10
|
+
:mixed_content,
|
11
|
+
:child_mappings
|
11
12
|
|
12
13
|
def initialize(
|
13
14
|
name,
|
@@ -16,7 +17,8 @@ module Lutaml
|
|
16
17
|
with: {},
|
17
18
|
delegate: nil,
|
18
19
|
mixed_content: false,
|
19
|
-
namespace_set: false
|
20
|
+
namespace_set: false,
|
21
|
+
child_mappings: nil
|
20
22
|
)
|
21
23
|
@name = name
|
22
24
|
@to = to
|
@@ -25,6 +27,7 @@ module Lutaml
|
|
25
27
|
@delegate = delegate
|
26
28
|
@mixed_content = mixed_content
|
27
29
|
@namespace_set = namespace_set
|
30
|
+
@child_mappings = child_mappings
|
28
31
|
end
|
29
32
|
|
30
33
|
alias from name
|
@@ -25,11 +25,23 @@ module Lutaml
|
|
25
25
|
def inherited(subclass)
|
26
26
|
super
|
27
27
|
|
28
|
+
@mappings ||= {}
|
29
|
+
@attributes ||= {}
|
30
|
+
|
28
31
|
subclass.instance_variable_set(:@attributes, @attributes.dup)
|
32
|
+
subclass.instance_variable_set(:@mappings, @mappings.dup)
|
33
|
+
subclass.instance_variable_set(:@model, subclass)
|
34
|
+
end
|
35
|
+
|
36
|
+
def model(klass = nil)
|
37
|
+
if klass
|
38
|
+
@model = klass
|
39
|
+
else
|
40
|
+
@model
|
41
|
+
end
|
29
42
|
end
|
30
43
|
|
31
44
|
def attribute(name, type, options = {})
|
32
|
-
self.attributes ||= {}
|
33
45
|
attr = Attribute.new(name, type, options)
|
34
46
|
attributes[name] = attr
|
35
47
|
|
@@ -38,19 +50,22 @@ module Lutaml
|
|
38
50
|
end
|
39
51
|
|
40
52
|
define_method(:"#{name}=") do |value|
|
53
|
+
if options[:values] && !options[:values].include?(value)
|
54
|
+
raise Lutaml::Model::InvalidValueError.new(name, value, options[:values])
|
55
|
+
end
|
56
|
+
|
41
57
|
instance_variable_set(:"@#{name}", value)
|
42
58
|
end
|
43
59
|
end
|
44
60
|
|
45
61
|
FORMATS.each do |format|
|
46
62
|
define_method(format) do |&block|
|
47
|
-
self.mappings ||= {}
|
48
63
|
klass = format == :xml ? XmlMapping : KeyValueMapping
|
49
|
-
|
50
|
-
|
64
|
+
mappings[format] = klass.new
|
65
|
+
mappings[format].instance_eval(&block)
|
51
66
|
|
52
|
-
if format == :xml && !
|
53
|
-
|
67
|
+
if format == :xml && !mappings[format].root_element
|
68
|
+
mappings[format].root(model.to_s)
|
54
69
|
end
|
55
70
|
end
|
56
71
|
|
@@ -59,12 +74,135 @@ module Lutaml
|
|
59
74
|
doc = adapter.parse(data)
|
60
75
|
mapped_attrs = apply_mappings(doc.to_h, format)
|
61
76
|
# apply_content_mapping(doc, mapped_attrs) if format == :xml
|
62
|
-
|
77
|
+
generate_model_object(self, mapped_attrs)
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method(:"to_#{format}") do |instance|
|
81
|
+
unless instance.is_a?(model)
|
82
|
+
msg = "argument is a '#{instance.class}' but should be a '#{model}'"
|
83
|
+
raise Lutaml::Model::IncorrectModelError, msg
|
84
|
+
end
|
85
|
+
|
86
|
+
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
87
|
+
|
88
|
+
if format == :xml
|
89
|
+
xml_options = { mapper_class: self }
|
90
|
+
|
91
|
+
adapter.new(instance).public_send(:"to_#{format}", xml_options)
|
92
|
+
else
|
93
|
+
hash = hash_representation(instance, format)
|
94
|
+
adapter.new(hash).public_send(:"to_#{format}")
|
95
|
+
end
|
63
96
|
end
|
64
97
|
end
|
65
98
|
|
99
|
+
def hash_representation(instance, format, options = {})
|
100
|
+
only = options[:only]
|
101
|
+
except = options[:except]
|
102
|
+
mappings = mappings_for(format).mappings
|
103
|
+
|
104
|
+
mappings.each_with_object({}) do |rule, hash|
|
105
|
+
name = rule.to
|
106
|
+
next if except&.include?(name) || (only && !only.include?(name))
|
107
|
+
|
108
|
+
next handle_delegate(instance, rule, hash) if rule.delegate
|
109
|
+
|
110
|
+
value = if rule.custom_methods[:to]
|
111
|
+
instance.send(rule.custom_methods[:to], instance, instance.send(name))
|
112
|
+
else
|
113
|
+
instance.send(name)
|
114
|
+
end
|
115
|
+
|
116
|
+
next if value.nil? && !rule.render_nil
|
117
|
+
|
118
|
+
attribute = attributes[name]
|
119
|
+
|
120
|
+
hash[rule.from] = if rule.child_mappings
|
121
|
+
generate_hash_from_child_mappings(value, rule.child_mappings)
|
122
|
+
elsif value.is_a?(Array)
|
123
|
+
value.map do |v|
|
124
|
+
if attribute.type <= Serialize
|
125
|
+
attribute.type.hash_representation(v, format, options)
|
126
|
+
else
|
127
|
+
attribute.type.serialize(v)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
elsif attribute.type <= Serialize
|
131
|
+
attribute.type.hash_representation(value, format, options)
|
132
|
+
else
|
133
|
+
attribute.type.serialize(value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def handle_delegate(instance, rule, hash)
|
139
|
+
name = rule.to
|
140
|
+
value = instance.send(rule.delegate).send(name)
|
141
|
+
return if value.nil? && !rule.render_nil
|
142
|
+
|
143
|
+
attribute = instance.send(rule.delegate).class.attributes[name]
|
144
|
+
hash[rule.from] = case value
|
145
|
+
when Array
|
146
|
+
value.map do |v|
|
147
|
+
if v.is_a?(Serialize)
|
148
|
+
hash_representation(v, format, options)
|
149
|
+
else
|
150
|
+
attribute.type.serialize(v)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
if value.is_a?(Serialize)
|
155
|
+
hash_representation(value, format, options)
|
156
|
+
else
|
157
|
+
attribute.type.serialize(value)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
66
162
|
def mappings_for(format)
|
67
|
-
|
163
|
+
mappings[format] || default_mappings(format)
|
164
|
+
end
|
165
|
+
|
166
|
+
def generate_model_object(type, mapped_attrs)
|
167
|
+
return type.model.new(mapped_attrs) if self == model
|
168
|
+
|
169
|
+
instance = type.model.new
|
170
|
+
|
171
|
+
type.attributes.each do |name, attr|
|
172
|
+
value = attr_value(mapped_attrs, name, attr)
|
173
|
+
|
174
|
+
instance.send(:"#{name}=", ensure_utf8(value))
|
175
|
+
end
|
176
|
+
|
177
|
+
instance
|
178
|
+
end
|
179
|
+
|
180
|
+
def attr_value(attrs, name, attr_rule)
|
181
|
+
value = if attrs.key?(name)
|
182
|
+
attrs[name]
|
183
|
+
elsif attrs.key?(name.to_sym)
|
184
|
+
attrs[name.to_sym]
|
185
|
+
elsif attrs.key?(name.to_s)
|
186
|
+
attrs[name.to_s]
|
187
|
+
else
|
188
|
+
attr_rule.default
|
189
|
+
end
|
190
|
+
|
191
|
+
if attr_rule.collection? || value.is_a?(Array)
|
192
|
+
(value || []).map do |v|
|
193
|
+
if v.is_a?(Hash)
|
194
|
+
attr_rule.type.new(v)
|
195
|
+
else
|
196
|
+
Lutaml::Model::Type.cast(
|
197
|
+
v, attr_rule.type
|
198
|
+
)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
elsif value.is_a?(Hash) && attr_rule.type != Lutaml::Model::Type::Hash
|
202
|
+
generate_model_object(attr_rule.type, value)
|
203
|
+
else
|
204
|
+
Lutaml::Model::Type.cast(value, attr_rule.type)
|
205
|
+
end
|
68
206
|
end
|
69
207
|
|
70
208
|
def default_mappings(format)
|
@@ -77,6 +215,52 @@ module Lutaml
|
|
77
215
|
end
|
78
216
|
end
|
79
217
|
|
218
|
+
def apply_child_mappings(hash, child_mappings)
|
219
|
+
return hash unless child_mappings
|
220
|
+
|
221
|
+
hash.map do |key, value|
|
222
|
+
child_mappings.to_h do |attr_name, path|
|
223
|
+
attr_value = if path == :key
|
224
|
+
key
|
225
|
+
elsif path == :value
|
226
|
+
value
|
227
|
+
else
|
228
|
+
path = [path] unless path.is_a?(Array)
|
229
|
+
value.dig(*path.map(&:to_s))
|
230
|
+
end
|
231
|
+
|
232
|
+
[attr_name, attr_value]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def generate_hash_from_child_mappings(value, child_mappings)
|
238
|
+
return value unless child_mappings
|
239
|
+
|
240
|
+
hash = {}
|
241
|
+
|
242
|
+
value.each do |child_obj|
|
243
|
+
map_key = nil
|
244
|
+
map_value = {}
|
245
|
+
child_mappings.each do |attr_name, path|
|
246
|
+
if path == :key
|
247
|
+
map_key = child_obj.send(attr_name)
|
248
|
+
elsif path == :value
|
249
|
+
map_value = child_obj.send(attr_name)
|
250
|
+
else
|
251
|
+
path = [path] unless path.is_a?(Array)
|
252
|
+
path[0...-1].inject(map_value) do |acc, k|
|
253
|
+
acc[k.to_s] ||= {}
|
254
|
+
end.public_send(:[]=, path.last.to_s, child_obj.send(attr_name))
|
255
|
+
end
|
256
|
+
end
|
257
|
+
# hash[mapping.name] ||= {}
|
258
|
+
hash[map_key] = map_value
|
259
|
+
end
|
260
|
+
|
261
|
+
hash
|
262
|
+
end
|
263
|
+
|
80
264
|
def apply_mappings(doc, format)
|
81
265
|
return apply_xml_mapping(doc) if format == :xml
|
82
266
|
|
@@ -98,6 +282,8 @@ module Lutaml
|
|
98
282
|
attr.default
|
99
283
|
end
|
100
284
|
|
285
|
+
value = apply_child_mappings(value, rule.child_mappings)
|
286
|
+
|
101
287
|
if attr.collection?
|
102
288
|
value = (value || []).map do |v|
|
103
289
|
attr.type <= Serialize ? attr.type.apply_mappings(v, format) : v
|
@@ -167,6 +353,21 @@ module Lutaml
|
|
167
353
|
hash[rule.to] = value
|
168
354
|
end
|
169
355
|
end
|
356
|
+
|
357
|
+
def ensure_utf8(value)
|
358
|
+
case value
|
359
|
+
when String
|
360
|
+
value.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
361
|
+
when Array
|
362
|
+
value.map { |v| ensure_utf8(v) }
|
363
|
+
when Hash
|
364
|
+
value.transform_keys do |k|
|
365
|
+
ensure_utf8(k)
|
366
|
+
end.transform_values { |v| ensure_utf8(v) }
|
367
|
+
else
|
368
|
+
value
|
369
|
+
end
|
370
|
+
end
|
170
371
|
end
|
171
372
|
|
172
373
|
attr_reader :element_order
|
@@ -180,37 +381,9 @@ module Lutaml
|
|
180
381
|
end
|
181
382
|
|
182
383
|
self.class.attributes.each do |name, attr|
|
183
|
-
value = attr_value(attrs, name, attr)
|
184
|
-
|
185
|
-
send(:"#{name}=", ensure_utf8(value))
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def attr_value(attrs, name, attr_rule)
|
190
|
-
value = if attrs.key?(name)
|
191
|
-
attrs[name]
|
192
|
-
elsif attrs.key?(name.to_sym)
|
193
|
-
attrs[name.to_sym]
|
194
|
-
elsif attrs.key?(name.to_s)
|
195
|
-
attrs[name.to_s]
|
196
|
-
else
|
197
|
-
attr_rule.default
|
198
|
-
end
|
384
|
+
value = self.class.attr_value(attrs, name, attr)
|
199
385
|
|
200
|
-
|
201
|
-
(value || []).map do |v|
|
202
|
-
if v.is_a?(Hash)
|
203
|
-
attr_rule.type.new(v)
|
204
|
-
else
|
205
|
-
Lutaml::Model::Type.cast(
|
206
|
-
v, attr_rule.type
|
207
|
-
)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
elsif value.is_a?(Hash) && attr_rule.type != Lutaml::Model::Type::Hash
|
211
|
-
attr_rule.type.new(value)
|
212
|
-
else
|
213
|
-
Lutaml::Model::Type.cast(value, attr_rule.type)
|
386
|
+
send(:"#{name}=", self.class.ensure_utf8(value))
|
214
387
|
end
|
215
388
|
end
|
216
389
|
|
@@ -226,119 +399,16 @@ module Lutaml
|
|
226
399
|
hash[key] || hash[key.to_sym] || hash[key.to_s]
|
227
400
|
end
|
228
401
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
# end
|
238
|
-
# adapter.new(representation).send("to_#{format}", options)
|
239
|
-
# end
|
240
|
-
# end
|
241
|
-
|
242
|
-
def to_xml(options = {})
|
243
|
-
adapter = Lutaml::Model::Config.xml_adapter
|
244
|
-
adapter.new(self).to_xml(options)
|
245
|
-
end
|
246
|
-
|
247
|
-
def to_json(options = {})
|
248
|
-
adapter = Lutaml::Model::Config.json_adapter
|
249
|
-
adapter.new(hash_representation(:json, options)).to_json(options)
|
250
|
-
end
|
251
|
-
|
252
|
-
def to_yaml(options = {})
|
253
|
-
adapter = Lutaml::Model::Config.yaml_adapter
|
254
|
-
adapter.to_yaml(self, options)
|
255
|
-
end
|
256
|
-
|
257
|
-
def to_toml(options = {})
|
258
|
-
adapter = Lutaml::Model::Config.toml_adapter
|
259
|
-
adapter.new(hash_representation(:toml, options)).to_toml
|
260
|
-
end
|
261
|
-
|
262
|
-
# TODO: END Make this work
|
263
|
-
|
264
|
-
def hash_representation(format, options = {})
|
265
|
-
only = options[:only]
|
266
|
-
except = options[:except]
|
267
|
-
mappings = self.class.mappings_for(format).mappings
|
268
|
-
|
269
|
-
mappings.each_with_object({}) do |rule, hash|
|
270
|
-
name = rule.to
|
271
|
-
next if except&.include?(name) || (only && !only.include?(name))
|
272
|
-
|
273
|
-
next handle_delegate(self, rule, hash) if rule.delegate
|
274
|
-
|
275
|
-
value = if rule.custom_methods[:to]
|
276
|
-
send(rule.custom_methods[:to], self, send(name))
|
277
|
-
else
|
278
|
-
send(name)
|
279
|
-
end
|
280
|
-
|
281
|
-
next if value.nil? && !rule.render_nil
|
282
|
-
|
283
|
-
attribute = self.class.attributes[name]
|
284
|
-
|
285
|
-
hash[rule.from] = case value
|
286
|
-
when Array
|
287
|
-
value.map do |v|
|
288
|
-
if v.is_a?(Serialize)
|
289
|
-
v.hash_representation(format, options)
|
290
|
-
else
|
291
|
-
attribute.type.serialize(v)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
else
|
295
|
-
if value.is_a?(Serialize)
|
296
|
-
value.hash_representation(format, options)
|
297
|
-
else
|
298
|
-
attribute.type.serialize(value)
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
private
|
305
|
-
|
306
|
-
def handle_delegate(_obj, rule, hash)
|
307
|
-
name = rule.to
|
308
|
-
value = send(rule.delegate).send(name)
|
309
|
-
return if value.nil? && !rule.render_nil
|
310
|
-
|
311
|
-
attribute = send(rule.delegate).class.attributes[name]
|
312
|
-
hash[rule.from] = case value
|
313
|
-
when Array
|
314
|
-
value.map do |v|
|
315
|
-
if v.is_a?(Serialize)
|
316
|
-
v.hash_representation(format, options)
|
317
|
-
else
|
318
|
-
attribute.type.serialize(v)
|
319
|
-
end
|
320
|
-
end
|
321
|
-
else
|
322
|
-
if value.is_a?(Serialize)
|
323
|
-
value.hash_representation(format, options)
|
324
|
-
else
|
325
|
-
attribute.type.serialize(value)
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
402
|
+
FORMATS.each do |format|
|
403
|
+
define_method(:"to_#{format}") do |options = {}|
|
404
|
+
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
405
|
+
representation = if format == :xml
|
406
|
+
self
|
407
|
+
else
|
408
|
+
self.class.hash_representation(self, format, options)
|
409
|
+
end
|
329
410
|
|
330
|
-
|
331
|
-
case value
|
332
|
-
when String
|
333
|
-
value.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
334
|
-
when Array
|
335
|
-
value.map { |v| ensure_utf8(v) }
|
336
|
-
when Hash
|
337
|
-
value.transform_keys do |k|
|
338
|
-
ensure_utf8(k)
|
339
|
-
end.transform_values { |v| ensure_utf8(v) }
|
340
|
-
else
|
341
|
-
value
|
411
|
+
adapter.new(representation).public_send(:"to_#{format}", options)
|
342
412
|
end
|
343
413
|
end
|
344
414
|
end
|
data/lib/lutaml/model/version.rb
CHANGED
@@ -13,11 +13,12 @@ module Lutaml
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_xml(options = {})
|
16
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
16
|
+
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
17
17
|
if root.is_a?(Lutaml::Model::XmlAdapter::NokogiriElement)
|
18
18
|
root.to_xml(xml)
|
19
19
|
else
|
20
|
-
options[:
|
20
|
+
mapper_class = options[:mapper_class] || @root.class
|
21
|
+
options[:xml_attributes] = build_namespace_attributes(mapper_class)
|
21
22
|
build_element(xml, @root, options)
|
22
23
|
end
|
23
24
|
end
|
@@ -32,7 +33,8 @@ module Lutaml
|
|
32
33
|
private
|
33
34
|
|
34
35
|
def build_unordered_element(xml, element, options = {})
|
35
|
-
|
36
|
+
mapper_class = options[:mapper_class] || element.class
|
37
|
+
xml_mapping = mapper_class.mappings_for(:xml)
|
36
38
|
return xml unless xml_mapping
|
37
39
|
|
38
40
|
attributes = options[:xml_attributes] ||= {}
|
@@ -53,7 +55,7 @@ module Lutaml
|
|
53
55
|
end
|
54
56
|
|
55
57
|
xml_mapping.elements.each do |element_rule|
|
56
|
-
attribute_def = attribute_definition_for(element, element_rule)
|
58
|
+
attribute_def = attribute_definition_for(element, element_rule, mapper_class: mapper_class)
|
57
59
|
value = attribute_value_for(element, element_rule)
|
58
60
|
|
59
61
|
next if value.nil? && !element_rule.render_nil?
|
@@ -79,7 +81,8 @@ module Lutaml
|
|
79
81
|
end
|
80
82
|
|
81
83
|
def build_ordered_element(xml, element, options = {})
|
82
|
-
|
84
|
+
mapper_class = options[:mapper_class] || element.class
|
85
|
+
xml_mapping = mapper_class.mappings_for(:xml)
|
83
86
|
return xml unless xml_mapping
|
84
87
|
|
85
88
|
attributes = build_attributes(element, xml_mapping)&.compact
|
@@ -106,7 +109,7 @@ module Lutaml
|
|
106
109
|
element_rule = xml_mapping.find_by_name(name)
|
107
110
|
next if element_rule.nil?
|
108
111
|
|
109
|
-
attribute_def = attribute_definition_for(element, element_rule)
|
112
|
+
attribute_def = attribute_definition_for(element, element_rule, mapper_class: mapper_class)
|
110
113
|
value = attribute_value_for(element, element_rule)
|
111
114
|
nsp_xml = element_rule.prefix ? xml[element_rule.prefix] : xml
|
112
115
|
|
@@ -127,7 +130,12 @@ module Lutaml
|
|
127
130
|
|
128
131
|
def add_to_xml(xml, value, attribute, rule)
|
129
132
|
if value && (attribute&.type&.<= Lutaml::Model::Serialize)
|
130
|
-
handle_nested_elements(
|
133
|
+
handle_nested_elements(
|
134
|
+
xml,
|
135
|
+
value,
|
136
|
+
rule: rule,
|
137
|
+
attribute: attribute,
|
138
|
+
)
|
131
139
|
else
|
132
140
|
xml.public_send(rule.name) do
|
133
141
|
if !value.nil?
|
@@ -14,9 +14,10 @@ module Lutaml
|
|
14
14
|
|
15
15
|
def to_xml(options = {})
|
16
16
|
builder = Ox::Builder.new
|
17
|
+
|
17
18
|
if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
|
18
19
|
@root.to_xml(builder)
|
19
|
-
elsif @root
|
20
|
+
elsif ordered?(@root, options)
|
20
21
|
build_ordered_element(builder, @root, options)
|
21
22
|
else
|
22
23
|
build_element(builder, @root, options)
|
@@ -30,7 +31,8 @@ module Lutaml
|
|
30
31
|
private
|
31
32
|
|
32
33
|
def build_unordered_element(builder, element, options = {})
|
33
|
-
|
34
|
+
mapper_class = options[:mapper_class] || element.class
|
35
|
+
xml_mapping = mapper_class.mappings_for(:xml)
|
34
36
|
return xml unless xml_mapping
|
35
37
|
|
36
38
|
attributes = build_attributes(element, xml_mapping).compact
|
@@ -45,7 +47,7 @@ module Lutaml
|
|
45
47
|
|
46
48
|
builder.element(prefixed_name, attributes) do |el|
|
47
49
|
xml_mapping.elements.each do |element_rule|
|
48
|
-
attribute_def = attribute_definition_for(element, element_rule)
|
50
|
+
attribute_def = attribute_definition_for(element, element_rule, mapper_class: mapper_class)
|
49
51
|
value = attribute_value_for(element, element_rule)
|
50
52
|
|
51
53
|
val = if attribute_def.collection?
|
@@ -58,7 +60,7 @@ module Lutaml
|
|
58
60
|
|
59
61
|
val.each do |v|
|
60
62
|
if attribute_def&.type&.<= Lutaml::Model::Serialize
|
61
|
-
handle_nested_elements(el, v, element_rule)
|
63
|
+
handle_nested_elements(el, v, rule: element_rule, attribute: attribute_def)
|
62
64
|
else
|
63
65
|
builder.element(element_rule.prefixed_name) do |el|
|
64
66
|
el.text(attribute_def.type.serialize(v)) if v
|
@@ -76,8 +78,9 @@ module Lutaml
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
def build_ordered_element(builder, element,
|
80
|
-
|
81
|
+
def build_ordered_element(builder, element, options = {})
|
82
|
+
mapper_class = options[:mapper_class] || element.class
|
83
|
+
xml_mapping = mapper_class.mappings_for(:xml)
|
81
84
|
return xml unless xml_mapping
|
82
85
|
|
83
86
|
attributes = build_attributes(element, xml_mapping).compact
|
@@ -91,7 +94,7 @@ module Lutaml
|
|
91
94
|
|
92
95
|
element_rule = xml_mapping.find_by_name(name)
|
93
96
|
|
94
|
-
attribute_def = attribute_definition_for(element, element_rule)
|
97
|
+
attribute_def = attribute_definition_for(element, element_rule, mapper_class: mapper_class)
|
95
98
|
value = attribute_value_for(element, element_rule)
|
96
99
|
|
97
100
|
if element_rule == xml_mapping.content_mapping
|
@@ -110,7 +113,12 @@ module Lutaml
|
|
110
113
|
|
111
114
|
def add_to_xml(xml, value, attribute, rule)
|
112
115
|
if value && (attribute&.type&.<= Lutaml::Model::Serialize)
|
113
|
-
handle_nested_elements(
|
116
|
+
handle_nested_elements(
|
117
|
+
xml,
|
118
|
+
value,
|
119
|
+
rule: rule,
|
120
|
+
attribute: attribute,
|
121
|
+
)
|
114
122
|
else
|
115
123
|
xml.element(rule.name) do |el|
|
116
124
|
if !value.nil?
|