lutaml-model 0.7.3 → 0.7.5
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/.envrc +1 -0
- data/.github/workflows/release.yml +3 -0
- data/.gitignore +6 -1
- data/.irbrc +1 -0
- data/.pryrc +1 -0
- data/.rubocop_todo.yml +25 -52
- data/README.adoc +2177 -192
- data/docs/custom_registers.adoc +228 -0
- data/docs/schema_generation.adoc +898 -0
- data/docs/schema_import.adoc +364 -0
- data/flake.lock +114 -0
- data/flake.nix +103 -0
- data/lib/lutaml/model/attribute.rb +230 -94
- data/lib/lutaml/model/choice.rb +30 -0
- data/lib/lutaml/model/collection.rb +194 -0
- data/lib/lutaml/model/comparable_model.rb +3 -3
- data/lib/lutaml/model/config.rb +26 -3
- data/lib/lutaml/model/constants.rb +2 -0
- data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
- data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
- data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
- data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
- data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
- data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
- data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
- data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
- data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
- data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
- data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
- data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
- data/lib/lutaml/model/error.rb +10 -0
- data/lib/lutaml/model/errors.rb +36 -0
- data/lib/lutaml/model/format_registry.rb +5 -2
- data/lib/lutaml/model/global_register.rb +41 -0
- data/lib/lutaml/model/{hash.rb → hash_adapter.rb} +5 -5
- data/lib/lutaml/model/jsonl/document.rb +14 -0
- data/lib/lutaml/model/jsonl/mapping.rb +19 -0
- data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
- data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
- data/lib/lutaml/model/jsonl/transform.rb +19 -0
- data/lib/lutaml/model/jsonl.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +3 -2
- data/lib/lutaml/model/mapping/key_value_mapping.rb +64 -4
- data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +4 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +8 -3
- data/lib/lutaml/model/register.rb +105 -0
- data/lib/lutaml/model/registrable.rb +6 -0
- data/lib/lutaml/model/schema/base_schema.rb +64 -0
- data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
- data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
- data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
- data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
- data/lib/lutaml/model/schema/generator/definition.rb +53 -0
- data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
- data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
- data/lib/lutaml/model/schema/generator/property.rb +110 -0
- data/lib/lutaml/model/schema/generator/ref.rb +24 -0
- data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
- data/lib/lutaml/model/schema/json_schema.rb +42 -49
- data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
- data/lib/lutaml/model/schema/renderer.rb +36 -0
- data/lib/lutaml/model/schema/shared_methods.rb +24 -0
- data/lib/lutaml/model/schema/templates/model.erb +9 -0
- data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
- data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
- data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
- data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
- data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
- data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
- data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
- data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
- data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
- data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
- data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
- data/lib/lutaml/model/schema.rb +1 -0
- data/lib/lutaml/model/sequence.rb +60 -30
- data/lib/lutaml/model/serialize.rb +175 -53
- data/lib/lutaml/model/services/base.rb +11 -0
- data/lib/lutaml/model/services/logger.rb +2 -2
- data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
- data/lib/lutaml/model/services/type/validator/number.rb +25 -0
- data/lib/lutaml/model/services/type/validator/string.rb +52 -0
- data/lib/lutaml/model/services/type/validator.rb +43 -0
- data/lib/lutaml/model/services/validator.rb +145 -0
- data/lib/lutaml/model/services.rb +3 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +60 -50
- data/lib/lutaml/model/transform/xml_transform.rb +46 -57
- data/lib/lutaml/model/transform.rb +22 -8
- data/lib/lutaml/model/type/boolean.rb +1 -1
- data/lib/lutaml/model/type/date.rb +1 -1
- data/lib/lutaml/model/type/date_time.rb +1 -1
- data/lib/lutaml/model/type/decimal.rb +11 -9
- data/lib/lutaml/model/type/float.rb +2 -1
- data/lib/lutaml/model/type/integer.rb +24 -21
- data/lib/lutaml/model/type/string.rb +4 -2
- data/lib/lutaml/model/type/time.rb +1 -1
- data/lib/lutaml/model/type/time_without_date.rb +1 -1
- data/lib/lutaml/model/type/value.rb +5 -1
- data/lib/lutaml/model/type.rb +5 -2
- data/lib/lutaml/model/utils.rb +30 -8
- data/lib/lutaml/model/validation.rb +6 -4
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml/document.rb +37 -19
- data/lib/lutaml/model/xml/mapping.rb +74 -13
- data/lib/lutaml/model/xml/mapping_rule.rb +10 -2
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +5 -3
- data/lib/lutaml/model/xml/oga/element.rb +4 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +4 -3
- data/lib/lutaml/model/xml/ox_adapter.rb +20 -6
- data/lib/lutaml/model/xml/xml_element.rb +3 -28
- data/lib/lutaml/model/xml_adapter/element.rb +1 -1
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +1 -1
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +1 -1
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +1 -1
- data/lib/lutaml/model/yamls/document.rb +14 -0
- data/lib/lutaml/model/yamls/mapping.rb +19 -0
- data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
- data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
- data/lib/lutaml/model/yamls/transform.rb +19 -0
- data/lib/lutaml/model/yamls.rb +21 -0
- data/lib/lutaml/model.rb +7 -31
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -5
- data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
- data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
- data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
- data/spec/fixtures/xml/product_catalog.xsd +151 -0
- data/spec/fixtures/xml/specifications_schema.xsd +38 -0
- data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
- data/spec/lutaml/model/attribute_spec.rb +41 -44
- data/spec/lutaml/model/choice_spec.rb +44 -0
- data/spec/lutaml/model/custom_collection_spec.rb +830 -0
- data/spec/lutaml/model/custom_model_spec.rb +15 -3
- data/spec/lutaml/model/defaults_spec.rb +5 -1
- data/spec/lutaml/model/global_register_spec.rb +108 -0
- data/spec/lutaml/model/group_spec.rb +9 -3
- data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
- data/spec/lutaml/model/jsonl_spec.rb +229 -0
- data/spec/lutaml/model/multiple_mapping_spec.rb +1 -1
- data/spec/lutaml/model/register/key_value_spec.rb +275 -0
- data/spec/lutaml/model/register/xml_spec.rb +187 -0
- data/spec/lutaml/model/register_spec.rb +147 -0
- data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
- data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
- data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
- data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
- data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
- data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
- data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
- data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
- data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
- data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
- data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
- data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
- data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
- data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
- data/spec/lutaml/model/sequence_spec.rb +36 -0
- data/spec/lutaml/model/serializable_spec.rb +31 -0
- data/spec/lutaml/model/type_spec.rb +8 -4
- data/spec/lutaml/model/utils_spec.rb +3 -3
- data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
- data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +24 -0
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +11 -4
- data/spec/lutaml/model/xml_mapping_spec.rb +1 -1
- data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
- data/spec/lutaml/model/yamls_spec.rb +294 -0
- data/spec/spec_helper.rb +1 -0
- metadata +105 -9
- data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
- /data/lib/lutaml/model/{hash → hash_adapter}/document.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/mapping.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/mapping_rule.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/standard_adapter.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/transform.rb +0 -0
@@ -0,0 +1,898 @@
|
|
1
|
+
= Schema generation
|
2
|
+
|
3
|
+
This document describes how to generate schemas from LutaML models.
|
4
|
+
|
5
|
+
== Schema generation
|
6
|
+
|
7
|
+
=== Overview
|
8
|
+
|
9
|
+
Lutaml::Model provides functionality to generate schema definitions from LutaML
|
10
|
+
models. This allows you to create schemas that can be used for validation or
|
11
|
+
documentation purposes.
|
12
|
+
|
13
|
+
The following figure illustrates the process of generating schemas from LutaML models.
|
14
|
+
Once the LutaML models are defined, they can be transformed into various schema formats
|
15
|
+
that can be used for validation, documentation, or other purposes.
|
16
|
+
|
17
|
+
.Generating serialization schemas from LutaML models
|
18
|
+
[source]
|
19
|
+
----
|
20
|
+
╔═══════════════════════╗ ╔════════════════════════════╗
|
21
|
+
║ Core Model ║ ║ Serialization Models ║
|
22
|
+
╚═══════════════════════╝ ╚════════════════════════════╝
|
23
|
+
|
24
|
+
╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮ ╭┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╮
|
25
|
+
┆ Model ┆ ┆ JSON/YAML/XML Schema ┆
|
26
|
+
┆ │ ┆ ┌────────────────┐ ┆ │ ┆
|
27
|
+
┆ ┌────────┴──┐ ┆ │ │ ┆ ┌──────┴──────┐ ┆
|
28
|
+
┆ │ │ ┆ │ Schema │ ┆ │ │ ┆
|
29
|
+
┆ Models Value Types ┆──►│ Generation │──►┆ Elements Validation ┆
|
30
|
+
┆ │ │ ┆ │ │ ┆ │ │ ┆
|
31
|
+
┆ │ │ ┆ └────────────────┘ ┆ │ │ ┆
|
32
|
+
┆ │ ┌──────┴──┐ ┆ │ ┆ ┌────┴────┐ ┌───┴───┐ ┆
|
33
|
+
┆ │ │ │ ┆ │ ┆ │ │ │ │ ┆
|
34
|
+
┆ │ String Integer ┆ │ ┆ Properties Patterns Enums ┆
|
35
|
+
┆ │ Date Float ┆ │ ┆ Definitions References ┆
|
36
|
+
┆ │ Time Boolean ┆ │ ┆ Types Min/Max ┆
|
37
|
+
┆ │ ┆ │ ┆ OneOf ┆
|
38
|
+
┆ └──────┐ ┆ │ ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯
|
39
|
+
┆ │ ┆ │
|
40
|
+
┆ Contains ┆ │ ┌────────────────┐
|
41
|
+
┆ more Models ┆ │ │ │
|
42
|
+
┆ (recursive) ┆ └───────────►│ Schema │
|
43
|
+
┆ ┆ │ Validation │
|
44
|
+
┆ ┆ │ │
|
45
|
+
╰┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╯ └────────────────┘
|
46
|
+
----
|
47
|
+
|
48
|
+
Currently, the following schema formats are supported:
|
49
|
+
|
50
|
+
* JSON Schema (https://json-schema.org/understanding-json-schema/[JSON Schema])
|
51
|
+
* YAML Schema (https://yaml.org/spec/1.2/spec.html[YAML])
|
52
|
+
* XSD (https://w3.org/TR/xmlschema-1/[XML Schema Definition Language])
|
53
|
+
* RELAX NG (https://relaxng.org/[RELAX NG])
|
54
|
+
|
55
|
+
|
56
|
+
=== JSON Schema generation
|
57
|
+
|
58
|
+
The `Lutaml::Model::Schema.to_json` method generates a JSON Schema from a LutaML
|
59
|
+
model class. The generated schema includes:
|
60
|
+
|
61
|
+
* Properties based on model attributes
|
62
|
+
* Validation constraints (patterns, enumerations, etc.)
|
63
|
+
* Support for polymorphic types
|
64
|
+
* Support for inheritance
|
65
|
+
* Support for choice attributes
|
66
|
+
* Collection constraints
|
67
|
+
|
68
|
+
==== Basic example
|
69
|
+
|
70
|
+
[example]
|
71
|
+
====
|
72
|
+
[source,ruby]
|
73
|
+
----
|
74
|
+
class Glaze < Lutaml::Model::Serializable
|
75
|
+
attribute :color, Lutaml::Model::Type::String
|
76
|
+
attribute :finish, Lutaml::Model::Type::String
|
77
|
+
end
|
78
|
+
|
79
|
+
class Vase < Lutaml::Model::Serializable
|
80
|
+
attribute :height, Lutaml::Model::Type::Float
|
81
|
+
attribute :diameter, Lutaml::Model::Type::Float
|
82
|
+
attribute :glaze, Glaze
|
83
|
+
attribute :materials, Lutaml::Model::Type::String, collection: true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Generate JSON schema
|
87
|
+
schema = Lutaml::Model::Schema.to_json(
|
88
|
+
Vase,
|
89
|
+
id: "https://example.com/vase.schema.json",
|
90
|
+
description: "A vase schema",
|
91
|
+
pretty: true
|
92
|
+
)
|
93
|
+
|
94
|
+
# Write to file
|
95
|
+
File.write("vase.schema.json", schema)
|
96
|
+
----
|
97
|
+
====
|
98
|
+
|
99
|
+
The generated schema will include definitions for all nested models and their
|
100
|
+
attributes. The output JSON schema would look like:
|
101
|
+
|
102
|
+
[source,json]
|
103
|
+
----
|
104
|
+
{
|
105
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
106
|
+
"$id": "https://example.com/vase.schema.json",
|
107
|
+
"description": "A vase schema",
|
108
|
+
"$ref": "#/$defs/Vase",
|
109
|
+
"$defs": {
|
110
|
+
"Vase": {
|
111
|
+
"type": "object",
|
112
|
+
"additionalProperties": false,
|
113
|
+
"properties": {
|
114
|
+
"height": {
|
115
|
+
"type": ["number", "null"]
|
116
|
+
},
|
117
|
+
"diameter": {
|
118
|
+
"type": ["number", "null"]
|
119
|
+
},
|
120
|
+
"glaze": {
|
121
|
+
"$ref": "#/$defs/Glaze"
|
122
|
+
},
|
123
|
+
"materials": {
|
124
|
+
"type": "array",
|
125
|
+
"items": {
|
126
|
+
"type": "string"
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
},
|
131
|
+
"Glaze": {
|
132
|
+
"type": "object",
|
133
|
+
"additionalProperties": false,
|
134
|
+
"properties": {
|
135
|
+
"color": {
|
136
|
+
"type": ["string", "null"]
|
137
|
+
},
|
138
|
+
"finish": {
|
139
|
+
"type": ["string", "null"]
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
----
|
146
|
+
|
147
|
+
==== Advanced examples
|
148
|
+
|
149
|
+
===== Models with validation constraints
|
150
|
+
|
151
|
+
[example]
|
152
|
+
====
|
153
|
+
[source,ruby]
|
154
|
+
----
|
155
|
+
class ValidationModel < Lutaml::Model::Serializable
|
156
|
+
attribute :name, Lutaml::Model::Type::String, values: %w[Alice Bob Charlie]
|
157
|
+
attribute :email, Lutaml::Model::Type::String, pattern: /.*?\S+@.+\.\S+/
|
158
|
+
attribute :age, Lutaml::Model::Type::Integer, collection: 1..3
|
159
|
+
attribute :score, Lutaml::Model::Type::Float, default: 0.0
|
160
|
+
end
|
161
|
+
|
162
|
+
# Generate JSON schema
|
163
|
+
schema = Lutaml::Model::Schema.to_json(ValidationModel, pretty: true)
|
164
|
+
----
|
165
|
+
====
|
166
|
+
|
167
|
+
The generated schema will include validation constraints:
|
168
|
+
|
169
|
+
[source,json]
|
170
|
+
----
|
171
|
+
{
|
172
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
173
|
+
"$ref": "#/$defs/ValidationModel",
|
174
|
+
"$defs": {
|
175
|
+
"ValidationModel": {
|
176
|
+
"type": "object",
|
177
|
+
"additionalProperties": false,
|
178
|
+
"properties": {
|
179
|
+
"name": {
|
180
|
+
"type": ["string", "null"],
|
181
|
+
"enum": ["Alice", "Bob", "Charlie"]
|
182
|
+
},
|
183
|
+
"email": {
|
184
|
+
"type": ["string", "null"],
|
185
|
+
"pattern": ".*?\\S+@.+\\.\\S+"
|
186
|
+
},
|
187
|
+
"age": {
|
188
|
+
"type": "array",
|
189
|
+
"items": {
|
190
|
+
"type": "integer"
|
191
|
+
},
|
192
|
+
"minItems": 1,
|
193
|
+
"maxItems": 3
|
194
|
+
},
|
195
|
+
"score": {
|
196
|
+
"type": ["number", "null"],
|
197
|
+
"default": 0.0
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
----
|
204
|
+
|
205
|
+
===== Models with choice attributes
|
206
|
+
|
207
|
+
[example]
|
208
|
+
====
|
209
|
+
[source,ruby]
|
210
|
+
----
|
211
|
+
class ChoiceModel < Lutaml::Model::Serializable
|
212
|
+
attribute :name, Lutaml::Model::Type::String
|
213
|
+
attribute :email, Lutaml::Model::Type::String
|
214
|
+
attribute :phone, Lutaml::Model::Type::String
|
215
|
+
|
216
|
+
choice(min: 1, max: 2) do
|
217
|
+
attribute :email, Lutaml::Model::Type::String
|
218
|
+
attribute :phone, Lutaml::Model::Type::String
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Generate JSON schema
|
223
|
+
schema = Lutaml::Model::Schema.to_json(ChoiceModel, pretty: true)
|
224
|
+
----
|
225
|
+
====
|
226
|
+
|
227
|
+
The generated schema will include choice constraints:
|
228
|
+
|
229
|
+
[source,json]
|
230
|
+
----
|
231
|
+
{
|
232
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
233
|
+
"$ref": "#/$defs/ChoiceModel",
|
234
|
+
"$defs": {
|
235
|
+
"ChoiceModel": {
|
236
|
+
"type": "object",
|
237
|
+
"additionalProperties": false,
|
238
|
+
"properties": {
|
239
|
+
"name": {
|
240
|
+
"type": ["string", "null"]
|
241
|
+
},
|
242
|
+
"email": {
|
243
|
+
"type": ["string", "null"]
|
244
|
+
},
|
245
|
+
"phone": {
|
246
|
+
"type": ["string", "null"]
|
247
|
+
}
|
248
|
+
},
|
249
|
+
"oneOf": [
|
250
|
+
{
|
251
|
+
"type": "object",
|
252
|
+
"properties": {
|
253
|
+
"email": {
|
254
|
+
"type": ["string", "null"]
|
255
|
+
},
|
256
|
+
"phone": {
|
257
|
+
"type": ["string", "null"]
|
258
|
+
}
|
259
|
+
}
|
260
|
+
}
|
261
|
+
]
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
----
|
266
|
+
|
267
|
+
===== Models with polymorphic types
|
268
|
+
|
269
|
+
[example]
|
270
|
+
====
|
271
|
+
[source,ruby]
|
272
|
+
----
|
273
|
+
class Shape < Lutaml::Model::Serializable
|
274
|
+
attribute :area, :float
|
275
|
+
end
|
276
|
+
|
277
|
+
class Circle < Shape
|
278
|
+
attribute :radius, Lutaml::Model::Type::Float
|
279
|
+
end
|
280
|
+
|
281
|
+
class Square < Shape
|
282
|
+
attribute :side, Lutaml::Model::Type::Float
|
283
|
+
end
|
284
|
+
|
285
|
+
class PolymorphicModel < Lutaml::Model::Serializable
|
286
|
+
attribute :shape, Shape, polymorphic: [Circle, Square]
|
287
|
+
end
|
288
|
+
|
289
|
+
# Generate JSON schema
|
290
|
+
schema = Lutaml::Model::Schema.to_json(PolymorphicModel, pretty: true)
|
291
|
+
----
|
292
|
+
====
|
293
|
+
|
294
|
+
The generated schema will include polymorphic type constraints:
|
295
|
+
|
296
|
+
[source,json]
|
297
|
+
----
|
298
|
+
{
|
299
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
300
|
+
"$ref": "#/$defs/PolymorphicModel",
|
301
|
+
"$defs": {
|
302
|
+
"PolymorphicModel": {
|
303
|
+
"type": "object",
|
304
|
+
"additionalProperties": false,
|
305
|
+
"properties": {
|
306
|
+
"shape": {
|
307
|
+
"type": ["object", "null"],
|
308
|
+
"oneOf": [
|
309
|
+
{
|
310
|
+
"$ref": "#/$defs/Circle"
|
311
|
+
},
|
312
|
+
{
|
313
|
+
"$ref": "#/$defs/Square"
|
314
|
+
},
|
315
|
+
{
|
316
|
+
"$ref": "#/$defs/Shape"
|
317
|
+
}
|
318
|
+
]
|
319
|
+
}
|
320
|
+
}
|
321
|
+
},
|
322
|
+
"Circle": {
|
323
|
+
"type": "object",
|
324
|
+
"additionalProperties": false,
|
325
|
+
"properties": {
|
326
|
+
"area": {
|
327
|
+
"type": ["number", "null"]
|
328
|
+
},
|
329
|
+
"radius": {
|
330
|
+
"type": ["number", "null"]
|
331
|
+
}
|
332
|
+
}
|
333
|
+
},
|
334
|
+
"Square": {
|
335
|
+
"type": "object",
|
336
|
+
"additionalProperties": false,
|
337
|
+
"properties": {
|
338
|
+
"area": {
|
339
|
+
"type": ["number", "null"]
|
340
|
+
},
|
341
|
+
"side": {
|
342
|
+
"type": ["number", "null"]
|
343
|
+
}
|
344
|
+
}
|
345
|
+
},
|
346
|
+
"Shape": {
|
347
|
+
"type": "object",
|
348
|
+
"additionalProperties": false,
|
349
|
+
"properties": {
|
350
|
+
"area": {
|
351
|
+
"type": ["number", "null"]
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
}
|
357
|
+
----
|
358
|
+
|
359
|
+
=== YAML Schema generation
|
360
|
+
|
361
|
+
The `Lutaml::Model::Schema.to_yaml` method generates a YAML Schema from a LutaML
|
362
|
+
model class. The generated schema includes the same features as the JSON Schema
|
363
|
+
generation.
|
364
|
+
|
365
|
+
==== Basic example
|
366
|
+
|
367
|
+
[example]
|
368
|
+
====
|
369
|
+
[source,ruby]
|
370
|
+
----
|
371
|
+
class Glaze < Lutaml::Model::Serializable
|
372
|
+
attribute :color, Lutaml::Model::Type::String
|
373
|
+
attribute :finish, Lutaml::Model::Type::String
|
374
|
+
end
|
375
|
+
|
376
|
+
class Vase < Lutaml::Model::Serializable
|
377
|
+
attribute :height, Lutaml::Model::Type::Float
|
378
|
+
attribute :diameter, Lutaml::Model::Type::Float
|
379
|
+
attribute :glaze, Glaze
|
380
|
+
attribute :materials, Lutaml::Model::Type::String, collection: true
|
381
|
+
end
|
382
|
+
|
383
|
+
# Generate YAML schema
|
384
|
+
schema = Lutaml::Model::Schema.to_yaml(
|
385
|
+
Vase,
|
386
|
+
id: "http://stsci.edu/schemas/yaml-schema/draft-01",
|
387
|
+
description: "A vase schema",
|
388
|
+
pretty: true
|
389
|
+
)
|
390
|
+
|
391
|
+
# Write to file
|
392
|
+
File.write("vase.schema.yaml", schema)
|
393
|
+
----
|
394
|
+
====
|
395
|
+
|
396
|
+
The generated YAML schema would look like:
|
397
|
+
|
398
|
+
[source,yaml]
|
399
|
+
----
|
400
|
+
%YAML 1.1
|
401
|
+
---
|
402
|
+
"$schema": https://json-schema.org/draft/2020-12/schema
|
403
|
+
"$id": http://stsci.edu/schemas/yaml-schema/draft-01
|
404
|
+
description: A vase schema
|
405
|
+
"$ref": "#/$defs/Vase"
|
406
|
+
"$defs":
|
407
|
+
Vase:
|
408
|
+
type: object
|
409
|
+
additionalProperties: false
|
410
|
+
properties:
|
411
|
+
height:
|
412
|
+
type:
|
413
|
+
- number
|
414
|
+
- 'null'
|
415
|
+
diameter:
|
416
|
+
type:
|
417
|
+
- number
|
418
|
+
- 'null'
|
419
|
+
glaze:
|
420
|
+
"$ref": "#/$defs/Glaze"
|
421
|
+
materials:
|
422
|
+
type: array
|
423
|
+
items:
|
424
|
+
type: string
|
425
|
+
Glaze:
|
426
|
+
type: object
|
427
|
+
additionalProperties: false
|
428
|
+
properties:
|
429
|
+
color:
|
430
|
+
type:
|
431
|
+
- string
|
432
|
+
- 'null'
|
433
|
+
finish:
|
434
|
+
type:
|
435
|
+
- string
|
436
|
+
- 'null'
|
437
|
+
----
|
438
|
+
|
439
|
+
==== Advanced examples
|
440
|
+
|
441
|
+
===== Models with validation constraints
|
442
|
+
|
443
|
+
[example]
|
444
|
+
====
|
445
|
+
[source,ruby]
|
446
|
+
----
|
447
|
+
class ValidationModel < Lutaml::Model::Serializable
|
448
|
+
attribute :name, Lutaml::Model::Type::String, values: %w[Alice Bob Charlie]
|
449
|
+
attribute :email, Lutaml::Model::Type::String, pattern: /.*?\S+@.+\.\S+/
|
450
|
+
attribute :age, Lutaml::Model::Type::Integer, collection: 1..3
|
451
|
+
attribute :score, Lutaml::Model::Type::Float, default: 0.0
|
452
|
+
end
|
453
|
+
|
454
|
+
# Generate YAML schema
|
455
|
+
schema = Lutaml::Model::Schema.to_yaml(ValidationModel)
|
456
|
+
----
|
457
|
+
====
|
458
|
+
|
459
|
+
The generated schema will include validation constraints:
|
460
|
+
|
461
|
+
[source,yaml]
|
462
|
+
----
|
463
|
+
%YAML 1.1
|
464
|
+
---
|
465
|
+
"$schema": https://json-schema.org/draft/2020-12/schema
|
466
|
+
"$ref": "#/$defs/ValidationModel"
|
467
|
+
"$defs":
|
468
|
+
ValidationModel:
|
469
|
+
type: object
|
470
|
+
additionalProperties: false
|
471
|
+
properties:
|
472
|
+
name:
|
473
|
+
type:
|
474
|
+
- string
|
475
|
+
- 'null'
|
476
|
+
enum:
|
477
|
+
- Alice
|
478
|
+
- Bob
|
479
|
+
- Charlie
|
480
|
+
email:
|
481
|
+
type:
|
482
|
+
- string
|
483
|
+
- 'null'
|
484
|
+
pattern: ".*?\\S+@.+\\.\\S+"
|
485
|
+
age:
|
486
|
+
type: array
|
487
|
+
items:
|
488
|
+
type: integer
|
489
|
+
minItems: 1
|
490
|
+
maxItems: 3
|
491
|
+
score:
|
492
|
+
type:
|
493
|
+
- number
|
494
|
+
- 'null'
|
495
|
+
default: 0.0
|
496
|
+
----
|
497
|
+
|
498
|
+
===== Models with polymorphic types
|
499
|
+
|
500
|
+
[example]
|
501
|
+
====
|
502
|
+
[source,ruby]
|
503
|
+
----
|
504
|
+
class Shape < Lutaml::Model::Serializable
|
505
|
+
attribute :area, :float
|
506
|
+
end
|
507
|
+
|
508
|
+
class Circle < Shape
|
509
|
+
attribute :radius, Lutaml::Model::Type::Float
|
510
|
+
end
|
511
|
+
|
512
|
+
class Square < Shape
|
513
|
+
attribute :side, Lutaml::Model::Type::Float
|
514
|
+
end
|
515
|
+
|
516
|
+
class PolymorphicModel < Lutaml::Model::Serializable
|
517
|
+
attribute :shape, Shape, polymorphic: [Circle, Square]
|
518
|
+
end
|
519
|
+
|
520
|
+
# Generate YAML schema
|
521
|
+
schema = Lutaml::Model::Schema.to_yaml(PolymorphicModel)
|
522
|
+
----
|
523
|
+
====
|
524
|
+
|
525
|
+
The generated schema will include polymorphic type constraints:
|
526
|
+
|
527
|
+
[source,yaml]
|
528
|
+
----
|
529
|
+
%YAML 1.1
|
530
|
+
---
|
531
|
+
"$schema": https://json-schema.org/draft/2020-12/schema
|
532
|
+
"$ref": "#/$defs/PolymorphicModel"
|
533
|
+
"$defs":
|
534
|
+
PolymorphicModel:
|
535
|
+
type: object
|
536
|
+
additionalProperties: false
|
537
|
+
properties:
|
538
|
+
shape:
|
539
|
+
type:
|
540
|
+
- object
|
541
|
+
- 'null'
|
542
|
+
oneOf:
|
543
|
+
- "$ref": "#/$defs/Circle"
|
544
|
+
- "$ref": "#/$defs/Square"
|
545
|
+
- "$ref": "#/$defs/Shape"
|
546
|
+
Shape:
|
547
|
+
type: object
|
548
|
+
additionalProperties: false
|
549
|
+
properties:
|
550
|
+
area:
|
551
|
+
type:
|
552
|
+
- number
|
553
|
+
- 'null'
|
554
|
+
Circle:
|
555
|
+
type: object
|
556
|
+
additionalProperties: false
|
557
|
+
properties:
|
558
|
+
area:
|
559
|
+
type:
|
560
|
+
- number
|
561
|
+
- 'null'
|
562
|
+
radius:
|
563
|
+
type:
|
564
|
+
- number
|
565
|
+
- 'null'
|
566
|
+
Square:
|
567
|
+
type: object
|
568
|
+
additionalProperties: false
|
569
|
+
properties:
|
570
|
+
area:
|
571
|
+
type:
|
572
|
+
- number
|
573
|
+
- 'null'
|
574
|
+
side:
|
575
|
+
type:
|
576
|
+
- number
|
577
|
+
- 'null'
|
578
|
+
----
|
579
|
+
|
580
|
+
=== XSD Schema generation
|
581
|
+
|
582
|
+
The `Lutaml::Model::Schema.to_xsd` method generates an XML Schema (XSD) from a LutaML
|
583
|
+
model class. The generated schema includes:
|
584
|
+
|
585
|
+
* Element definitions based on model attributes
|
586
|
+
* Complex types for nested models
|
587
|
+
* Support for collections
|
588
|
+
* XML namespace support
|
589
|
+
* Validation constraints
|
590
|
+
|
591
|
+
==== Basic example
|
592
|
+
|
593
|
+
[example]
|
594
|
+
====
|
595
|
+
[source,ruby]
|
596
|
+
----
|
597
|
+
class Glaze < Lutaml::Model::Serializable
|
598
|
+
attribute :color, Lutaml::Model::Type::String
|
599
|
+
attribute :finish, Lutaml::Model::Type::String
|
600
|
+
end
|
601
|
+
|
602
|
+
class Vase < Lutaml::Model::Serializable
|
603
|
+
attribute :height, Lutaml::Model::Type::Float
|
604
|
+
attribute :diameter, Lutaml::Model::Type::Float
|
605
|
+
attribute :glaze, Glaze
|
606
|
+
attribute :materials, Lutaml::Model::Type::String, collection: true
|
607
|
+
end
|
608
|
+
|
609
|
+
# Generate XSD schema
|
610
|
+
schema = Lutaml::Model::Schema.to_xsd(
|
611
|
+
Vase,
|
612
|
+
namespace: "http://example.com/vase",
|
613
|
+
prefix: "vase",
|
614
|
+
pretty: true
|
615
|
+
)
|
616
|
+
|
617
|
+
# Write to file
|
618
|
+
File.write("vase.xsd", schema)
|
619
|
+
----
|
620
|
+
====
|
621
|
+
|
622
|
+
The generated XSD schema would look like:
|
623
|
+
|
624
|
+
[source,xml]
|
625
|
+
----
|
626
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
627
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
628
|
+
xmlns:vase="http://example.com/vase"
|
629
|
+
targetNamespace="http://example.com/vase"
|
630
|
+
elementFormDefault="qualified">
|
631
|
+
<xs:element name="Vase">
|
632
|
+
<xs:complexType>
|
633
|
+
<xs:sequence>
|
634
|
+
<xs:element name="height" type="xs:float"/>
|
635
|
+
<xs:element name="diameter" type="xs:float"/>
|
636
|
+
<xs:element name="glaze" type="vase:Glaze"/>
|
637
|
+
<xs:element name="materials" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
|
638
|
+
</xs:sequence>
|
639
|
+
</xs:complexType>
|
640
|
+
</xs:element>
|
641
|
+
|
642
|
+
<xs:complexType name="Glaze">
|
643
|
+
<xs:sequence>
|
644
|
+
<xs:element name="color" type="xs:string"/>
|
645
|
+
<xs:element name="finish" type="xs:string"/>
|
646
|
+
</xs:sequence>
|
647
|
+
</xs:complexType>
|
648
|
+
</xs:schema>
|
649
|
+
----
|
650
|
+
|
651
|
+
==== Advanced examples
|
652
|
+
|
653
|
+
===== Models with validation constraints
|
654
|
+
|
655
|
+
[example]
|
656
|
+
====
|
657
|
+
[source,ruby]
|
658
|
+
----
|
659
|
+
class ValidationModel < Lutaml::Model::Serializable
|
660
|
+
attribute :name, Lutaml::Model::Type::String, values: %w[Alice Bob Charlie]
|
661
|
+
attribute :email, Lutaml::Model::Type::String, pattern: /.*?\S+@.+\.\S+/
|
662
|
+
attribute :age, Lutaml::Model::Type::Integer, collection: 1..3
|
663
|
+
attribute :score, Lutaml::Model::Type::Float, default: 0.0
|
664
|
+
end
|
665
|
+
|
666
|
+
# Generate XSD schema
|
667
|
+
schema = Lutaml::Model::Schema.to_xsd(ValidationModel, pretty: true)
|
668
|
+
----
|
669
|
+
====
|
670
|
+
|
671
|
+
The generated schema will include validation constraints:
|
672
|
+
|
673
|
+
[source,xml]
|
674
|
+
----
|
675
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
676
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
677
|
+
<xs:element name="ValidationModel">
|
678
|
+
<xs:complexType>
|
679
|
+
<xs:sequence>
|
680
|
+
<xs:element name="name">
|
681
|
+
<xs:simpleType>
|
682
|
+
<xs:restriction base="xs:string">
|
683
|
+
<xs:enumeration value="Alice"/>
|
684
|
+
<xs:enumeration value="Bob"/>
|
685
|
+
<xs:enumeration value="Charlie"/>
|
686
|
+
</xs:restriction>
|
687
|
+
</xs:simpleType>
|
688
|
+
</xs:element>
|
689
|
+
<xs:element name="email">
|
690
|
+
<xs:simpleType>
|
691
|
+
<xs:restriction base="xs:string">
|
692
|
+
<xs:pattern value=".*?\S+@.+\.\S+"/>
|
693
|
+
</xs:restriction>
|
694
|
+
</xs:simpleType>
|
695
|
+
</xs:element>
|
696
|
+
<xs:element name="age" minOccurs="1" maxOccurs="3" type="xs:integer"/>
|
697
|
+
<xs:element name="score" type="xs:float" default="0.0"/>
|
698
|
+
</xs:sequence>
|
699
|
+
</xs:complexType>
|
700
|
+
</xs:element>
|
701
|
+
</xs:schema>
|
702
|
+
----
|
703
|
+
|
704
|
+
===== Models with polymorphic types
|
705
|
+
|
706
|
+
[example]
|
707
|
+
====
|
708
|
+
[source,ruby]
|
709
|
+
----
|
710
|
+
class Shape < Lutaml::Model::Serializable
|
711
|
+
attribute :area, :float
|
712
|
+
end
|
713
|
+
|
714
|
+
class Circle < Shape
|
715
|
+
attribute :radius, Lutaml::Model::Type::Float
|
716
|
+
end
|
717
|
+
|
718
|
+
class Square < Shape
|
719
|
+
attribute :side, Lutaml::Model::Type::Float
|
720
|
+
end
|
721
|
+
|
722
|
+
class PolymorphicModel < Lutaml::Model::Serializable
|
723
|
+
attribute :shape, Shape, polymorphic: [Circle, Square]
|
724
|
+
end
|
725
|
+
|
726
|
+
# Generate XSD schema
|
727
|
+
schema = Lutaml::Model::Schema.to_xsd(PolymorphicModel, pretty: true)
|
728
|
+
----
|
729
|
+
====
|
730
|
+
|
731
|
+
The generated schema will include polymorphic type support:
|
732
|
+
|
733
|
+
[source,xml]
|
734
|
+
----
|
735
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
736
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
737
|
+
<xs:element name="PolymorphicModel">
|
738
|
+
<xs:complexType>
|
739
|
+
<xs:sequence>
|
740
|
+
<xs:element name="shape">
|
741
|
+
<xs:complexType>
|
742
|
+
<xs:choice>
|
743
|
+
<xs:element name="Circle">
|
744
|
+
<xs:complexType>
|
745
|
+
<xs:sequence>
|
746
|
+
<xs:element name="area" type="xs:float"/>
|
747
|
+
<xs:element name="radius" type="xs:float"/>
|
748
|
+
</xs:sequence>
|
749
|
+
</xs:complexType>
|
750
|
+
</xs:element>
|
751
|
+
<xs:element name="Square">
|
752
|
+
<xs:complexType>
|
753
|
+
<xs:sequence>
|
754
|
+
<xs:element name="area" type="xs:float"/>
|
755
|
+
<xs:element name="side" type="xs:float"/>
|
756
|
+
</xs:sequence>
|
757
|
+
</xs:complexType>
|
758
|
+
</xs:element>
|
759
|
+
<xs:element name="Shape">
|
760
|
+
<xs:complexType>
|
761
|
+
<xs:sequence>
|
762
|
+
<xs:element name="area" type="xs:float"/>
|
763
|
+
</xs:sequence>
|
764
|
+
</xs:complexType>
|
765
|
+
</xs:element>
|
766
|
+
</xs:choice>
|
767
|
+
</xs:complexType>
|
768
|
+
</xs:element>
|
769
|
+
</xs:sequence>
|
770
|
+
</xs:complexType>
|
771
|
+
</xs:element>
|
772
|
+
</xs:schema>
|
773
|
+
----
|
774
|
+
|
775
|
+
=== RELAX NG Schema generation
|
776
|
+
|
777
|
+
The `Lutaml::Model::Schema::RelaxngSchema.generate` method generates a RELAX NG schema from a LutaML
|
778
|
+
model class. The generated schema includes:
|
779
|
+
|
780
|
+
* Element definitions based on model attributes
|
781
|
+
* Named patterns for nested models
|
782
|
+
* Support for collections
|
783
|
+
|
784
|
+
==== Basic example
|
785
|
+
|
786
|
+
[example]
|
787
|
+
====
|
788
|
+
[source,ruby]
|
789
|
+
----
|
790
|
+
class Glaze < Lutaml::Model::Serializable
|
791
|
+
attribute :color, Lutaml::Model::Type::String
|
792
|
+
attribute :finish, Lutaml::Model::Type::String
|
793
|
+
end
|
794
|
+
|
795
|
+
class Vase < Lutaml::Model::Serializable
|
796
|
+
attribute :height, Lutaml::Model::Type::Float
|
797
|
+
attribute :diameter, Lutaml::Model::Type::Float
|
798
|
+
attribute :glaze, Glaze
|
799
|
+
attribute :materials, Lutaml::Model::Type::String, collection: true
|
800
|
+
end
|
801
|
+
|
802
|
+
# Generate RELAX NG schema
|
803
|
+
schema = Lutaml::Model::Schema::RelaxngSchema.generate(Vase, pretty: true)
|
804
|
+
|
805
|
+
# Write to file
|
806
|
+
File.write("vase.rng", schema)
|
807
|
+
----
|
808
|
+
====
|
809
|
+
|
810
|
+
The generated RELAX NG schema would look like:
|
811
|
+
|
812
|
+
[source,xml]
|
813
|
+
----
|
814
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
815
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
816
|
+
<start>
|
817
|
+
<ref name="Vase"/>
|
818
|
+
</start>
|
819
|
+
<define name="Vase">
|
820
|
+
<element name="Vase">
|
821
|
+
<element name="height">
|
822
|
+
<data type="float"/>
|
823
|
+
</element>
|
824
|
+
<element name="diameter">
|
825
|
+
<data type="float"/>
|
826
|
+
</element>
|
827
|
+
<ref name="Glaze"/>
|
828
|
+
<zeroOrMore>
|
829
|
+
<element name="materials">
|
830
|
+
<data type="string"/>
|
831
|
+
</element>
|
832
|
+
</zeroOrMore>
|
833
|
+
</element>
|
834
|
+
</define>
|
835
|
+
<define name="Glaze">
|
836
|
+
<element name="Glaze">
|
837
|
+
<element name="color">
|
838
|
+
<data type="string"/>
|
839
|
+
</element>
|
840
|
+
<element name="finish">
|
841
|
+
<data type="string"/>
|
842
|
+
</element>
|
843
|
+
</element>
|
844
|
+
</define>
|
845
|
+
</grammar>
|
846
|
+
----
|
847
|
+
|
848
|
+
==== Advanced examples
|
849
|
+
|
850
|
+
===== Models with validation constraints
|
851
|
+
|
852
|
+
[example]
|
853
|
+
====
|
854
|
+
[source,ruby]
|
855
|
+
----
|
856
|
+
class ValidationModel < Lutaml::Model::Serializable
|
857
|
+
attribute :name, Lutaml::Model::Type::String, values: %w[Alice Bob Charlie]
|
858
|
+
attribute :email, Lutaml::Model::Type::String, pattern: /.*?\S+@.+\.\S+/
|
859
|
+
attribute :age, Lutaml::Model::Type::Integer, collection: 1..3
|
860
|
+
end
|
861
|
+
|
862
|
+
# Generate RELAX NG schema
|
863
|
+
schema = Lutaml::Model::Schema::RelaxngSchema.generate(ValidationModel, pretty: true)
|
864
|
+
----
|
865
|
+
====
|
866
|
+
|
867
|
+
The generated schema will include validation constraints:
|
868
|
+
|
869
|
+
[source,xml]
|
870
|
+
----
|
871
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
872
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
873
|
+
<start>
|
874
|
+
<ref name="ValidationModel"/>
|
875
|
+
</start>
|
876
|
+
<define name="ValidationModel">
|
877
|
+
<element name="ValidationModel">
|
878
|
+
<element name="name">
|
879
|
+
<choice>
|
880
|
+
<value>Alice</value>
|
881
|
+
<value>Bob</value>
|
882
|
+
<value>Charlie</value>
|
883
|
+
</choice>
|
884
|
+
</element>
|
885
|
+
<element name="email">
|
886
|
+
<data type="string">
|
887
|
+
<param name="pattern">.*?\S+@.+\.\S+</param>
|
888
|
+
</data>
|
889
|
+
</element>
|
890
|
+
<oneOrMore>
|
891
|
+
<element name="age">
|
892
|
+
<data type="integer"/>
|
893
|
+
</element>
|
894
|
+
</oneOrMore>
|
895
|
+
</element>
|
896
|
+
</define>
|
897
|
+
</grammar>
|
898
|
+
----
|