lutaml-model 0.5.3 → 0.5.4
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-tests.yml +2 -0
- data/.rubocop_todo.yml +39 -13
- data/Gemfile +1 -0
- data/README.adoc +396 -23
- data/lib/lutaml/model/constants.rb +7 -0
- data/lib/lutaml/model/error/type/invalid_value_error.rb +19 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/key_value_mapping.rb +31 -2
- data/lib/lutaml/model/mapping_hash.rb +8 -0
- data/lib/lutaml/model/mapping_rule.rb +4 -0
- data/lib/lutaml/model/schema/templates/simple_type.rb +247 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +720 -0
- data/lib/lutaml/model/schema.rb +5 -0
- data/lib/lutaml/model/serialize.rb +24 -8
- data/lib/lutaml/model/toml_adapter/toml_rb_adapter.rb +1 -2
- data/lib/lutaml/model/type/hash.rb +11 -11
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +5 -1
- data/lib/lutaml/model/xml_adapter/xml_document.rb +11 -15
- data/lib/lutaml/model/xml_mapping.rb +4 -2
- data/lib/lutaml/model/xml_mapping_rule.rb +1 -4
- data/lib/lutaml/model.rb +1 -0
- data/spec/fixtures/xml/invalid_math_document.xml +4 -0
- data/spec/fixtures/xml/math_document_schema.xsd +56 -0
- data/spec/fixtures/xml/test_schema.xsd +53 -0
- data/spec/fixtures/xml/valid_math_document.xml +4 -0
- data/spec/lutaml/model/cdata_spec.rb +2 -2
- data/spec/lutaml/model/custom_model_spec.rb +7 -20
- data/spec/lutaml/model/key_value_mapping_spec.rb +27 -0
- data/spec/lutaml/model/map_all_spec.rb +188 -0
- data/spec/lutaml/model/mixed_content_spec.rb +15 -15
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +1431 -0
- data/spec/lutaml/model/with_child_mapping_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +52 -0
- data/spec/lutaml/model/xml_mapping_spec.rb +108 -1
- metadata +12 -2
data/README.adoc
CHANGED
@@ -49,12 +49,12 @@ The Lutaml::Model data modelling approach is as follows:
|
|
49
49
|
.Modeling relationships of a LutaML Model
|
50
50
|
[source]
|
51
51
|
----
|
52
|
-
|
52
|
+
LutaML Model
|
53
53
|
│
|
54
54
|
Has many attributes
|
55
55
|
│
|
56
56
|
▼
|
57
|
-
|
57
|
+
Attribute
|
58
58
|
│
|
59
59
|
Has type of
|
60
60
|
│
|
@@ -97,7 +97,7 @@ Studio (Model)
|
|
97
97
|
[source]
|
98
98
|
----
|
99
99
|
╔═══════════════════════╗ ╔════════════════════════════╗
|
100
|
-
║
|
100
|
+
║ LutaML Core Model ║ ║ Serialization Models ║
|
101
101
|
╚═══════════════════════╝ ╚════════════════════════════╝
|
102
102
|
|
103
103
|
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
@@ -109,8 +109,8 @@ Studio (Model)
|
|
109
109
|
┆ │ │ ┆ │ & │ ┆ │ │ ┆
|
110
110
|
┆ │ │ ┆ │ Mapping Rules │ ┆ │ │ ┆
|
111
111
|
┆ │ ┌──────┴──┐ ┆ │ │ ┆ ┌────┴────┐ ┌─┴─┐ ┆
|
112
|
-
┆ │ │ │ ┆
|
113
|
-
┆ │ String Integer ┆
|
112
|
+
┆ │ │ │ ┆ └────────────────┘ ┆ │ │ │ │ ┆
|
113
|
+
┆ │ String Integer ┆ │ ┆ Element Value xs:string ┆
|
114
114
|
┆ │ Date Float ┆ │ ┆ Attribute Type xs:date ┆
|
115
115
|
┆ │ Time Boolean ┆ ├──────► ┆ xs:boolean ┆
|
116
116
|
┆ │ ┆ │ ┆ xs:anyURI ┆
|
@@ -131,22 +131,109 @@ Studio (Model)
|
|
131
131
|
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
132
132
|
----
|
133
133
|
|
134
|
+
.Model transformation of a LutaML Model to another LutaML Model
|
135
|
+
[source]
|
136
|
+
----
|
137
|
+
╔═══════════════════════╗ ╔══════════════════╗ ╔═══════════════════════╗
|
138
|
+
║LutaML Model Class FOO ║ ║LutaML Transformer║ ║LutaML Model Class BAR ║
|
139
|
+
╚═══════════════════════╝ ╚══════════════════╝ ╚═══════════════════════╝
|
140
|
+
|
141
|
+
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
142
|
+
┆ Model ┆ ┆ Model ┆
|
143
|
+
┆ │ ┆ ┌────────────────┐ ┆ │ ┆
|
144
|
+
┆ ┌────────┴──┐ ┆ │ │ ┆ ┌────────┴──┐ ┆
|
145
|
+
┆ │ │ ┆ │ Model │ ┆ │ │ ┆
|
146
|
+
┆ Models Value Types ┆───►│ Transformation │───►┆ Models Value Types ┆
|
147
|
+
┆ │ │ ┆◄───│ & │◄───┆ │ │ ┆
|
148
|
+
┆ │ │ ┆ │ Mapping Rules │ ┆ │ │ ┆
|
149
|
+
┆ │ ┌──────┴──┐ ┆ │ │ ┆ │ ┌──────┴──┐ ┆
|
150
|
+
┆ │ │ │ ┆ └────────────────┘ ┆ │ │ │ ┆
|
151
|
+
┆ │ String Integer ┆ ┆ │ String Integer ┆
|
152
|
+
┆ │ Date Float ┆ ┆ │ Date Float ┆
|
153
|
+
┆ │ Time Boolean ┆ ┆ │ Time Boolean ┆
|
154
|
+
┆ │ ┆ ┆ │ ┆
|
155
|
+
┆ └──────┐ ┆ ┆ └──────┐ ┆
|
156
|
+
┆ │ ┆ ┆ │ ┆
|
157
|
+
┆ Contains ┆ ┆ Contains ┆
|
158
|
+
┆ more Models ┆ ┆ more Models ┆
|
159
|
+
┆ (recursive) ┆ ┆ (recursive) ┆
|
160
|
+
┆ ┆ ┆ ┆
|
161
|
+
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
162
|
+
----
|
163
|
+
|
164
|
+
.The `Value` class, transformation, and serialization formats
|
165
|
+
[source]
|
166
|
+
----
|
167
|
+
╔═══════════════════════╗ ╔═══════════════════════╗
|
168
|
+
║LutaML Value Class FOO ║ ║ Serialization Value ║
|
169
|
+
╚═══════════════════════╝ ╚═══════════════════════╝
|
170
|
+
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
171
|
+
┆ ┌───────────────┐ ┆ ┆ ┌───────────────┐ ┆
|
172
|
+
┆ │ Value │ ┆ ┌──────────────────┐ ┆ │ XML Value │ ┆
|
173
|
+
┆ └───────────────┘ ┆──►│ Value Serializer │──►┆ └───────────────┘ ┆
|
174
|
+
┆ ┌───────────────┐ ┆ └──────────────────┘ ┆ ┌───────────────┐ ┆
|
175
|
+
┆ │Primitive Types│ ┆ ┆ │XML Value Types│ ┆
|
176
|
+
┆ └───────────────┘ ┆ ┆ └───────────────┘ ┆
|
177
|
+
┆ ┌───┘ ┆ ┆ ┌───┘ ┆
|
178
|
+
┆ ├─ string ┆ ┆ ├─ xs:string ┆
|
179
|
+
┆ ├─ integer ┆ ┆ ├─ xs:integer ┆
|
180
|
+
┆ ├─ float ┆ ┆ ├─ xs:decimal ┆
|
181
|
+
┆ ├─ boolean ┆ ┆ ├─ xs:boolean ┆
|
182
|
+
┆ ├─ date ┆ ┆ ├─ xs:date ┆
|
183
|
+
┆ ├─ time_without_date ┆ ┆ ├─ xs:time ┆
|
184
|
+
┆ ├─ date_time ┆ ┆ ├─ xs:dateTime ┆
|
185
|
+
┆ ├─ time ┆ ┆ ├─ xs:decimal ┆
|
186
|
+
┆ ├─ decimal ┆ ┆ ├─ xs:anyType ┆
|
187
|
+
┆ └─ hash ┆ ┆ └─ (complex element) ┆
|
188
|
+
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
189
|
+
│
|
190
|
+
▼
|
191
|
+
┌───────────────────┐
|
192
|
+
│ Value Transformer │
|
193
|
+
└───────────────────┘
|
194
|
+
│
|
195
|
+
▼
|
196
|
+
╔═══════════════════════╗
|
197
|
+
║LutaML Value Class BAR ║
|
198
|
+
╚═══════════════════════╝
|
199
|
+
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
200
|
+
┆ ┌───────────────┐ ┆
|
201
|
+
┆ │ Value │ ┆
|
202
|
+
┆ └───────────────┘ ┆
|
203
|
+
┆ ┌───────────────┐ ┆
|
204
|
+
┆ │Primitive Types│ ┆
|
205
|
+
┆ └───────────────┘ ┆
|
206
|
+
┆ ┌───┘ ┆
|
207
|
+
┆ ├─ string ┆
|
208
|
+
┆ ├─ integer ┆
|
209
|
+
┆ ├─ float ┆
|
210
|
+
┆ ├─ boolean ┆
|
211
|
+
┆ ├─ date ┆
|
212
|
+
┆ ├─ time_without_date ┆
|
213
|
+
┆ ├─ date_time ┆
|
214
|
+
┆ ├─ time ┆
|
215
|
+
┆ ├─ decimal ┆
|
216
|
+
┆ └─ hash ┆
|
217
|
+
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
218
|
+
----
|
219
|
+
|
134
220
|
.Example of LutaML Model instance transformed into a serialization model and serialized to JSON
|
135
221
|
====
|
136
222
|
[source]
|
137
223
|
----
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
224
|
+
╔═════════════════════╗ ╔═════════════════════╗ ╔═════════════════════╗
|
225
|
+
║ Studio (Core Model) ║ ║ JSON Model ║ ║ Serialized JSON ║
|
226
|
+
╚═════════════════════╝ ╚═════════════════════╝ ╚═════════════════════╝
|
227
|
+
|
228
|
+
name: "Studio 1" ┌─► { ┌─► {
|
229
|
+
address: │ "name": "...", │ "name": "Studio 1",
|
230
|
+
├── street: "..." │ "address": { │ "address": {
|
231
|
+
└── city: "..." │ "street": "...", │ "street": "...",
|
232
|
+
kilns: ──┤ "city": "..." ──┤ "city": "..."
|
233
|
+
├── count: 3 │ }, │ },
|
234
|
+
└── temp: 1200 │ "kilnsCount": ..., │ "kilnsCount": 3,
|
235
|
+
│ "kilnsTemp": ... │ "kilnsTemp": 1200
|
236
|
+
└─► } └─► }
|
150
237
|
----
|
151
238
|
====
|
152
239
|
|
@@ -926,10 +1013,8 @@ end
|
|
926
1013
|
----
|
927
1014
|
====
|
928
1015
|
|
929
|
-
|
930
|
-
==== Mapping all
|
931
|
-
|
932
|
-
WARNING: This feature is only applicable to XML (for now).
|
1016
|
+
[[xml-map-all]]
|
1017
|
+
==== Mapping all XML content
|
933
1018
|
|
934
1019
|
The `map_all` tag in XML mapping captures and maps all content within an XML
|
935
1020
|
element into a single attribute in the target Ruby object.
|
@@ -937,6 +1022,12 @@ element into a single attribute in the target Ruby object.
|
|
937
1022
|
The use case for `map_all` is to tell Lutaml::Model to not parse the content of
|
938
1023
|
the XML element at all, and instead handle it as an XML string.
|
939
1024
|
|
1025
|
+
NOTE: The corresponding method for key-value formats is at <<key-value-map-all>>.
|
1026
|
+
|
1027
|
+
WARNING: Notice that usage of mapping all will lead to incompatibility between
|
1028
|
+
serialization formats, i.e. the raw string content will not be portable as
|
1029
|
+
objects are across different formats.
|
1030
|
+
|
940
1031
|
This is useful in the case where the content of an XML element is not to be
|
941
1032
|
handled by a Lutaml::Model::Serializable object.
|
942
1033
|
|
@@ -949,8 +1040,9 @@ This includes:
|
|
949
1040
|
* attributes
|
950
1041
|
* text nodes
|
951
1042
|
|
952
|
-
The `map_all` tag is **exclusive** and cannot be combined with other mappings
|
953
|
-
|
1043
|
+
The `map_all` tag is **exclusive** and cannot be combined with other mappings
|
1044
|
+
(`map_element`, `map_content`) except for `map_attribute` for the same element,
|
1045
|
+
ensuring it captures the entire inner XML content.
|
954
1046
|
|
955
1047
|
NOTE: An error is raised if `map_all` is defined alongside any other mapping in
|
956
1048
|
the same XML mapping context.
|
@@ -1672,6 +1764,7 @@ end
|
|
1672
1764
|
|
1673
1765
|
// TODO: How to create mixed content from `#new`?
|
1674
1766
|
|
1767
|
+
|
1675
1768
|
[[xml-schema-location]]
|
1676
1769
|
==== Automatic support of `xsi:schemaLocation`
|
1677
1770
|
|
@@ -1931,6 +2024,102 @@ end
|
|
1931
2024
|
----
|
1932
2025
|
====
|
1933
2026
|
|
2027
|
+
[[key-value-map-all]]
|
2028
|
+
==== Mapping all key-value content
|
2029
|
+
|
2030
|
+
The `map_all` tag captures and maps all content within a serialization format
|
2031
|
+
into a single attribute in the target Ruby object.
|
2032
|
+
|
2033
|
+
The use case for `map_all` is to tell Lutaml::Model to not parse the content at
|
2034
|
+
all, and instead handle it as a raw string.
|
2035
|
+
|
2036
|
+
NOTE: The corresponding method for XML is at <<xml-map-all>>.
|
2037
|
+
|
2038
|
+
WARNING: Notice that usage of mapping all will lead to incompatibility between
|
2039
|
+
serialization formats, i.e. the raw string content will not be portable as
|
2040
|
+
objects are across different formats.
|
2041
|
+
|
2042
|
+
This is useful when the content needs to be handled as-is without parsing into
|
2043
|
+
individual attributes.
|
2044
|
+
|
2045
|
+
The `map_all` tag is **exclusive** and cannot be combined with other mappings,
|
2046
|
+
ensuring it captures the entire content.
|
2047
|
+
|
2048
|
+
NOTE: An error is raised if `map_all` is defined alongside any other mapping in
|
2049
|
+
the same mapping context.
|
2050
|
+
|
2051
|
+
Syntax:
|
2052
|
+
|
2053
|
+
[source,ruby]
|
2054
|
+
----
|
2055
|
+
json | yaml | toml | key_value do
|
2056
|
+
map_all to: :name_of_attribute
|
2057
|
+
end
|
2058
|
+
----
|
2059
|
+
|
2060
|
+
.Using `map_all` to capture all content across different formats
|
2061
|
+
[example]
|
2062
|
+
====
|
2063
|
+
[source,ruby]
|
2064
|
+
----
|
2065
|
+
class Document < Lutaml::Model::Serializable
|
2066
|
+
attribute :content, :string
|
2067
|
+
|
2068
|
+
json do
|
2069
|
+
map_all to: :content
|
2070
|
+
end
|
2071
|
+
|
2072
|
+
yaml do
|
2073
|
+
map_all to: :content
|
2074
|
+
end
|
2075
|
+
|
2076
|
+
toml do
|
2077
|
+
map_all to: :content
|
2078
|
+
end
|
2079
|
+
end
|
2080
|
+
----
|
2081
|
+
|
2082
|
+
For JSON:
|
2083
|
+
[source,json]
|
2084
|
+
----
|
2085
|
+
{
|
2086
|
+
"sections": [
|
2087
|
+
{ "title": "Introduction", "text": "Chapter 1" },
|
2088
|
+
{ "title": "Conclusion", "text": "Final chapter" }
|
2089
|
+
],
|
2090
|
+
"metadata": {
|
2091
|
+
"author": "John Doe",
|
2092
|
+
"date": "2024-01-15"
|
2093
|
+
}
|
2094
|
+
}
|
2095
|
+
----
|
2096
|
+
|
2097
|
+
For YAML:
|
2098
|
+
[source,yaml]
|
2099
|
+
----
|
2100
|
+
sections:
|
2101
|
+
- title: Introduction
|
2102
|
+
text: Chapter 1
|
2103
|
+
- title: Conclusion
|
2104
|
+
text: Final chapter
|
2105
|
+
metadata:
|
2106
|
+
author: John Doe
|
2107
|
+
date: 2024-01-15
|
2108
|
+
----
|
2109
|
+
|
2110
|
+
The content is preserved exactly as provided:
|
2111
|
+
|
2112
|
+
[source,ruby]
|
2113
|
+
----
|
2114
|
+
> doc = Document.from_json(json_content)
|
2115
|
+
> puts doc.content
|
2116
|
+
> # "{\"sections\":[{\"title\":\"Introduction\",\"text\":\"Chapter 1\"},{\"title\":\"Conclusion\",\"text\":\"Final chapter\"}],\"metadata\":{\"author\":\"John Doe\",\"date\":\"2024-01-15\"}}"
|
2117
|
+
|
2118
|
+
> doc = Document.from_yaml(yaml_content)
|
2119
|
+
> puts doc.content
|
2120
|
+
> # "sections:\n - title: Introduction\n text: Chapter 1\n - title: Conclusion\n text: Final chapter\nmetadata:\n author: John Doe\n date: 2024-01-15\n"
|
2121
|
+
----
|
2122
|
+
====
|
1934
2123
|
|
1935
2124
|
==== Nested attribute mappings
|
1936
2125
|
|
@@ -3310,6 +3499,181 @@ end
|
|
3310
3499
|
====
|
3311
3500
|
|
3312
3501
|
|
3502
|
+
== Importing data models
|
3503
|
+
|
3504
|
+
=== General
|
3505
|
+
|
3506
|
+
Lutaml::Model provides a way to import data models defined from various formats
|
3507
|
+
into the LutaML data modeling system.
|
3508
|
+
|
3509
|
+
Data model languages supported are:
|
3510
|
+
|
3511
|
+
* XSD (https://w3.org/TR/xmlschema-1/[XML Schema Definition Language])
|
3512
|
+
// * RNC (https://relaxng.org/compact-tutorial-20030326.html[RELAX NG Compact Syntax])
|
3513
|
+
// * RNG (https://relaxng.org/relaxng-compact.html[RELAX NG XML Syntax])
|
3514
|
+
// * JSON Schema (https://json-schema.org/understanding-json-schema/[JSON Schema])
|
3515
|
+
// * YAML Schema (https://yaml.org/spec/1.2/spec.html[YAML])
|
3516
|
+
// * LutaML
|
3517
|
+
|
3518
|
+
|
3519
|
+
The following figure illustrates the process of importing an XML Schema model to
|
3520
|
+
create LutaML core models. Once the LutaML core models are created, they can be
|
3521
|
+
used to parse and generate XML documents according to the imported XML Schema
|
3522
|
+
model.
|
3523
|
+
|
3524
|
+
Today, the LutaML core models are written into Ruby files, which can be used to
|
3525
|
+
parse and generate XML documents according to the imported XML Schema.
|
3526
|
+
This is to be changed so that the LutaML core models are directly loaded and
|
3527
|
+
interpreted.
|
3528
|
+
|
3529
|
+
.Importing an XML Schema model to create LutaML core models
|
3530
|
+
[source]
|
3531
|
+
----
|
3532
|
+
╔════════════════════════════╗ ╔═══════════════════════╗
|
3533
|
+
║ Serialization Models ║ ║ Core Model ║
|
3534
|
+
╚════════════════════════════╝ ╚═══════════════════════╝
|
3535
|
+
|
3536
|
+
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
3537
|
+
┆ XML Schema (XSD/RNG/RNC) ┆ ┆ Model ┆
|
3538
|
+
┆ │ ┆ ┌────────────────┐ ┆ │ ┆
|
3539
|
+
┆ ┌──────┴──────┐ ┆ │ │ ┆ ┌────────┴──┐ ┆
|
3540
|
+
┆ │ │ ┆ │ Model │ ┆ │ │ ┆
|
3541
|
+
┆ Models Value Types ┆──►│ Importing │──►┆ Models Value Types ┆
|
3542
|
+
┆ │ │ ┆ │ │ ┆ │ │ ┆
|
3543
|
+
┆ │ │ ┆ └────────────────┘ ┆ │ │ ┆
|
3544
|
+
┆ ┌────┴────┐ ┌─┴─┐ ┆ │ ┆ │ ┌──────┴──┐ ┆
|
3545
|
+
┆ │ │ │ │ ┆ │ ┆ │ │ │ ┆
|
3546
|
+
┆ Element Value xs:string ┆ │ ┆ │ String Integer ┆
|
3547
|
+
┆ Attribute Type xs:date ┆ │ ┆ │ Date Float ┆
|
3548
|
+
┆ Union Complex xs:boolean ┆ │ ┆ │ Time Boolean ┆
|
3549
|
+
┆ Sequence Choice xs:anyURI ┆ │ ┆ │ ┆
|
3550
|
+
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯ │ ┆ └──────┐ ┆
|
3551
|
+
│ ┆ │ ┆
|
3552
|
+
│ ┆ Contains ┆
|
3553
|
+
│ ┆ more Models ┆
|
3554
|
+
│ ┆ (recursive) ┆
|
3555
|
+
│ ┆ ┆
|
3556
|
+
│ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
3557
|
+
│ ┌────────────────┐
|
3558
|
+
│ │ │
|
3559
|
+
│ │ Model │
|
3560
|
+
└──────────► │ Transformation │
|
3561
|
+
│ & │
|
3562
|
+
│ Mapping Rules │
|
3563
|
+
│ │
|
3564
|
+
└────────────────┘
|
3565
|
+
----
|
3566
|
+
|
3567
|
+
|
3568
|
+
[[xml-schema-to-model-files]]
|
3569
|
+
=== XML Schema (XSD)
|
3570
|
+
|
3571
|
+
W3C XSD is a schema language designed to define the structure of XML documents,
|
3572
|
+
alongside other XML schema languages like DTD, RELAX NG, and Schematron.
|
3573
|
+
|
3574
|
+
Lutaml::Model supports the import of XSD schema files to define information
|
3575
|
+
models that can be used to parse and generate XML documents.
|
3576
|
+
|
3577
|
+
Specifically, the `Lutaml::Model::Schema#from_xml` method loads XML Schema files
|
3578
|
+
(XSD, `*.xsd`) and generates Ruby files (`*.rb`) that inherit from
|
3579
|
+
`Lutaml::Model::Serializable` that are saved to disk.
|
3580
|
+
|
3581
|
+
Syntax:
|
3582
|
+
|
3583
|
+
[source,ruby]
|
3584
|
+
----
|
3585
|
+
Lutaml::Model::Schema.from_xml(
|
3586
|
+
xsd_schema, <1>
|
3587
|
+
options: options <2>
|
3588
|
+
)
|
3589
|
+
----
|
3590
|
+
<1> The `xsd_schema` is the XML Schema string to be converted to model files.
|
3591
|
+
<2> The `options` hash is an optional argument.
|
3592
|
+
|
3593
|
+
`options`:: Optional hash containing potentially the following key-values.
|
3594
|
+
|
3595
|
+
`output_dir`::: The directory where the model files will be saved. If not
|
3596
|
+
provided, a default directory named `lutaml_models_<timestamp>` is created.
|
3597
|
+
+
|
3598
|
+
[example]
|
3599
|
+
`"path/to/directory"`
|
3600
|
+
|
3601
|
+
`namespace`::: The namespace of the schema. This will be added in the
|
3602
|
+
`Lutaml::Model::Serializable` file's `xml do` block.
|
3603
|
+
+
|
3604
|
+
[example]
|
3605
|
+
`http://example.com/namespace`
|
3606
|
+
|
3607
|
+
`prefix`::: The prefix of the namespace provided in the `namespace` option.
|
3608
|
+
+
|
3609
|
+
[example]
|
3610
|
+
`example-prefix`
|
3611
|
+
|
3612
|
+
`location`::: The URL or path of the directory containing all the files of the
|
3613
|
+
schema. For more information, refer to the
|
3614
|
+
link:https://www.w3.org/TR/xmlschema-1/#include[XML Schema specification].
|
3615
|
+
+
|
3616
|
+
[example]
|
3617
|
+
`"http://example.com/example.xsd"`
|
3618
|
+
+
|
3619
|
+
[example]
|
3620
|
+
`"path/to/schema/directory"`
|
3621
|
+
|
3622
|
+
|
3623
|
+
The generated LutaML models consists of two different kind of Ruby classes
|
3624
|
+
depending on the XSD schema:
|
3625
|
+
|
3626
|
+
XSD "SimpleTypes":: converted into classes that inherit from
|
3627
|
+
`Lutaml::Model::Type::Value`, which define the data types with restrictions and
|
3628
|
+
other validations of these values.
|
3629
|
+
|
3630
|
+
XSD "ComplexTypes":: converted into classes that inherit from
|
3631
|
+
`Lutaml::Model::Serializable` that model according to the defined structure.
|
3632
|
+
|
3633
|
+
Lutaml::Model uses the https://github.com/lutaml/lutaml-xsd[`lutaml-xsd` gem] to
|
3634
|
+
automatically resolve the `include` and `import` elements, enabling
|
3635
|
+
*Lutaml-Model* to generate the corresponding model files.
|
3636
|
+
|
3637
|
+
This auto-resolving feature allows seamless integration of these files into your
|
3638
|
+
models without the need for manual resolution of includes and imports.
|
3639
|
+
|
3640
|
+
[example]
|
3641
|
+
.Using `Lutaml::Model::Schema#from_xml` to convert an XML Schema to model files
|
3642
|
+
====
|
3643
|
+
[source,ruby]
|
3644
|
+
----
|
3645
|
+
xsd_schema = <<~XSD
|
3646
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
3647
|
+
/* your schema here */
|
3648
|
+
</xs:schema>
|
3649
|
+
XSD
|
3650
|
+
options = {
|
3651
|
+
# These are all optional:
|
3652
|
+
output_dir: 'path/to/directory',
|
3653
|
+
namespace: 'http://example.com/namespace',
|
3654
|
+
prefix: "example-prefix",
|
3655
|
+
location: "http://example.com/example.xsd"
|
3656
|
+
# or
|
3657
|
+
# location: "path/to/schema/directory"
|
3658
|
+
}
|
3659
|
+
|
3660
|
+
# generates the files in the output_dir | default_dir
|
3661
|
+
Lutaml::Model::Schema.from_xml(xsd_schema, options: options)
|
3662
|
+
----
|
3663
|
+
====
|
3664
|
+
|
3665
|
+
You could also directly load the generated Ruby files into your application by
|
3666
|
+
requiring them.
|
3667
|
+
|
3668
|
+
[example]
|
3669
|
+
.Using the generated Ruby files in your application
|
3670
|
+
====
|
3671
|
+
[source,ruby]
|
3672
|
+
----
|
3673
|
+
Lutaml::Model::Schema.from_xml(xsd_schema, options: {output_dir: 'path/to/directory'})
|
3674
|
+
require_relative 'path/to/directory/*.rb'
|
3675
|
+
----
|
3676
|
+
====
|
3313
3677
|
|
3314
3678
|
|
3315
3679
|
== Validation
|
@@ -3701,6 +4065,15 @@ attribute for every element.
|
|
3701
4065
|
| Requires manual specification on every XML element that uses it.
|
3702
4066
|
|
|
3703
4067
|
|
4068
|
+
|
4069
|
+
| Compiling XML Schema to *Lutaml::Model::Serializable* classes
|
4070
|
+
| Yes. Using <<xml-schema-to-model-files, `Lutaml::Model::Schema#from_xml`>>
|
4071
|
+
|
4072
|
+
1. *ComplexTypes* are compiled to *Lutaml::Model::Serializable* classes containing the attributes.
|
4073
|
+
2. *SimpleTypes* are compiled to *Lutaml::Model::Type::Value* classes to support XML Schema level validations.
|
4074
|
+
| Yes, Provides only an array of the classes and doesn't support `simple types` with restrictions and/or other validations.
|
4075
|
+
|
|
4076
|
+
|
3704
4077
|
4+h| Attribute features
|
3705
4078
|
|
3706
4079
|
| Attribute delegation
|
data/lib/lutaml/model/error.rb
CHANGED
@@ -36,6 +36,27 @@ module Lutaml
|
|
36
36
|
|
37
37
|
alias map_element map
|
38
38
|
|
39
|
+
def map_all(
|
40
|
+
to: nil,
|
41
|
+
render_nil: false,
|
42
|
+
render_default: false,
|
43
|
+
with: {},
|
44
|
+
delegate: nil
|
45
|
+
)
|
46
|
+
@raw_mapping = true
|
47
|
+
validate!(Constants::RAW_MAPPING_KEY, to, with)
|
48
|
+
@mappings << KeyValueMappingRule.new(
|
49
|
+
Constants::RAW_MAPPING_KEY,
|
50
|
+
to: to,
|
51
|
+
render_nil: render_nil,
|
52
|
+
render_default: render_default,
|
53
|
+
with: with,
|
54
|
+
delegate: delegate,
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
alias map_all_content map_all
|
59
|
+
|
39
60
|
def name_for_mapping(root_mappings, name)
|
40
61
|
return "root_mapping" if root_mappings
|
41
62
|
|
@@ -43,12 +64,14 @@ module Lutaml
|
|
43
64
|
end
|
44
65
|
|
45
66
|
def validate!(key, to, with)
|
46
|
-
|
67
|
+
validate_mappings!(key)
|
68
|
+
|
69
|
+
if to.nil? && with.empty? && !@raw_mapping
|
47
70
|
msg = ":to or :with argument is required for mapping '#{key}'"
|
48
71
|
raise IncorrectMappingArgumentsError.new(msg)
|
49
72
|
end
|
50
73
|
|
51
|
-
if !with.empty? && (with[:from].nil? || with[:to].nil?)
|
74
|
+
if !with.empty? && (with[:from].nil? || with[:to].nil?) && !@raw_mapping
|
52
75
|
msg = ":with argument for mapping '#{key}' requires :to and :from keys"
|
53
76
|
raise IncorrectMappingArgumentsError.new(msg)
|
54
77
|
end
|
@@ -62,6 +85,12 @@ module Lutaml
|
|
62
85
|
end
|
63
86
|
end
|
64
87
|
|
88
|
+
def validate_mappings!(_type)
|
89
|
+
if (@raw_mapping && Utils.present?(@mappings)) || (!@raw_mapping && @mappings.any?(&:raw_mapping?))
|
90
|
+
raise StandardError, "map_all is not allowed with other mappings"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
65
94
|
def deep_dup
|
66
95
|
self.class.new.tap do |new_mapping|
|
67
96
|
new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
|