lutaml-model 0.6.7 → 0.7.2
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/.github/workflows/dependent-repos-todo.json +7 -0
- data/.github/workflows/dependent-repos.json +17 -9
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +51 -65
- data/Gemfile +4 -1
- data/README.adoc +5083 -2612
- data/RELEASE_NOTES.adoc +346 -0
- data/docs/custom_adapters.adoc +144 -0
- data/lib/lutaml/model/attribute.rb +101 -16
- data/lib/lutaml/model/choice.rb +7 -0
- data/lib/lutaml/model/comparable_model.rb +48 -9
- data/lib/lutaml/model/config.rb +48 -42
- data/lib/lutaml/model/error/collection_count_out_of_range_error.rb +1 -1
- data/lib/lutaml/model/error/polymorphic_error.rb +14 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/format_registry.rb +41 -0
- data/lib/lutaml/model/hash/document.rb +11 -0
- data/lib/lutaml/model/hash/mapping.rb +19 -0
- data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
- data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
- data/lib/lutaml/model/hash/transform.rb +8 -0
- data/lib/lutaml/model/hash.rb +21 -0
- data/lib/lutaml/model/json/document.rb +11 -0
- data/lib/lutaml/model/json/mapping.rb +19 -0
- data/lib/lutaml/model/json/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
- data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
- data/lib/lutaml/model/json/transform.rb +8 -0
- data/lib/lutaml/model/json.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +27 -0
- data/lib/lutaml/model/{key_value_mapping.rb → mapping/key_value_mapping.rb} +64 -16
- data/lib/lutaml/model/{key_value_mapping_rule.rb → mapping/key_value_mapping_rule.rb} +18 -2
- data/lib/lutaml/model/mapping/mapping.rb +13 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +300 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +15 -15
- data/lib/lutaml/model/sequence.rb +2 -2
- data/lib/lutaml/model/serialization_adapter.rb +22 -0
- data/lib/lutaml/model/serialize.rb +219 -444
- data/lib/lutaml/model/services/logger.rb +54 -0
- data/lib/lutaml/model/services/transformer.rb +48 -0
- data/lib/lutaml/model/services.rb +2 -0
- data/lib/lutaml/model/toml/document.rb +11 -0
- data/lib/lutaml/model/toml/mapping.rb +27 -0
- data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
- data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
- data/lib/lutaml/model/toml/transform.rb +8 -0
- data/lib/lutaml/model/toml.rb +30 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
- data/lib/lutaml/model/transform/xml_transform.rb +239 -0
- data/lib/lutaml/model/transform.rb +78 -0
- data/lib/lutaml/model/type/date.rb +1 -1
- data/lib/lutaml/model/type/date_time.rb +2 -2
- data/lib/lutaml/model/type/hash.rb +1 -1
- data/lib/lutaml/model/type/time.rb +2 -2
- data/lib/lutaml/model/type/time_without_date.rb +2 -2
- data/lib/lutaml/model/type/value.rb +6 -9
- data/lib/lutaml/model/uninitialized_class.rb +64 -0
- data/lib/lutaml/model/utils.rb +44 -0
- data/lib/lutaml/model/validation.rb +1 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
- data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
- data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
- data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +41 -21
- data/lib/lutaml/model/xml/element.rb +32 -0
- data/lib/lutaml/model/xml/mapping.rb +410 -0
- data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
- data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
- data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
- data/lib/lutaml/model/xml/transform.rb +8 -0
- data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +23 -10
- data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
- data/lib/lutaml/model/xml.rb +31 -0
- data/lib/lutaml/model/xml_adapter/element.rb +11 -25
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
- data/lib/lutaml/model/yaml/document.rb +10 -0
- data/lib/lutaml/model/yaml/mapping.rb +19 -0
- data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
- data/lib/lutaml/model/yaml/transform.rb +8 -0
- data/lib/lutaml/model/yaml.rb +21 -0
- data/lib/lutaml/model.rb +40 -4
- data/lutaml-model.gemspec +0 -4
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +7 -7
- data/spec/fixtures/person.rb +5 -5
- data/spec/lutaml/model/attribute_spec.rb +37 -1
- data/spec/lutaml/model/cdata_spec.rb +9 -9
- data/spec/lutaml/model/collection_spec.rb +50 -2
- data/spec/lutaml/model/comparable_model_spec.rb +92 -27
- data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
- data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
- data/spec/lutaml/model/defaults_spec.rb +1 -1
- data/spec/lutaml/model/enum_spec.rb +1 -1
- data/spec/lutaml/model/group_spec.rb +333 -20
- data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
- data/spec/lutaml/model/json_adapter_spec.rb +6 -6
- data/spec/lutaml/model/key_value_mapping_spec.rb +65 -3
- data/spec/lutaml/model/mixed_content_spec.rb +24 -24
- data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
- data/spec/lutaml/model/ordered_content_spec.rb +6 -6
- data/spec/lutaml/model/polymorphic_spec.rb +526 -0
- data/spec/lutaml/model/render_empty_spec.rb +194 -0
- data/spec/lutaml/model/render_nil_spec.rb +206 -22
- data/spec/lutaml/model/root_mappings_spec.rb +3 -3
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
- data/spec/lutaml/model/serializable_spec.rb +179 -103
- data/spec/lutaml/model/simple_model_spec.rb +9 -9
- data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/toml_spec.rb +51 -0
- data/spec/lutaml/model/transformation_spec.rb +72 -15
- data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
- data/spec/lutaml/model/value_map_spec.rb +240 -0
- data/spec/lutaml/model/xml/namespace/nested_with_explicit_namespace_spec.rb +85 -0
- data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
- data/spec/lutaml/model/xml/xml_element_spec.rb +93 -0
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +105 -5
- data/spec/lutaml/model/xml_mapping_spec.rb +70 -16
- data/spec/lutaml/model/xml_spec.rb +63 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
- data/spec/sample_model_spec.rb +3 -3
- data/spec/spec_helper.rb +3 -3
- metadata +76 -59
- data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
- data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
- data/lib/lutaml/model/loggable.rb +0 -15
- data/lib/lutaml/model/mapping_rule.rb +0 -109
- data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
- data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
- data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
- data/lib/lutaml/model/toml_adapter.rb +0 -6
- data/lib/lutaml/model/xml_mapping.rb +0 -307
- data/lib/lutaml/model/xml_mapping_rule.rb +0 -122
- data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
- data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
- data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -6,8 +6,8 @@ require_relative "element"
|
|
6
6
|
|
7
7
|
module Lutaml
|
8
8
|
module Model
|
9
|
-
module
|
10
|
-
class
|
9
|
+
module Xml
|
10
|
+
class Document
|
11
11
|
attr_reader :root, :encoding
|
12
12
|
|
13
13
|
def initialize(root, encoding = nil)
|
@@ -154,11 +154,11 @@ module Lutaml
|
|
154
154
|
end
|
155
155
|
|
156
156
|
# Only transform when recursion is not called
|
157
|
-
if
|
158
|
-
value =
|
157
|
+
if !attribute.collection? || value.is_a?(Array)
|
158
|
+
value = ExportTransformer.call(value, rule, attribute)
|
159
159
|
end
|
160
160
|
|
161
|
-
if value.is_a?(Array)
|
161
|
+
if value.is_a?(Array) && !Utils.empty_collection?(value)
|
162
162
|
value.each do |item|
|
163
163
|
add_to_xml(xml, element, prefix, item, options)
|
164
164
|
end
|
@@ -168,12 +168,18 @@ module Lutaml
|
|
168
168
|
|
169
169
|
return if !render_element?(rule, element, value)
|
170
170
|
|
171
|
+
value = rule.render_value_for(value)
|
172
|
+
|
171
173
|
if value && (attribute&.type&.<= Lutaml::Model::Serialize)
|
172
174
|
handle_nested_elements(
|
173
175
|
xml,
|
174
176
|
value,
|
175
177
|
options.merge({ rule: rule, attribute: attribute }),
|
176
178
|
)
|
179
|
+
elsif value.nil?
|
180
|
+
xml.create_and_add_element(rule.name, attributes: { "xsi:nil" => true })
|
181
|
+
elsif Utils.empty?(value)
|
182
|
+
xml.create_and_add_element(rule.name)
|
177
183
|
elsif rule.raw_mapping?
|
178
184
|
xml.add_xml_fragment(xml, value)
|
179
185
|
elsif rule.prefix_set?
|
@@ -205,19 +211,12 @@ module Lutaml
|
|
205
211
|
end
|
206
212
|
|
207
213
|
def build_unordered_element(xml, element, options = {})
|
208
|
-
mapper_class = options
|
214
|
+
mapper_class = determine_mapper_class(element, options)
|
209
215
|
xml_mapping = mapper_class.mappings_for(:xml)
|
210
216
|
return xml unless xml_mapping
|
211
217
|
|
212
|
-
attributes =
|
213
|
-
|
214
|
-
xml_mapping, options).merge(attributes)&.compact
|
215
|
-
|
216
|
-
prefix = if options.key?(:namespace_prefix)
|
217
|
-
options[:namespace_prefix]
|
218
|
-
elsif xml_mapping.namespace_prefix
|
219
|
-
xml_mapping.namespace_prefix
|
220
|
-
end
|
218
|
+
attributes = build_element_attributes(element, xml_mapping, options)
|
219
|
+
prefix = determine_namespace_prefix(options, xml_mapping)
|
221
220
|
|
222
221
|
prefixed_xml = xml.add_namespace_prefix(prefix)
|
223
222
|
tag_name = options[:tag_name] || xml_mapping.root_element
|
@@ -241,7 +240,7 @@ module Lutaml
|
|
241
240
|
if attribute_def
|
242
241
|
value = attribute_value_for(element, element_rule)
|
243
242
|
|
244
|
-
next if
|
243
|
+
next if !element_rule.render?(value, element)
|
245
244
|
|
246
245
|
value = [value] if attribute_def.collection? && !value.is_a?(Array)
|
247
246
|
end
|
@@ -289,11 +288,7 @@ module Lutaml
|
|
289
288
|
end
|
290
289
|
|
291
290
|
def render_element?(rule, element, value)
|
292
|
-
|
293
|
-
end
|
294
|
-
|
295
|
-
def render_value?(rule, value)
|
296
|
-
rule.attribute? || rule.render_nil? || !value.nil?
|
291
|
+
rule.render?(value, element)
|
297
292
|
end
|
298
293
|
|
299
294
|
def render_default?(rule, element)
|
@@ -370,6 +365,8 @@ module Lutaml
|
|
370
365
|
attr = attribute_definition_for(element, mapping_rule, mapper_class: options[:mapper_class])
|
371
366
|
value = attr.serialize(value, :xml) if attr
|
372
367
|
|
368
|
+
value = ExportTransformer.call(value, mapping_rule, attr)
|
369
|
+
|
373
370
|
if render_element?(mapping_rule, element, value)
|
374
371
|
hash[mapping_rule.prefixed_name] = value ? value.to_s : value
|
375
372
|
end
|
@@ -433,6 +430,29 @@ module Lutaml
|
|
433
430
|
def cdata
|
434
431
|
@root.cdata
|
435
432
|
end
|
433
|
+
|
434
|
+
private
|
435
|
+
|
436
|
+
def determine_mapper_class(element, options)
|
437
|
+
if options[:mapper_class] && element.is_a?(options[:mapper_class])
|
438
|
+
element.class
|
439
|
+
else
|
440
|
+
options[:mapper_class] || element.class
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def determine_namespace_prefix(options, mapping)
|
445
|
+
return options[:namespace_prefix] if options.key?(:namespace_prefix)
|
446
|
+
|
447
|
+
mapping.namespace_prefix
|
448
|
+
end
|
449
|
+
|
450
|
+
def build_element_attributes(element, mapping, options)
|
451
|
+
xml_attributes = options[:xml_attributes] ||= {}
|
452
|
+
attributes = build_attributes(element, mapping, options)
|
453
|
+
|
454
|
+
attributes.merge(xml_attributes)&.compact
|
455
|
+
end
|
436
456
|
end
|
437
457
|
end
|
438
458
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
module Xml
|
4
|
+
class Element
|
5
|
+
attr_reader :type, :name
|
6
|
+
|
7
|
+
def initialize(type, name)
|
8
|
+
@type = type
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def text?
|
13
|
+
@type == "Text" && @name != "#cdata-section"
|
14
|
+
end
|
15
|
+
|
16
|
+
def element_tag
|
17
|
+
@name unless text?
|
18
|
+
end
|
19
|
+
|
20
|
+
def eql?(other)
|
21
|
+
return false unless other.is_a?(self.class)
|
22
|
+
|
23
|
+
instance_variables.all? do |var|
|
24
|
+
instance_variable_get(var) == other.instance_variable_get(var)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
alias == eql?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,410 @@
|
|
1
|
+
require_relative "../mapping/mapping"
|
2
|
+
require_relative "mapping_rule"
|
3
|
+
|
4
|
+
module Lutaml
|
5
|
+
module Model
|
6
|
+
module Xml
|
7
|
+
class Mapping < Mapping
|
8
|
+
TYPES = {
|
9
|
+
attribute: :map_attribute,
|
10
|
+
element: :map_element,
|
11
|
+
content: :map_content,
|
12
|
+
all_content: :map_all,
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader :root_element,
|
16
|
+
:namespace_uri,
|
17
|
+
:namespace_prefix,
|
18
|
+
:mixed_content,
|
19
|
+
:ordered,
|
20
|
+
:element_sequence
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
|
25
|
+
@elements = {}
|
26
|
+
@attributes = {}
|
27
|
+
@element_sequence = []
|
28
|
+
@content_mapping = nil
|
29
|
+
@raw_mapping = nil
|
30
|
+
@mixed_content = false
|
31
|
+
@format = :xml
|
32
|
+
end
|
33
|
+
|
34
|
+
def finalize(mapper_class)
|
35
|
+
if !root_element && !no_root?
|
36
|
+
root(mapper_class.model.to_s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias mixed_content? mixed_content
|
41
|
+
alias ordered? ordered
|
42
|
+
|
43
|
+
def root(name, mixed: false, ordered: false)
|
44
|
+
@root_element = name
|
45
|
+
@mixed_content = mixed
|
46
|
+
@ordered = ordered || mixed # mixed contenet will always be ordered
|
47
|
+
end
|
48
|
+
|
49
|
+
def root?
|
50
|
+
!!root_element
|
51
|
+
end
|
52
|
+
|
53
|
+
def no_root
|
54
|
+
@no_root = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def no_root?
|
58
|
+
!!@no_root
|
59
|
+
end
|
60
|
+
|
61
|
+
def prefixed_root
|
62
|
+
if namespace_uri && namespace_prefix
|
63
|
+
"#{namespace_prefix}:#{root_element}"
|
64
|
+
else
|
65
|
+
root_element
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def namespace(uri, prefix = nil)
|
70
|
+
raise Lutaml::Model::NoRootNamespaceError if no_root?
|
71
|
+
|
72
|
+
@namespace_uri = uri
|
73
|
+
@namespace_prefix = prefix
|
74
|
+
end
|
75
|
+
|
76
|
+
# rubocop:disable Metrics/ParameterLists
|
77
|
+
def map_element(
|
78
|
+
name,
|
79
|
+
to: nil,
|
80
|
+
render_nil: false,
|
81
|
+
render_default: false,
|
82
|
+
render_empty: false,
|
83
|
+
treat_nil: :nil,
|
84
|
+
treat_empty: :empty,
|
85
|
+
treat_omitted: :nil,
|
86
|
+
with: {},
|
87
|
+
delegate: nil,
|
88
|
+
cdata: false,
|
89
|
+
polymorphic: {},
|
90
|
+
namespace: (namespace_set = false
|
91
|
+
nil),
|
92
|
+
prefix: (prefix_set = false
|
93
|
+
nil),
|
94
|
+
transform: {},
|
95
|
+
value_map: {}
|
96
|
+
)
|
97
|
+
validate!(
|
98
|
+
name, to, with, render_nil, render_empty, type: TYPES[:element]
|
99
|
+
)
|
100
|
+
|
101
|
+
rule = MappingRule.new(
|
102
|
+
name,
|
103
|
+
to: to,
|
104
|
+
render_nil: render_nil,
|
105
|
+
render_default: render_default,
|
106
|
+
render_empty: render_empty,
|
107
|
+
treat_nil: treat_nil,
|
108
|
+
treat_empty: treat_empty,
|
109
|
+
treat_omitted: treat_omitted,
|
110
|
+
with: with,
|
111
|
+
delegate: delegate,
|
112
|
+
cdata: cdata,
|
113
|
+
namespace: namespace,
|
114
|
+
default_namespace: namespace_uri,
|
115
|
+
prefix: prefix,
|
116
|
+
polymorphic: polymorphic,
|
117
|
+
namespace_set: namespace_set != false,
|
118
|
+
prefix_set: prefix_set != false,
|
119
|
+
transform: transform,
|
120
|
+
value_map: value_map,
|
121
|
+
)
|
122
|
+
@elements[rule.namespaced_name] = rule
|
123
|
+
end
|
124
|
+
|
125
|
+
def map_attribute(
|
126
|
+
name,
|
127
|
+
to: nil,
|
128
|
+
render_nil: false,
|
129
|
+
render_default: false,
|
130
|
+
render_empty: false,
|
131
|
+
with: {},
|
132
|
+
delegate: nil,
|
133
|
+
polymorphic_map: {},
|
134
|
+
namespace: (namespace_set = false
|
135
|
+
nil),
|
136
|
+
prefix: (prefix_set = false
|
137
|
+
nil),
|
138
|
+
transform: {},
|
139
|
+
value_map: {}
|
140
|
+
)
|
141
|
+
validate!(
|
142
|
+
name, to, with, render_nil, render_empty, type: TYPES[:attribute]
|
143
|
+
)
|
144
|
+
|
145
|
+
if name == "schemaLocation"
|
146
|
+
Logger.warn_auto_handling(
|
147
|
+
name: name,
|
148
|
+
caller_file: File.basename(caller_locations(1, 1)[0].path),
|
149
|
+
caller_line: caller_locations(1, 1)[0].lineno,
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
rule = MappingRule.new(
|
154
|
+
name,
|
155
|
+
to: to,
|
156
|
+
render_nil: render_nil,
|
157
|
+
render_default: render_default,
|
158
|
+
with: with,
|
159
|
+
delegate: delegate,
|
160
|
+
namespace: namespace,
|
161
|
+
prefix: prefix,
|
162
|
+
attribute: true,
|
163
|
+
polymorphic_map: polymorphic_map,
|
164
|
+
default_namespace: namespace_uri,
|
165
|
+
namespace_set: namespace_set != false,
|
166
|
+
prefix_set: prefix_set != false,
|
167
|
+
transform: transform,
|
168
|
+
value_map: value_map,
|
169
|
+
)
|
170
|
+
@attributes[rule.namespaced_name] = rule
|
171
|
+
end
|
172
|
+
|
173
|
+
# rubocop:enable Metrics/ParameterLists
|
174
|
+
|
175
|
+
def map_content(
|
176
|
+
to: nil,
|
177
|
+
render_nil: false,
|
178
|
+
render_default: false,
|
179
|
+
render_empty: false,
|
180
|
+
with: {},
|
181
|
+
delegate: nil,
|
182
|
+
mixed: false,
|
183
|
+
cdata: false,
|
184
|
+
transform: {},
|
185
|
+
value_map: {}
|
186
|
+
)
|
187
|
+
validate!(
|
188
|
+
"content", to, with, render_nil, render_empty, type: TYPES[:content]
|
189
|
+
)
|
190
|
+
|
191
|
+
@content_mapping = MappingRule.new(
|
192
|
+
nil,
|
193
|
+
to: to,
|
194
|
+
render_nil: render_nil,
|
195
|
+
render_default: render_default,
|
196
|
+
render_empty: render_empty,
|
197
|
+
with: with,
|
198
|
+
delegate: delegate,
|
199
|
+
mixed_content: mixed,
|
200
|
+
cdata: cdata,
|
201
|
+
transform: transform,
|
202
|
+
value_map: value_map,
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
def map_all(
|
207
|
+
to:,
|
208
|
+
render_nil: false,
|
209
|
+
render_default: false,
|
210
|
+
delegate: nil,
|
211
|
+
with: {},
|
212
|
+
namespace: (namespace_set = false
|
213
|
+
nil),
|
214
|
+
prefix: (prefix_set = false
|
215
|
+
nil),
|
216
|
+
render_empty: false
|
217
|
+
)
|
218
|
+
validate!(
|
219
|
+
Constants::RAW_MAPPING_KEY,
|
220
|
+
to,
|
221
|
+
with,
|
222
|
+
render_nil,
|
223
|
+
render_empty,
|
224
|
+
type: TYPES[:all_content],
|
225
|
+
)
|
226
|
+
|
227
|
+
rule = MappingRule.new(
|
228
|
+
Constants::RAW_MAPPING_KEY,
|
229
|
+
to: to,
|
230
|
+
render_nil: render_nil,
|
231
|
+
render_default: render_default,
|
232
|
+
with: with,
|
233
|
+
delegate: delegate,
|
234
|
+
namespace: namespace,
|
235
|
+
prefix: prefix,
|
236
|
+
default_namespace: namespace_uri,
|
237
|
+
namespace_set: namespace_set != false,
|
238
|
+
prefix_set: prefix_set != false,
|
239
|
+
)
|
240
|
+
|
241
|
+
@raw_mapping = rule
|
242
|
+
end
|
243
|
+
|
244
|
+
alias map_all_content map_all
|
245
|
+
|
246
|
+
def sequence(&block)
|
247
|
+
@element_sequence << Sequence.new(self).tap do |s|
|
248
|
+
s.instance_eval(&block)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def import_model_mappings(model)
|
253
|
+
raise Lutaml::Model::ImportModelWithRootError.new(model) if model.root?
|
254
|
+
|
255
|
+
mappings = model.mappings_for(:xml)
|
256
|
+
@elements.merge!(mappings.instance_variable_get(:@elements))
|
257
|
+
@attributes.merge!(mappings.instance_variable_get(:@attributes))
|
258
|
+
(@element_sequence << mappings.element_sequence).flatten!
|
259
|
+
end
|
260
|
+
|
261
|
+
def validate!(key, to, with, render_nil, render_empty, type: nil)
|
262
|
+
validate_raw_mappings!(type)
|
263
|
+
validate_to_and_with_arguments!(key, to, with)
|
264
|
+
|
265
|
+
if render_nil == :as_empty || render_empty == :as_empty
|
266
|
+
raise IncorrectMappingArgumentsError.new(
|
267
|
+
":as_empty is not supported for XML mappings",
|
268
|
+
)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def validate_to_and_with_arguments!(key, to, with)
|
273
|
+
if to.nil? && with.empty?
|
274
|
+
raise IncorrectMappingArgumentsError.new(
|
275
|
+
":to or :with argument is required for mapping '#{key}'",
|
276
|
+
)
|
277
|
+
end
|
278
|
+
|
279
|
+
validate_with_options!(key, to, with)
|
280
|
+
end
|
281
|
+
|
282
|
+
def validate_with_options!(key, to, with)
|
283
|
+
return true if to
|
284
|
+
|
285
|
+
if !with.empty? && (with[:from].nil? || with[:to].nil?)
|
286
|
+
raise IncorrectMappingArgumentsError.new(
|
287
|
+
":with argument for mapping '#{key}' requires :to and :from keys",
|
288
|
+
)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def validate_raw_mappings!(type)
|
293
|
+
if !@raw_mapping.nil? && type != TYPES[:attribute]
|
294
|
+
raise StandardError, "#{type} is not allowed, only #{TYPES[:attribute]} " \
|
295
|
+
"is allowed with #{TYPES[:all_content]}"
|
296
|
+
end
|
297
|
+
|
298
|
+
if !(elements.empty? && content_mapping.nil?) && type == TYPES[:all_content]
|
299
|
+
raise StandardError, "#{TYPES[:all_content]} is not allowed with other mappings"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def elements
|
304
|
+
@elements.values
|
305
|
+
end
|
306
|
+
|
307
|
+
def attributes
|
308
|
+
@attributes.values
|
309
|
+
end
|
310
|
+
|
311
|
+
def content_mapping
|
312
|
+
@content_mapping
|
313
|
+
end
|
314
|
+
|
315
|
+
def raw_mapping
|
316
|
+
@raw_mapping
|
317
|
+
end
|
318
|
+
|
319
|
+
def mappings
|
320
|
+
elements + attributes + [content_mapping, raw_mapping].compact
|
321
|
+
end
|
322
|
+
|
323
|
+
def element(name)
|
324
|
+
elements.detect do |rule|
|
325
|
+
name == rule.to
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def attribute(name)
|
330
|
+
attributes.detect do |rule|
|
331
|
+
name == rule.to
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def find_by_name(name)
|
336
|
+
if ["text", "#cdata-section"].include?(name.to_s)
|
337
|
+
content_mapping
|
338
|
+
else
|
339
|
+
mappings.detect do |rule|
|
340
|
+
rule.name == name.to_s || rule.name == name.to_sym
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def mapping_attributes_hash
|
346
|
+
@attributes
|
347
|
+
end
|
348
|
+
|
349
|
+
def mapping_elements_hash
|
350
|
+
@elements
|
351
|
+
end
|
352
|
+
|
353
|
+
def merge_mapping_attributes(mapping)
|
354
|
+
mapping_attributes_hash.merge!(mapping.mapping_attributes_hash)
|
355
|
+
end
|
356
|
+
|
357
|
+
def merge_mapping_elements(mapping)
|
358
|
+
mapping_elements_hash.merge!(mapping.mapping_elements_hash)
|
359
|
+
end
|
360
|
+
|
361
|
+
def merge_elements_sequence(mapping)
|
362
|
+
mapping.element_sequence.each do |sequence|
|
363
|
+
element_sequence << Lutaml::Model::Sequence.new(self).tap do |instance|
|
364
|
+
sequence.attributes.each do |attr|
|
365
|
+
instance.attributes << attr.deep_dup
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def deep_dup
|
372
|
+
self.class.new.tap do |xml_mapping|
|
373
|
+
xml_mapping.root(@root_element.dup, mixed: @mixed_content,
|
374
|
+
ordered: @ordered)
|
375
|
+
xml_mapping.namespace(@namespace_uri.dup, @namespace_prefix.dup)
|
376
|
+
|
377
|
+
attributes_to_dup.each do |var_name|
|
378
|
+
value = instance_variable_get(var_name)
|
379
|
+
xml_mapping.instance_variable_set(var_name, Utils.deep_dup(value))
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def polymorphic_mapping
|
385
|
+
mappings.find(&:polymorphic_mapping?)
|
386
|
+
end
|
387
|
+
|
388
|
+
def attributes_to_dup
|
389
|
+
@attributes_to_dup ||= %i[
|
390
|
+
@content_mapping
|
391
|
+
@raw_mapping
|
392
|
+
@element_sequence
|
393
|
+
@attributes
|
394
|
+
@elements
|
395
|
+
]
|
396
|
+
end
|
397
|
+
|
398
|
+
def dup_mappings(mappings)
|
399
|
+
new_mappings = {}
|
400
|
+
|
401
|
+
mappings.each do |key, mapping_rule|
|
402
|
+
new_mappings[key] = mapping_rule.deep_dup
|
403
|
+
end
|
404
|
+
|
405
|
+
new_mappings
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require_relative "../mapping/mapping_rule"
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Xml
|
6
|
+
class MappingRule < MappingRule
|
7
|
+
attr_reader :namespace, :prefix, :mixed_content, :default_namespace, :cdata
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
name,
|
11
|
+
to:,
|
12
|
+
render_nil: false,
|
13
|
+
render_default: false,
|
14
|
+
render_empty: false,
|
15
|
+
treat_nil: nil,
|
16
|
+
treat_empty: nil,
|
17
|
+
treat_omitted: nil,
|
18
|
+
with: {},
|
19
|
+
delegate: nil,
|
20
|
+
namespace: nil,
|
21
|
+
prefix: nil,
|
22
|
+
mixed_content: false,
|
23
|
+
cdata: false,
|
24
|
+
namespace_set: false,
|
25
|
+
prefix_set: false,
|
26
|
+
attribute: false,
|
27
|
+
default_namespace: nil,
|
28
|
+
polymorphic: {},
|
29
|
+
polymorphic_map: {},
|
30
|
+
transform: {},
|
31
|
+
value_map: {}
|
32
|
+
)
|
33
|
+
super(
|
34
|
+
name,
|
35
|
+
to: to,
|
36
|
+
render_nil: render_nil,
|
37
|
+
render_default: render_default,
|
38
|
+
render_empty: render_empty,
|
39
|
+
treat_nil: treat_nil,
|
40
|
+
treat_empty: treat_empty,
|
41
|
+
treat_omitted: treat_omitted,
|
42
|
+
with: with,
|
43
|
+
delegate: delegate,
|
44
|
+
attribute: attribute,
|
45
|
+
polymorphic: polymorphic,
|
46
|
+
polymorphic_map: polymorphic_map,
|
47
|
+
transform: transform,
|
48
|
+
value_map: value_map,
|
49
|
+
)
|
50
|
+
|
51
|
+
@namespace = if namespace.to_s == "inherit"
|
52
|
+
# we are using inherit_namespace in xml builder by
|
53
|
+
# default so no need to do anything here.
|
54
|
+
else
|
55
|
+
namespace
|
56
|
+
end
|
57
|
+
@prefix = prefix
|
58
|
+
@mixed_content = mixed_content
|
59
|
+
@cdata = cdata
|
60
|
+
|
61
|
+
@default_namespace = default_namespace
|
62
|
+
|
63
|
+
@namespace_set = namespace_set
|
64
|
+
@prefix_set = prefix_set
|
65
|
+
end
|
66
|
+
|
67
|
+
def namespace_set?
|
68
|
+
!!@namespace_set
|
69
|
+
end
|
70
|
+
|
71
|
+
def prefix_set?
|
72
|
+
!!@prefix_set
|
73
|
+
end
|
74
|
+
|
75
|
+
def content_mapping?
|
76
|
+
name.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
def content_key
|
80
|
+
cdata ? "#cdata-section" : "text"
|
81
|
+
end
|
82
|
+
|
83
|
+
def mixed_content?
|
84
|
+
!!@mixed_content
|
85
|
+
end
|
86
|
+
|
87
|
+
def prefixed_name
|
88
|
+
rule_name = multiple_mappings? ? name.first : name
|
89
|
+
if prefix
|
90
|
+
"#{prefix}:#{rule_name}"
|
91
|
+
else
|
92
|
+
rule_name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def namespaced_names(parent_namespace = nil)
|
97
|
+
if multiple_mappings?
|
98
|
+
name.map { |rule_name| namespaced_name(parent_namespace, rule_name) }
|
99
|
+
else
|
100
|
+
[namespaced_name(parent_namespace)]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def namespaced_name(parent_namespace = nil, name = self.name)
|
105
|
+
if name.to_s == "lang"
|
106
|
+
"#{prefix}:#{name}"
|
107
|
+
elsif namespace_set? || @attribute
|
108
|
+
[namespace, name].compact.join(":")
|
109
|
+
elsif default_namespace
|
110
|
+
"#{default_namespace}:#{name}"
|
111
|
+
else
|
112
|
+
[parent_namespace, name].compact.join(":")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def deep_dup
|
117
|
+
self.class.new(
|
118
|
+
name.dup,
|
119
|
+
to: to,
|
120
|
+
render_nil: render_nil,
|
121
|
+
render_default: render_default,
|
122
|
+
with: Utils.deep_dup(custom_methods),
|
123
|
+
delegate: delegate,
|
124
|
+
namespace: namespace.dup,
|
125
|
+
prefix: prefix.dup,
|
126
|
+
mixed_content: mixed_content,
|
127
|
+
cdata: cdata,
|
128
|
+
namespace_set: namespace_set?,
|
129
|
+
prefix_set: prefix_set?,
|
130
|
+
attribute: attribute,
|
131
|
+
polymorphic: polymorphic.dup,
|
132
|
+
default_namespace: default_namespace.dup,
|
133
|
+
transform: transform.dup,
|
134
|
+
render_empty: render_empty.dup,
|
135
|
+
value_map: Utils.deep_dup(@value_map),
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|