lutaml-model 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +33 -10
- 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 +125 -35
- 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 +6 -7
- 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 +143 -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
|