lutaml-model 0.5.4 → 0.6.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/.rubocop_todo.yml +58 -21
- data/Gemfile +1 -0
- data/README.adoc +1112 -264
- data/lib/lutaml/model/attribute.rb +37 -15
- data/lib/lutaml/model/choice.rb +56 -0
- data/lib/lutaml/model/config.rb +1 -0
- data/lib/lutaml/model/error/choice_lower_bound_error.rb +9 -0
- data/lib/lutaml/model/error/choice_upper_bound_error.rb +9 -0
- data/lib/lutaml/model/error/import_model_with_root_error.rb +9 -0
- data/lib/lutaml/model/error/incorrect_sequence_error.rb +9 -0
- data/lib/lutaml/model/error/invalid_choice_range_error.rb +20 -0
- data/lib/lutaml/model/error/no_root_mapping_error.rb +9 -0
- data/lib/lutaml/model/error/no_root_namespace_error.rb +9 -0
- data/lib/lutaml/model/error/unknown_sequence_mapping_error.rb +9 -0
- data/lib/lutaml/model/error.rb +8 -0
- data/lib/lutaml/model/json_adapter/standard_json_adapter.rb +6 -1
- data/lib/lutaml/model/key_value_mapping.rb +3 -1
- data/lib/lutaml/model/key_value_mapping_rule.rb +4 -2
- data/lib/lutaml/model/liquefiable.rb +59 -0
- data/lib/lutaml/model/mapping_hash.rb +1 -1
- data/lib/lutaml/model/mapping_rule.rb +15 -2
- data/lib/lutaml/model/schema/xml_compiler.rb +68 -26
- data/lib/lutaml/model/schema_location.rb +7 -0
- data/lib/lutaml/model/sequence.rb +71 -0
- data/lib/lutaml/model/serialize.rb +126 -38
- data/lib/lutaml/model/type/decimal.rb +0 -4
- data/lib/lutaml/model/type/time.rb +3 -3
- data/lib/lutaml/model/utils.rb +19 -15
- data/lib/lutaml/model/validation.rb +12 -1
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/oga.rb +10 -7
- data/lib/lutaml/model/xml_adapter/builder/ox.rb +20 -13
- data/lib/lutaml/model/xml_adapter/element.rb +32 -0
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +8 -8
- data/lib/lutaml/model/xml_adapter/oga/element.rb +14 -13
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +86 -19
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +19 -15
- data/lib/lutaml/model/xml_adapter/xml_document.rb +74 -13
- data/lib/lutaml/model/xml_adapter/xml_element.rb +57 -3
- data/lib/lutaml/model/xml_mapping.rb +49 -7
- data/lib/lutaml/model/xml_mapping_rule.rb +8 -3
- data/lib/lutaml/model.rb +1 -0
- data/lutaml-model.gemspec +5 -0
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +75 -0
- data/spec/ceramic_spec.rb +39 -0
- data/spec/fixtures/ceramic.rb +23 -0
- data/spec/fixtures/xml/address_example_260.xsd +9 -0
- data/spec/fixtures/xml/user.xsd +10 -0
- data/spec/lutaml/model/cdata_spec.rb +4 -5
- data/spec/lutaml/model/choice_spec.rb +168 -0
- data/spec/lutaml/model/collection_spec.rb +1 -1
- data/spec/lutaml/model/custom_model_spec.rb +55 -8
- data/spec/lutaml/model/custom_serialization_spec.rb +74 -2
- data/spec/lutaml/model/defaults_spec.rb +3 -1
- data/spec/lutaml/model/delegation_spec.rb +7 -5
- data/spec/lutaml/model/enum_spec.rb +35 -0
- data/spec/lutaml/model/group_spec.rb +160 -0
- data/spec/lutaml/model/inheritance_spec.rb +25 -0
- data/spec/lutaml/model/liquefiable_spec.rb +121 -0
- data/spec/lutaml/model/mixed_content_spec.rb +80 -41
- data/spec/lutaml/model/multiple_mapping_spec.rb +22 -10
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +218 -25
- data/spec/lutaml/model/sequence_spec.rb +216 -0
- data/spec/lutaml/model/transformation_spec.rb +230 -0
- data/spec/lutaml/model/type_spec.rb +138 -31
- data/spec/lutaml/model/utils_spec.rb +32 -0
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -7
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +51 -0
- data/spec/lutaml/model/xml_mapping_spec.rb +167 -112
- metadata +67 -2
@@ -6,21 +6,22 @@ module Lutaml
|
|
6
6
|
module Oga
|
7
7
|
class Element < XmlElement
|
8
8
|
def initialize(node, parent: nil)
|
9
|
-
|
10
|
-
when ::
|
11
|
-
namespace_name = node.
|
9
|
+
text = case node
|
10
|
+
when Moxml::Element
|
11
|
+
namespace_name = node.namespace&.prefix
|
12
12
|
add_namespaces(node)
|
13
13
|
children = parse_children(node)
|
14
14
|
attributes = node_attributes(node)
|
15
|
-
node
|
16
|
-
|
17
|
-
|
15
|
+
@root = node
|
16
|
+
node.inner_text
|
17
|
+
when Moxml::Text
|
18
|
+
node.content
|
18
19
|
end
|
19
20
|
super(
|
20
|
-
|
21
|
+
OgaAdapter.name_of(node),
|
21
22
|
Hash(attributes),
|
22
23
|
Array(children),
|
23
|
-
|
24
|
+
text,
|
24
25
|
parent_document: parent,
|
25
26
|
namespace_prefix: namespace_name,
|
26
27
|
)
|
@@ -31,7 +32,7 @@ module Lutaml
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def text
|
34
|
-
@text
|
35
|
+
super || @text
|
35
36
|
end
|
36
37
|
|
37
38
|
def to_xml(builder = Builder::Oga.build)
|
@@ -61,7 +62,7 @@ module Lutaml
|
|
61
62
|
next if attr_is_namespace?(attr)
|
62
63
|
|
63
64
|
name = if attr.namespace
|
64
|
-
"#{attr.namespace.
|
65
|
+
"#{attr.namespace.prefix}:#{attr.name}"
|
65
66
|
else
|
66
67
|
attr.name
|
67
68
|
end
|
@@ -69,7 +70,7 @@ module Lutaml
|
|
69
70
|
name,
|
70
71
|
attr.value,
|
71
72
|
namespace: attr.namespace&.uri,
|
72
|
-
namespace_prefix: attr.namespace&.
|
73
|
+
namespace_prefix: attr.namespace&.prefix,
|
73
74
|
)
|
74
75
|
end
|
75
76
|
end
|
@@ -79,8 +80,8 @@ module Lutaml
|
|
79
80
|
end
|
80
81
|
|
81
82
|
def add_namespaces(node)
|
82
|
-
node.namespaces.
|
83
|
-
add_namespace(XmlNamespace.new(namespace.uri, namespace.
|
83
|
+
node.namespaces.each do |namespace|
|
84
|
+
add_namespace(XmlNamespace.new(namespace.uri, namespace.prefix))
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "oga"
|
2
|
+
require "moxml/adapter/oga"
|
2
3
|
require_relative "xml_document"
|
3
4
|
require_relative "oga/document"
|
4
5
|
require_relative "oga/element"
|
@@ -8,35 +9,105 @@ module Lutaml
|
|
8
9
|
module Model
|
9
10
|
module XmlAdapter
|
10
11
|
class OgaAdapter < XmlDocument
|
12
|
+
TEXT_CLASSES = [Moxml::Text, Moxml::Cdata].freeze
|
13
|
+
|
11
14
|
def self.parse(xml, options = {})
|
12
|
-
|
13
|
-
xml = xml.encode("UTF-16").encode("UTF-8") if encoding && encoding != "UTF-8"
|
14
|
-
parsed = ::Oga.parse_xml(xml)
|
15
|
+
parsed = Moxml::Adapter::Oga.parse(xml)
|
15
16
|
@root = Oga::Element.new(parsed.children.first)
|
16
|
-
new(@root, encoding)
|
17
|
+
new(@root, encoding(xml, options))
|
17
18
|
end
|
18
19
|
|
19
20
|
def to_xml(options = {})
|
20
21
|
builder_options = {}
|
21
|
-
|
22
22
|
builder_options[:encoding] = if options.key?(:encoding)
|
23
|
-
options[:encoding]
|
23
|
+
options[:encoding]
|
24
24
|
elsif options.key?(:parse_encoding)
|
25
25
|
options[:parse_encoding]
|
26
26
|
else
|
27
27
|
"UTF-8"
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
|
+
builder = Builder::Oga.build(builder_options) do |xml|
|
30
31
|
if @root.is_a?(Oga::Element)
|
31
32
|
@root.build_xml(xml)
|
32
33
|
else
|
33
34
|
build_element(xml, @root, options)
|
34
35
|
end
|
35
36
|
end
|
36
|
-
xml_data = builder.to_xml
|
37
|
+
xml_data = builder.to_xml
|
37
38
|
options[:declaration] ? declaration(options) + xml_data : xml_data
|
38
|
-
|
39
|
-
|
39
|
+
end
|
40
|
+
|
41
|
+
def attributes_hash(element)
|
42
|
+
result = Lutaml::Model::MappingHash.new
|
43
|
+
|
44
|
+
element.attributes.each do |attr|
|
45
|
+
if attr.name == "schemaLocation"
|
46
|
+
result["__schema_location"] = {
|
47
|
+
namespace: attr.namespace,
|
48
|
+
prefix: attr.namespace.prefix,
|
49
|
+
schema_location: attr.value,
|
50
|
+
}
|
51
|
+
else
|
52
|
+
result[self.class.namespaced_attr_name(attr)] = attr.value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.name_of(element)
|
60
|
+
case element
|
61
|
+
when Moxml::Text
|
62
|
+
"text"
|
63
|
+
when Moxml::Cdata
|
64
|
+
"cdata"
|
65
|
+
else
|
66
|
+
element.name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.prefixed_name_of(node)
|
71
|
+
return name_of(node) if TEXT_CLASSES.include?(node.class)
|
72
|
+
|
73
|
+
[node&.namespace&.prefix, node.name].compact.join(":")
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.text_of(element)
|
77
|
+
element.content
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.namespaced_attr_name(attribute)
|
81
|
+
attr_ns = attribute.namespace
|
82
|
+
attr_name = attribute.name
|
83
|
+
return attr_name unless attr_ns
|
84
|
+
|
85
|
+
prefix = attr_name == "lang" ? attr_ns.prefix : attr_ns.uri
|
86
|
+
[prefix, attr_name].compact.join(":")
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.namespaced_name_of(node)
|
90
|
+
return name_of(node) unless node.respond_to?(:namespace)
|
91
|
+
|
92
|
+
[node&.namespace&.uri, node.name].compact.join(":")
|
93
|
+
end
|
94
|
+
|
95
|
+
def order
|
96
|
+
children.map do |child|
|
97
|
+
type = child.text? ? "Text" : "Element"
|
98
|
+
Element.new(type, child.unprefixed_name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.order_of(element)
|
103
|
+
element.children.map do |child|
|
104
|
+
instance_args = if TEXT_CLASSES.include?(child.class)
|
105
|
+
["Text", "text"]
|
106
|
+
else
|
107
|
+
["Element", name_of(child)]
|
108
|
+
end
|
109
|
+
Element.new(*instance_args)
|
110
|
+
end
|
40
111
|
end
|
41
112
|
|
42
113
|
private
|
@@ -54,18 +125,18 @@ module Lutaml
|
|
54
125
|
index_hash = {}
|
55
126
|
content = []
|
56
127
|
|
57
|
-
element.element_order.each do |
|
58
|
-
index_hash[name] ||= -1
|
59
|
-
curr_index = index_hash[name] += 1
|
128
|
+
element.element_order.each do |object|
|
129
|
+
index_hash[object.name] ||= -1
|
130
|
+
curr_index = index_hash[object.name] += 1
|
60
131
|
|
61
|
-
element_rule = xml_mapping.find_by_name(name)
|
132
|
+
element_rule = xml_mapping.find_by_name(object.name)
|
62
133
|
next if element_rule.nil?
|
63
134
|
|
64
135
|
attribute_def = attribute_definition_for(element, element_rule,
|
65
136
|
mapper_class: mapper_class)
|
66
137
|
value = attribute_value_for(element, element_rule)
|
67
138
|
|
68
|
-
next if element_rule == xml_mapping.content_mapping && element_rule.cdata &&
|
139
|
+
next if element_rule == xml_mapping.content_mapping && element_rule.cdata && object.text?
|
69
140
|
|
70
141
|
if element_rule == xml_mapping.content_mapping
|
71
142
|
text = xml_mapping.content_mapping.serialize(element)
|
@@ -94,10 +165,6 @@ module Lutaml
|
|
94
165
|
el.add_text(el, content.join)
|
95
166
|
end
|
96
167
|
end
|
97
|
-
|
98
|
-
def invalid_encoding!(encoding)
|
99
|
-
raise Error, "unknown encoding name - #{encoding}"
|
100
|
-
end
|
101
168
|
end
|
102
169
|
end
|
103
170
|
end
|
@@ -7,26 +7,26 @@ module Lutaml
|
|
7
7
|
module XmlAdapter
|
8
8
|
class OxAdapter < XmlDocument
|
9
9
|
def self.parse(xml, options = {})
|
10
|
-
Ox.default_options = Ox.default_options.merge(encoding:
|
10
|
+
Ox.default_options = Ox.default_options.merge(encoding: encoding(xml, options))
|
11
11
|
|
12
12
|
parsed = Ox.parse(xml)
|
13
|
-
root = OxElement.new(parsed)
|
14
|
-
new(root, Ox.default_options[:encoding])
|
13
|
+
@root = OxElement.new(parsed)
|
14
|
+
new(@root, Ox.default_options[:encoding])
|
15
15
|
end
|
16
16
|
|
17
17
|
def to_xml(options = {})
|
18
18
|
builder_options = { version: options[:version] }
|
19
19
|
|
20
20
|
builder_options[:encoding] = if options.key?(:encoding)
|
21
|
-
options[:encoding]
|
21
|
+
options[:encoding] unless options[:encoding].nil?
|
22
22
|
elsif options.key?(:parse_encoding)
|
23
23
|
options[:parse_encoding]
|
24
24
|
else
|
25
25
|
"UTF-8"
|
26
26
|
end
|
27
27
|
|
28
|
-
builder = Builder::Ox.build
|
29
|
-
builder.xml.instruct(:xml, encoding:
|
28
|
+
builder = Builder::Ox.build(builder_options)
|
29
|
+
builder.xml.instruct(:xml, encoding: builder_options[:encoding])
|
30
30
|
|
31
31
|
if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
|
32
32
|
@root.build_xml(builder)
|
@@ -39,10 +39,6 @@ module Lutaml
|
|
39
39
|
end
|
40
40
|
|
41
41
|
xml_data = builder.xml.to_s
|
42
|
-
if builder_options[:encoding] && xml_data.valid_encoding?
|
43
|
-
xml_data = xml_data.encode(builder_options[:encoding])
|
44
|
-
end
|
45
|
-
|
46
42
|
stripped_data = xml_data.lines.drop(1).join
|
47
43
|
options[:declaration] ? declaration(options) + stripped_data : stripped_data
|
48
44
|
end
|
@@ -62,18 +58,18 @@ module Lutaml
|
|
62
58
|
index_hash = {}
|
63
59
|
content = []
|
64
60
|
|
65
|
-
element.element_order.each do |
|
66
|
-
index_hash[name] ||= -1
|
67
|
-
curr_index = index_hash[name] += 1
|
61
|
+
element.element_order.each do |object|
|
62
|
+
index_hash[object.name] ||= -1
|
63
|
+
curr_index = index_hash[object.name] += 1
|
68
64
|
|
69
|
-
element_rule = xml_mapping.find_by_name(name)
|
65
|
+
element_rule = xml_mapping.find_by_name(object.name)
|
70
66
|
next if element_rule.nil?
|
71
67
|
|
72
68
|
attribute_def = attribute_definition_for(element, element_rule,
|
73
69
|
mapper_class: mapper_class)
|
74
70
|
value = attribute_value_for(element, element_rule)
|
75
71
|
|
76
|
-
next if element_rule == xml_mapping.content_mapping && element_rule.cdata &&
|
72
|
+
next if element_rule == xml_mapping.content_mapping && element_rule.cdata && object.text?
|
77
73
|
|
78
74
|
if element_rule == xml_mapping.content_mapping
|
79
75
|
text = element.send(xml_mapping.content_mapping.to)
|
@@ -198,6 +194,14 @@ module Lutaml
|
|
198
194
|
children
|
199
195
|
end
|
200
196
|
|
197
|
+
def cdata
|
198
|
+
super || cdata_children.first&.text
|
199
|
+
end
|
200
|
+
|
201
|
+
def text
|
202
|
+
super || cdata
|
203
|
+
end
|
204
|
+
|
201
205
|
private
|
202
206
|
|
203
207
|
def parse_children(node, root_node: nil)
|
@@ -2,6 +2,7 @@ require_relative "../mapping_hash"
|
|
2
2
|
require_relative "xml_element"
|
3
3
|
require_relative "xml_attribute"
|
4
4
|
require_relative "xml_namespace"
|
5
|
+
require_relative "element"
|
5
6
|
|
6
7
|
module Lutaml
|
7
8
|
module Model
|
@@ -22,6 +23,22 @@ module Lutaml
|
|
22
23
|
@root.children
|
23
24
|
end
|
24
25
|
|
26
|
+
def root
|
27
|
+
@root
|
28
|
+
end
|
29
|
+
|
30
|
+
def attributes
|
31
|
+
root.attributes
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.encoding(xml, options)
|
35
|
+
if options.key?(:encoding)
|
36
|
+
options[:encoding]
|
37
|
+
else
|
38
|
+
xml.encoding.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
25
42
|
def declaration(options)
|
26
43
|
version = "1.0"
|
27
44
|
version = options[:declaration] if options[:declaration].is_a?(String)
|
@@ -75,22 +92,32 @@ module Lutaml
|
|
75
92
|
def parse_element(element, klass = nil, format = nil)
|
76
93
|
result = Lutaml::Model::MappingHash.new
|
77
94
|
result.node = element
|
78
|
-
result.item_order = element
|
95
|
+
result.item_order = self.class.order_of(element)
|
79
96
|
|
80
97
|
element.children.each do |child|
|
81
98
|
if klass&.<= Serialize
|
82
|
-
attr = klass.attribute_for_child(child
|
99
|
+
attr = klass.attribute_for_child(self.class.name_of(child),
|
83
100
|
format)
|
84
101
|
end
|
85
102
|
|
86
|
-
|
103
|
+
if child.respond_to?(:text?) && child.text?
|
104
|
+
result.assign_or_append_value(
|
105
|
+
self.class.name_of(child),
|
106
|
+
self.class.text_of(child),
|
107
|
+
)
|
108
|
+
next
|
109
|
+
end
|
87
110
|
|
88
111
|
result["elements"] ||= Lutaml::Model::MappingHash.new
|
89
|
-
result["elements"].assign_or_append_value(
|
112
|
+
result["elements"].assign_or_append_value(
|
113
|
+
self.class.namespaced_name_of(child),
|
114
|
+
parse_element(child, attr&.type || klass, format),
|
115
|
+
)
|
90
116
|
end
|
91
117
|
|
92
118
|
result["attributes"] = attributes_hash(element) if element.attributes&.any?
|
93
119
|
|
120
|
+
result.merge(attributes_hash(element))
|
94
121
|
result
|
95
122
|
end
|
96
123
|
|
@@ -121,14 +148,6 @@ module Lutaml
|
|
121
148
|
end
|
122
149
|
|
123
150
|
def add_to_xml(xml, element, prefix, value, options = {})
|
124
|
-
if value.is_a?(Array)
|
125
|
-
value.each do |item|
|
126
|
-
add_to_xml(xml, element, prefix, item, options)
|
127
|
-
end
|
128
|
-
|
129
|
-
return
|
130
|
-
end
|
131
|
-
|
132
151
|
attribute = options[:attribute]
|
133
152
|
rule = options[:rule]
|
134
153
|
|
@@ -138,6 +157,19 @@ module Lutaml
|
|
138
157
|
return
|
139
158
|
end
|
140
159
|
|
160
|
+
# Only transform when recursion is not called
|
161
|
+
if (!attribute.collection? || value.is_a?(Array)) && transform_method = rule.transform[:export] || attribute.transform_export_method
|
162
|
+
value = transform_method.call(value)
|
163
|
+
end
|
164
|
+
|
165
|
+
if value.is_a?(Array)
|
166
|
+
value.each do |item|
|
167
|
+
add_to_xml(xml, element, prefix, item, options)
|
168
|
+
end
|
169
|
+
|
170
|
+
return
|
171
|
+
end
|
172
|
+
|
141
173
|
return if !render_element?(rule, element, value)
|
142
174
|
|
143
175
|
if value && (attribute&.type&.<= Lutaml::Model::Serialize)
|
@@ -161,7 +193,7 @@ module Lutaml
|
|
161
193
|
|
162
194
|
def add_value(xml, value, attribute, cdata: false)
|
163
195
|
if !value.nil?
|
164
|
-
serialized_value = attribute.
|
196
|
+
serialized_value = attribute.serialize(value, :xml)
|
165
197
|
if attribute.raw?
|
166
198
|
xml.add_xml_fragment(xml, value)
|
167
199
|
elsif attribute.type == Lutaml::Model::Type::Hash
|
@@ -339,6 +371,9 @@ module Lutaml
|
|
339
371
|
end
|
340
372
|
|
341
373
|
value = mapping_rule.to_value_for(element)
|
374
|
+
attr = attribute_definition_for(element, mapping_rule, mapper_class: options[:mapper_class])
|
375
|
+
value = attr.serialize(value, :xml) if attr
|
376
|
+
|
342
377
|
if render_element?(mapping_rule, element, value)
|
343
378
|
hash[mapping_rule.prefixed_name] = value ? value.to_s : value
|
344
379
|
end
|
@@ -376,6 +411,32 @@ module Lutaml
|
|
376
411
|
def self.type
|
377
412
|
Utils.snake_case(self).split("/").last.split("_").first
|
378
413
|
end
|
414
|
+
|
415
|
+
def self.order_of(element)
|
416
|
+
element.order
|
417
|
+
end
|
418
|
+
|
419
|
+
def self.name_of(element)
|
420
|
+
element.name
|
421
|
+
end
|
422
|
+
|
423
|
+
def self.text_of(element)
|
424
|
+
element.text
|
425
|
+
end
|
426
|
+
|
427
|
+
def self.namespaced_name_of(element)
|
428
|
+
element.namespaced_name
|
429
|
+
end
|
430
|
+
|
431
|
+
def text
|
432
|
+
return @root.text_children.map(&:text) if @root.children.count > 1
|
433
|
+
|
434
|
+
@root.text
|
435
|
+
end
|
436
|
+
|
437
|
+
def cdata
|
438
|
+
@root.cdata
|
439
|
+
end
|
379
440
|
end
|
380
441
|
end
|
381
442
|
end
|
@@ -8,7 +8,8 @@ module Lutaml
|
|
8
8
|
:children,
|
9
9
|
:text,
|
10
10
|
:namespace_prefix,
|
11
|
-
:parent_document
|
11
|
+
:parent_document,
|
12
|
+
:default_namespace
|
12
13
|
|
13
14
|
attr_accessor :adapter_node
|
14
15
|
|
@@ -117,10 +118,63 @@ module Lutaml
|
|
117
118
|
end
|
118
119
|
|
119
120
|
def order
|
120
|
-
children.
|
121
|
-
|
121
|
+
children.map do |child|
|
122
|
+
type = child.text? ? "Text" : "Element"
|
123
|
+
Lutaml::Model::XmlAdapter::Element.new(type, child.unprefixed_name)
|
122
124
|
end
|
123
125
|
end
|
126
|
+
|
127
|
+
def root
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def text
|
132
|
+
return text_children.map(&:text) if children.count > 1
|
133
|
+
|
134
|
+
@text
|
135
|
+
end
|
136
|
+
|
137
|
+
def cdata_children
|
138
|
+
find_children_by_name("#cdata-section")
|
139
|
+
end
|
140
|
+
|
141
|
+
def text_children
|
142
|
+
find_children_by_name("text")
|
143
|
+
end
|
144
|
+
|
145
|
+
def find_attribute_value(attribute_name)
|
146
|
+
if attribute_name.is_a?(Array)
|
147
|
+
attributes.values.find do |attr|
|
148
|
+
attribute_name.include?(attr.namespaced_name)
|
149
|
+
end&.value
|
150
|
+
else
|
151
|
+
attributes.values.find do |attr|
|
152
|
+
attribute_name == attr.namespaced_name
|
153
|
+
end&.value
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def find_children_by_name(name)
|
158
|
+
if name.is_a?(Array)
|
159
|
+
children.select { |child| name.include?(child.namespaced_name) }
|
160
|
+
else
|
161
|
+
children.select { |child| child.namespaced_name == name }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def find_child_by_name(name)
|
166
|
+
find_children_by_name(name).first
|
167
|
+
end
|
168
|
+
|
169
|
+
def cdata
|
170
|
+
return cdata_children.map(&:text) if children.count > 1
|
171
|
+
|
172
|
+
@text
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_h
|
176
|
+
document.to_h
|
177
|
+
end
|
124
178
|
end
|
125
179
|
end
|
126
180
|
end
|
@@ -16,11 +16,13 @@ module Lutaml
|
|
16
16
|
:namespace_uri,
|
17
17
|
:namespace_prefix,
|
18
18
|
:mixed_content,
|
19
|
-
:ordered
|
19
|
+
:ordered,
|
20
|
+
:element_sequence
|
20
21
|
|
21
22
|
def initialize
|
22
23
|
@elements = {}
|
23
24
|
@attributes = {}
|
25
|
+
@element_sequence = []
|
24
26
|
@content_mapping = nil
|
25
27
|
@raw_mapping = nil
|
26
28
|
@mixed_content = false
|
@@ -35,6 +37,18 @@ module Lutaml
|
|
35
37
|
@ordered = ordered || mixed # mixed contenet will always be ordered
|
36
38
|
end
|
37
39
|
|
40
|
+
def root?
|
41
|
+
!!root_element
|
42
|
+
end
|
43
|
+
|
44
|
+
def no_root
|
45
|
+
@no_root = true
|
46
|
+
end
|
47
|
+
|
48
|
+
def no_root?
|
49
|
+
!!@no_root
|
50
|
+
end
|
51
|
+
|
38
52
|
def prefixed_root
|
39
53
|
if namespace_uri && namespace_prefix
|
40
54
|
"#{namespace_prefix}:#{root_element}"
|
@@ -44,6 +58,8 @@ module Lutaml
|
|
44
58
|
end
|
45
59
|
|
46
60
|
def namespace(uri, prefix = nil)
|
61
|
+
raise Lutaml::Model::NoRootNamespaceError if no_root?
|
62
|
+
|
47
63
|
@namespace_uri = uri
|
48
64
|
@namespace_prefix = prefix
|
49
65
|
end
|
@@ -60,7 +76,8 @@ module Lutaml
|
|
60
76
|
namespace: (namespace_set = false
|
61
77
|
nil),
|
62
78
|
prefix: (prefix_set = false
|
63
|
-
nil)
|
79
|
+
nil),
|
80
|
+
transform: {}
|
64
81
|
)
|
65
82
|
validate!(name, to, with, type: TYPES[:element])
|
66
83
|
|
@@ -77,6 +94,7 @@ module Lutaml
|
|
77
94
|
prefix: prefix,
|
78
95
|
namespace_set: namespace_set != false,
|
79
96
|
prefix_set: prefix_set != false,
|
97
|
+
transform: transform,
|
80
98
|
)
|
81
99
|
@elements[rule.namespaced_name] = rule
|
82
100
|
end
|
@@ -170,6 +188,21 @@ module Lutaml
|
|
170
188
|
|
171
189
|
alias map_all_content map_all
|
172
190
|
|
191
|
+
def sequence(&block)
|
192
|
+
@element_sequence << Sequence.new(self).tap do |s|
|
193
|
+
s.instance_eval(&block)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def import_model_mappings(model)
|
198
|
+
raise Lutaml::Model::ImportModelWithRootError.new(model) if model.root?
|
199
|
+
|
200
|
+
mappings = model.mappings_for(:xml)
|
201
|
+
@elements.merge!(mappings.instance_variable_get(:@elements))
|
202
|
+
@attributes.merge!(mappings.instance_variable_get(:@attributes))
|
203
|
+
(@element_sequence << mappings.element_sequence).flatten!
|
204
|
+
end
|
205
|
+
|
173
206
|
def validate!(key, to, with, type: nil)
|
174
207
|
validate_mappings!(type)
|
175
208
|
|
@@ -243,14 +276,23 @@ module Lutaml
|
|
243
276
|
ordered: @ordered)
|
244
277
|
xml_mapping.namespace(@namespace_uri.dup, @namespace_prefix.dup)
|
245
278
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
@content_mapping&.deep_dup)
|
279
|
+
attributes_to_dup.each do |var_name|
|
280
|
+
value = instance_variable_get(var_name)
|
281
|
+
xml_mapping.instance_variable_set(var_name, Utils.deep_dup(value))
|
282
|
+
end
|
251
283
|
end
|
252
284
|
end
|
253
285
|
|
286
|
+
def attributes_to_dup
|
287
|
+
@attributes_to_dup ||= %i[
|
288
|
+
@content_mapping
|
289
|
+
@raw_mapping
|
290
|
+
@element_sequence
|
291
|
+
@attributes
|
292
|
+
@elements
|
293
|
+
]
|
294
|
+
end
|
295
|
+
|
254
296
|
def dup_mappings(mappings)
|
255
297
|
new_mappings = {}
|
256
298
|
|
@@ -19,7 +19,8 @@ module Lutaml
|
|
19
19
|
namespace_set: false,
|
20
20
|
prefix_set: false,
|
21
21
|
attribute: false,
|
22
|
-
default_namespace: nil
|
22
|
+
default_namespace: nil,
|
23
|
+
transform: {}
|
23
24
|
)
|
24
25
|
super(
|
25
26
|
name,
|
@@ -28,7 +29,8 @@ module Lutaml
|
|
28
29
|
render_default: render_default,
|
29
30
|
with: with,
|
30
31
|
delegate: delegate,
|
31
|
-
attribute: attribute
|
32
|
+
attribute: attribute,
|
33
|
+
transform: transform
|
32
34
|
)
|
33
35
|
|
34
36
|
@namespace = if namespace.to_s == "inherit"
|
@@ -101,15 +103,18 @@ module Lutaml
|
|
101
103
|
name.dup,
|
102
104
|
to: to,
|
103
105
|
render_nil: render_nil,
|
106
|
+
render_default: render_default,
|
104
107
|
with: Utils.deep_dup(custom_methods),
|
105
108
|
delegate: delegate,
|
106
109
|
namespace: namespace.dup,
|
107
110
|
prefix: prefix.dup,
|
108
111
|
mixed_content: mixed_content,
|
112
|
+
cdata: cdata,
|
109
113
|
namespace_set: namespace_set?,
|
110
|
-
attribute: attribute,
|
111
114
|
prefix_set: prefix_set?,
|
115
|
+
attribute: attribute,
|
112
116
|
default_namespace: default_namespace.dup,
|
117
|
+
transform: transform.dup,
|
113
118
|
)
|
114
119
|
end
|
115
120
|
end
|