lutaml-model 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|