lutaml-model 0.8.3 → 0.8.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/.github/workflows/dependent-tests.yml +3 -1
- data/.rubocop.yml +18 -0
- data/.rubocop_todo.yml +16 -22
- data/Gemfile +2 -0
- data/README.adoc +327 -3
- data/docs/_guides/document-validation.adoc +303 -0
- data/docs/_guides/index.adoc +19 -0
- data/docs/_guides/jsonld-serialization.adoc +217 -0
- data/docs/_guides/rdf-serialization.adoc +344 -0
- data/docs/_guides/turtle-serialization.adoc +224 -0
- data/docs/_guides/xml-mapping.adoc +9 -1
- data/docs/_guides/xml_mappings/07_best_practices.adoc +36 -0
- data/docs/_guides/xml_mappings/08_troubleshooting.adoc +89 -0
- data/docs/_pages/serialization_adapters.adoc +31 -0
- data/docs/_references/index.adoc +1 -0
- data/docs/_references/rdf-namespaces.adoc +243 -0
- data/docs/_tutorials/lutaml-xml-architecture.adoc +6 -1
- data/docs/index.adoc +3 -2
- data/lib/lutaml/jsonld/adapter.rb +23 -0
- data/lib/lutaml/jsonld/context.rb +69 -0
- data/lib/lutaml/jsonld/term_definition.rb +39 -0
- data/lib/lutaml/jsonld/transform.rb +174 -0
- data/lib/lutaml/jsonld.rb +23 -0
- data/lib/lutaml/model/attribute.rb +19 -1
- data/lib/lutaml/model/error/liquid_drop_already_registered_error.rb +11 -0
- data/lib/lutaml/model/error/ordered_content_mapping_error.rb +17 -0
- data/lib/lutaml/model/format_registry.rb +10 -1
- data/lib/lutaml/model/global_context.rb +1 -0
- data/lib/lutaml/model/liquefiable.rb +12 -15
- data/lib/lutaml/model/mapping/mapping_rule.rb +10 -2
- data/lib/lutaml/model/mapping_hash.rb +1 -1
- data/lib/lutaml/model/serialize/format_conversion.rb +17 -1
- data/lib/lutaml/model/services/transformer.rb +67 -32
- data/lib/lutaml/model/transform.rb +41 -4
- data/lib/lutaml/model/uninitialized_class.rb +11 -5
- data/lib/lutaml/model/validation/concerns/has_issues.rb +27 -0
- data/lib/lutaml/model/validation/context.rb +36 -0
- data/lib/lutaml/model/validation/issue.rb +62 -0
- data/lib/lutaml/model/validation/layer_result.rb +34 -0
- data/lib/lutaml/model/validation/profile.rb +66 -0
- data/lib/lutaml/model/validation/registry.rb +60 -0
- data/lib/lutaml/model/validation/remediation.rb +33 -0
- data/lib/lutaml/model/validation/remediation_result.rb +20 -0
- data/lib/lutaml/model/validation/report.rb +39 -0
- data/lib/lutaml/model/validation/rule.rb +59 -0
- data/lib/lutaml/model/validation.rb +2 -1
- data/lib/lutaml/model/validation_framework.rb +77 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +10 -0
- data/lib/lutaml/rdf/error.rb +7 -0
- data/lib/lutaml/rdf/iri.rb +44 -0
- data/lib/lutaml/rdf/language_tagged.rb +11 -0
- data/lib/lutaml/rdf/literal.rb +62 -0
- data/lib/lutaml/rdf/mapping.rb +71 -0
- data/lib/lutaml/rdf/mapping_rule.rb +35 -0
- data/lib/lutaml/rdf/member_rule.rb +13 -0
- data/lib/lutaml/rdf/namespace.rb +58 -0
- data/lib/lutaml/rdf/namespace_set.rb +69 -0
- data/lib/lutaml/rdf/namespaces/dcterms_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/owl_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/rdf_namespace.rb +14 -0
- data/lib/lutaml/rdf/namespaces/rdfs_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/skos_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/xsd_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces.rb +14 -0
- data/lib/lutaml/rdf/transform.rb +36 -0
- data/lib/lutaml/rdf.rb +19 -0
- data/lib/lutaml/turtle/adapter.rb +35 -0
- data/lib/lutaml/turtle/mapping.rb +7 -0
- data/lib/lutaml/turtle/transform.rb +158 -0
- data/lib/lutaml/turtle.rb +22 -0
- data/lib/lutaml/xml/adapter/nokogiri_adapter.rb +9 -2
- data/lib/lutaml/xml/adapter/oga_adapter.rb +11 -3
- data/lib/lutaml/xml/adapter/ox_adapter.rb +5 -2
- data/lib/lutaml/xml/adapter/rexml_adapter.rb +10 -3
- data/lib/lutaml/xml/adapter_element.rb +26 -2
- data/lib/lutaml/xml/data_model.rb +14 -0
- data/lib/lutaml/xml/document.rb +3 -0
- data/lib/lutaml/xml/element.rb +8 -2
- data/lib/lutaml/xml/mapping.rb +9 -0
- data/lib/lutaml/xml/model_transform.rb +42 -0
- data/lib/lutaml/xml/schema/xsd/base.rb +4 -1
- data/lib/lutaml/xml/serialization/instance_methods.rb +3 -1
- data/lib/lutaml/xml/transformation/ordered_applier.rb +46 -2
- data/lib/lutaml/xml/transformation.rb +40 -1
- data/lib/lutaml/xml/xml_element.rb +8 -7
- data/lutaml-model.gemspec +1 -1
- data/spec/lutaml/integration/edge_cases_spec.rb +109 -0
- data/spec/lutaml/integration/multi_format_spec.rb +106 -0
- data/spec/lutaml/integration/round_trip_spec.rb +170 -0
- data/spec/lutaml/jsonld/adapter_spec.rb +46 -0
- data/spec/lutaml/jsonld/context_spec.rb +114 -0
- data/spec/lutaml/jsonld/term_definition_spec.rb +55 -0
- data/spec/lutaml/jsonld/transform_spec.rb +211 -0
- data/spec/lutaml/model/attribute_default_cache_spec.rb +58 -0
- data/spec/lutaml/model/liquefiable_spec.rb +22 -6
- data/spec/lutaml/model/liquid_compatibility_spec.rb +442 -0
- data/spec/lutaml/model/ordered_content_spec.rb +5 -5
- data/spec/lutaml/model/services/transformer_spec.rb +43 -0
- data/spec/lutaml/model/transform_cache_spec.rb +62 -0
- data/spec/lutaml/model/transform_dynamic_attributes_spec.rb +41 -0
- data/spec/lutaml/model/uninitialized_class_deep_dup_spec.rb +39 -0
- data/spec/lutaml/model/uninitialized_class_spec.rb +14 -2
- data/spec/lutaml/model/validation/concerns/has_issues_spec.rb +76 -0
- data/spec/lutaml/model/validation/context_spec.rb +60 -0
- data/spec/lutaml/model/validation/issue_spec.rb +77 -0
- data/spec/lutaml/model/validation/layer_result_spec.rb +66 -0
- data/spec/lutaml/model/validation/profile_spec.rb +134 -0
- data/spec/lutaml/model/validation/registry_spec.rb +94 -0
- data/spec/lutaml/model/validation/remediation_result_spec.rb +23 -0
- data/spec/lutaml/model/validation/remediation_spec.rb +72 -0
- data/spec/lutaml/model/validation/report_spec.rb +58 -0
- data/spec/lutaml/model/validation/rule_spec.rb +134 -0
- data/spec/lutaml/model/validation/uninitialized_class_validate_spec.rb +29 -0
- data/spec/lutaml/model/validation/validation_error_spec.rb +29 -0
- data/spec/lutaml/model/validation/validation_framework_spec.rb +110 -0
- data/spec/lutaml/rdf/graph_serialization_spec.rb +137 -0
- data/spec/lutaml/rdf/iri_spec.rb +73 -0
- data/spec/lutaml/rdf/literal_spec.rb +98 -0
- data/spec/lutaml/rdf/mapping_spec.rb +164 -0
- data/spec/lutaml/rdf/member_rule_spec.rb +17 -0
- data/spec/lutaml/rdf/namespace_set_spec.rb +115 -0
- data/spec/lutaml/rdf/namespace_spec.rb +241 -0
- data/spec/lutaml/rdf/rdf_transform_spec.rb +82 -0
- data/spec/lutaml/turtle/adapter_spec.rb +47 -0
- data/spec/lutaml/turtle/mapping_spec.rb +123 -0
- data/spec/lutaml/turtle/transform_spec.rb +273 -0
- data/spec/lutaml/xml/content_model_validation_spec.rb +157 -0
- data/spec/lutaml/xml/mapping_spec.rb +12 -7
- metadata +95 -7
- data/spec/fixtures/liquid_templates/_ceramics.liquid +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bc036758cf2a4ac1420e14fc6be130730410ab183cd002ced260bdbf08793eb
|
|
4
|
+
data.tar.gz: 1dfc1b473558992eb1481a535d86c1688313951530762c9317af90413028032e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a4cec37c9acf840b89f6f363aecb8e7bf1a2237d962c6fa8bbe4d4422848cc63812efbd86369780c0e7d26470ff9f220284d062af86b9ebf7f621f3f8e579cb
|
|
7
|
+
data.tar.gz: a48c77e4d99c97fb8cc6fa6793a45b2ba12b79196d9340a23bf4d43a1090c84c05a2402a84ab52792b105713c78caa51f58cfcb141cf79459b06c929adac11b5
|
|
@@ -19,6 +19,8 @@ on:
|
|
|
19
19
|
|
|
20
20
|
jobs:
|
|
21
21
|
rake:
|
|
22
|
-
uses: metanorma/ci/.github/workflows/dependent-rake.yml@
|
|
22
|
+
uses: metanorma/ci/.github/workflows/dependent-rake.yml@fix/add-pat-token
|
|
23
23
|
with:
|
|
24
24
|
command: bundle exec rspec
|
|
25
|
+
secrets:
|
|
26
|
+
pat_token: ${{ secrets.LUTAML_CI_PAT_TOKEN }}
|
data/.rubocop.yml
CHANGED
|
@@ -24,3 +24,21 @@ Style/OneClassPerFile:
|
|
|
24
24
|
- Exclude
|
|
25
25
|
Exclude:
|
|
26
26
|
- 'spec/**/*'
|
|
27
|
+
|
|
28
|
+
RSpec/EmptyExampleGroup:
|
|
29
|
+
inherit_mode:
|
|
30
|
+
merge:
|
|
31
|
+
- Exclude
|
|
32
|
+
Exclude:
|
|
33
|
+
- 'spec/lutaml/jsonld/transform_spec.rb'
|
|
34
|
+
|
|
35
|
+
RSpec/NamedSubject:
|
|
36
|
+
inherit_mode:
|
|
37
|
+
merge:
|
|
38
|
+
- Exclude
|
|
39
|
+
Exclude:
|
|
40
|
+
- 'spec/lutaml/turtle/transform_spec.rb'
|
|
41
|
+
|
|
42
|
+
RSpec/ContextMethod:
|
|
43
|
+
Exclude:
|
|
44
|
+
- 'spec/lutaml/jsonld/transform_spec.rb'
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-05-
|
|
3
|
+
# on 2026-05-06 13:11:11 UTC using RuboCop version 1.86.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -11,15 +11,7 @@ Gemspec/RequiredRubyVersion:
|
|
|
11
11
|
Exclude:
|
|
12
12
|
- 'lutaml-model.gemspec'
|
|
13
13
|
|
|
14
|
-
# Offense count:
|
|
15
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
16
|
-
# Configuration parameters: AllowForAlignment.
|
|
17
|
-
Layout/CommentIndentation:
|
|
18
|
-
Exclude:
|
|
19
|
-
- 'lib/lutaml/model/mapping/listener.rb'
|
|
20
|
-
- 'lib/lutaml/model/services/base.rb'
|
|
21
|
-
|
|
22
|
-
# Offense count: 3210
|
|
14
|
+
# Offense count: 3264
|
|
23
15
|
# This cop supports safe autocorrection (--autocorrect).
|
|
24
16
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
25
17
|
# URISchemes: http, https
|
|
@@ -118,7 +110,7 @@ Lint/UselessConstantScoping:
|
|
|
118
110
|
- 'lib/lutaml/xml/adapter/nokogiri_adapter.rb'
|
|
119
111
|
- 'lib/lutaml/xml/mapping_rule.rb'
|
|
120
112
|
|
|
121
|
-
# Offense count:
|
|
113
|
+
# Offense count: 355
|
|
122
114
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
123
115
|
Metrics/AbcSize:
|
|
124
116
|
Enabled: false
|
|
@@ -134,23 +126,23 @@ Metrics/BlockLength:
|
|
|
134
126
|
Metrics/BlockNesting:
|
|
135
127
|
Max: 6
|
|
136
128
|
|
|
137
|
-
# Offense count:
|
|
129
|
+
# Offense count: 315
|
|
138
130
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
139
131
|
Metrics/CyclomaticComplexity:
|
|
140
132
|
Enabled: false
|
|
141
133
|
|
|
142
|
-
# Offense count:
|
|
134
|
+
# Offense count: 575
|
|
143
135
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
144
136
|
Metrics/MethodLength:
|
|
145
137
|
Max: 514
|
|
146
138
|
|
|
147
|
-
# Offense count:
|
|
139
|
+
# Offense count: 88
|
|
148
140
|
# Configuration parameters: CountKeywordArgs.
|
|
149
141
|
Metrics/ParameterLists:
|
|
150
142
|
Max: 24
|
|
151
143
|
MaxOptionalParameters: 5
|
|
152
144
|
|
|
153
|
-
# Offense count:
|
|
145
|
+
# Offense count: 264
|
|
154
146
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
155
147
|
Metrics/PerceivedComplexity:
|
|
156
148
|
Enabled: false
|
|
@@ -242,7 +234,7 @@ RSpec/BeforeAfterAll:
|
|
|
242
234
|
RSpec/ContextWording:
|
|
243
235
|
Enabled: false
|
|
244
236
|
|
|
245
|
-
# Offense count:
|
|
237
|
+
# Offense count: 92
|
|
246
238
|
# Configuration parameters: IgnoredMetadata.
|
|
247
239
|
RSpec/DescribeClass:
|
|
248
240
|
Enabled: false
|
|
@@ -253,7 +245,7 @@ RSpec/DescribeMethod:
|
|
|
253
245
|
- 'spec/lutaml/xml/schema/xsd/schema_helper_methods_spec.rb'
|
|
254
246
|
- 'spec/lutaml/xml/serializable_namespace_spec.rb'
|
|
255
247
|
|
|
256
|
-
# Offense count:
|
|
248
|
+
# Offense count: 1234
|
|
257
249
|
# Configuration parameters: CountAsOne.
|
|
258
250
|
RSpec/ExampleLength:
|
|
259
251
|
Max: 68
|
|
@@ -328,11 +320,11 @@ RSpec/MultipleDescribes:
|
|
|
328
320
|
- 'spec/lutaml/xml/namespace_resolution_strategy_spec.rb'
|
|
329
321
|
- 'spec/lutaml/xml/xml_space_type_spec.rb'
|
|
330
322
|
|
|
331
|
-
# Offense count:
|
|
323
|
+
# Offense count: 1442
|
|
332
324
|
RSpec/MultipleExpectations:
|
|
333
325
|
Max: 21
|
|
334
326
|
|
|
335
|
-
# Offense count:
|
|
327
|
+
# Offense count: 190
|
|
336
328
|
# Configuration parameters: AllowSubject.
|
|
337
329
|
RSpec/MultipleMemoizedHelpers:
|
|
338
330
|
Max: 15
|
|
@@ -376,13 +368,13 @@ RSpec/RepeatedExampleGroupDescription:
|
|
|
376
368
|
Exclude:
|
|
377
369
|
- 'spec/lutaml/model/mixed_content_spec.rb'
|
|
378
370
|
|
|
379
|
-
# Offense count:
|
|
371
|
+
# Offense count: 40
|
|
380
372
|
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
|
|
381
373
|
# SupportedInflectors: default, active_support
|
|
382
374
|
RSpec/SpecFilePathFormat:
|
|
383
375
|
Enabled: false
|
|
384
376
|
|
|
385
|
-
# Offense count:
|
|
377
|
+
# Offense count: 32
|
|
386
378
|
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
|
|
387
379
|
RSpec/VerifiedDoubles:
|
|
388
380
|
Exclude:
|
|
@@ -393,6 +385,7 @@ RSpec/VerifiedDoubles:
|
|
|
393
385
|
- 'spec/lutaml/model/schema/renderer_spec.rb'
|
|
394
386
|
- 'spec/lutaml/model/transformation_builder_spec.rb'
|
|
395
387
|
- 'spec/lutaml/model/transformation_spec.rb'
|
|
388
|
+
- 'spec/lutaml/model/validation/context_spec.rb'
|
|
396
389
|
- 'spec/lutaml/xml/namespace_resolution_strategy_spec.rb'
|
|
397
390
|
|
|
398
391
|
# Offense count: 1
|
|
@@ -400,13 +393,14 @@ Security/MarshalLoad:
|
|
|
400
393
|
Exclude:
|
|
401
394
|
- 'scripts-xmi-profile/profile_xmi.rb'
|
|
402
395
|
|
|
403
|
-
# Offense count:
|
|
396
|
+
# Offense count: 2
|
|
404
397
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
405
398
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
406
399
|
# AllowedMethods: ==, equal?, eql?
|
|
407
400
|
Style/ClassEqualityComparison:
|
|
408
401
|
Exclude:
|
|
409
402
|
- 'lib/lutaml/model/attribute.rb'
|
|
403
|
+
- 'lib/lutaml/model/validation/profile.rb'
|
|
410
404
|
|
|
411
405
|
# Offense count: 13
|
|
412
406
|
# This cop supports safe autocorrection (--autocorrect).
|
data/Gemfile
CHANGED
|
@@ -12,6 +12,7 @@ gem "base64"
|
|
|
12
12
|
gem "benchmark-ips"
|
|
13
13
|
gem "bigdecimal"
|
|
14
14
|
gem "canon" # , path: "../canon"
|
|
15
|
+
gem "json-ld", "~> 3.3"
|
|
15
16
|
gem "liquid", "~> 5"
|
|
16
17
|
gem "multi_json"
|
|
17
18
|
gem "nokogiri"
|
|
@@ -20,6 +21,7 @@ gem "oj"
|
|
|
20
21
|
gem "openssl", "~> 3.0"
|
|
21
22
|
gem "ox"
|
|
22
23
|
gem "rake"
|
|
24
|
+
gem "rdf-turtle", "~> 3.3"
|
|
23
25
|
gem "rexml"
|
|
24
26
|
gem "rspec"
|
|
25
27
|
gem "rubocop"
|
data/README.adoc
CHANGED
|
@@ -27,7 +27,7 @@ for:
|
|
|
27
27
|
|
|
28
28
|
It provides simple, flexible and comprehensive mechanisms for defining
|
|
29
29
|
information models with attributes and types, and the serialization of them
|
|
30
|
-
to/from serialization formats including JSON, XML, YAML, and
|
|
30
|
+
to/from serialization formats including JSON, XML, YAML, TOML, JSON-LD, and Turtle, as well as
|
|
31
31
|
transformation to other formats like Hash.
|
|
32
32
|
|
|
33
33
|
For serialization formats, it uses an adapter pattern to support multiple
|
|
@@ -48,7 +48,7 @@ link:docs/migration-guides/0-1-0-migrate-from-shale.adoc[Migrating from Shale to
|
|
|
48
48
|
== Features
|
|
49
49
|
|
|
50
50
|
* Define models with attributes and types
|
|
51
|
-
* Serialize and deserialize models to/from JSON, XML, YAML, and
|
|
51
|
+
* Serialize and deserialize models to/from JSON, XML, YAML, TOML, JSON-LD, and Turtle
|
|
52
52
|
* Transform models to other formats like Hash
|
|
53
53
|
* Support for multiple serialization libraries (e.g., `toml-rb`, `tomlib`)
|
|
54
54
|
* Configurable adapters for different serialization formats
|
|
@@ -65,7 +65,9 @@ link:docs/migration-guides/0-1-0-migrate-from-shale.adoc[Migrating from Shale to
|
|
|
65
65
|
* Symmetric OOP architecture for all formats with KeyValueDataModel (see <<keyvaluedatamodel-architecture>>)
|
|
66
66
|
* Parse XSD schemas into Ruby objects for inspection and manipulation (see <<xsd-schema-parsing>>)
|
|
67
67
|
* Reusable XML mapping classes for sharing mappings across models
|
|
68
|
+
* RDF namespace classes and JSON-LD/Turtle format adapters for Linked Data serialization
|
|
68
69
|
* Consolidation mapping: group sibling XML elements into structured model instances (see <<consolidation-mapping>>)
|
|
70
|
+
* Document-level validation framework with composable rules, profiles, and remediation (see <<document-validation-framework>>)
|
|
69
71
|
|
|
70
72
|
|
|
71
73
|
== Data modeling in a nutshell
|
|
@@ -5390,6 +5392,11 @@ Collection serialization formats::
|
|
|
5390
5392
|
`jsonl`::: JSONL (JSON Lines) (see <<mapping-collections>>)
|
|
5391
5393
|
`yamls`::: YAML Stream (multi-document format) (see <<mapping-collections>>)
|
|
5392
5394
|
|
|
5395
|
+
RDF serialization formats::
|
|
5396
|
+
|
|
5397
|
+
`rdf`::: Unified RDF mapping for both JSON-LD and Turtle (see <<mapping-rdf>>)
|
|
5398
|
+
`turtle`::: Turtle (see link:docs/_guides/turtle-serialization.adoc[Turtle Serialization])
|
|
5399
|
+
|
|
5393
5400
|
|
|
5394
5401
|
.Using the `xml`, `hsh`, `json`, `yaml`, `toml` and `key_value` blocks to define serialization mappings
|
|
5395
5402
|
[example]
|
|
@@ -5438,6 +5445,73 @@ end
|
|
|
5438
5445
|
====
|
|
5439
5446
|
|
|
5440
5447
|
|
|
5448
|
+
[[mapping-rdf]]
|
|
5449
|
+
=== Unified RDF mapping (`rdf`)
|
|
5450
|
+
|
|
5451
|
+
The `rdf` block defines predicate-based mappings once for both JSON-LD and
|
|
5452
|
+
Turtle serialization. It follows the same unified-mapping principle as
|
|
5453
|
+
`key_value` (which serves JSON, YAML, TOML).
|
|
5454
|
+
|
|
5455
|
+
.Using the `rdf` block to define unified RDF mappings
|
|
5456
|
+
[example]
|
|
5457
|
+
====
|
|
5458
|
+
[source,ruby]
|
|
5459
|
+
----
|
|
5460
|
+
class Concept < Lutaml::Model::Serializable
|
|
5461
|
+
attribute :code, :string
|
|
5462
|
+
attribute :name, :string
|
|
5463
|
+
|
|
5464
|
+
rdf do
|
|
5465
|
+
namespace SkosNamespace
|
|
5466
|
+
|
|
5467
|
+
subject { |m| "http://example.org/concept/#{m.code}" }
|
|
5468
|
+
type "skos:Concept"
|
|
5469
|
+
|
|
5470
|
+
predicate :notation, namespace: SkosNamespace, to: :code
|
|
5471
|
+
predicate :prefLabel, namespace: SkosNamespace, to: :name
|
|
5472
|
+
end
|
|
5473
|
+
end
|
|
5474
|
+
----
|
|
5475
|
+
|
|
5476
|
+
Serializes to both formats:
|
|
5477
|
+
|
|
5478
|
+
[source,ruby]
|
|
5479
|
+
----
|
|
5480
|
+
concept = Concept.new(code: "2119", name: "component")
|
|
5481
|
+
concept.to_turtle # => Turtle with @prefix, a skos:Concept, predicates
|
|
5482
|
+
concept.to_jsonld # => JSON-LD with @context, @type, @id, properties
|
|
5483
|
+
----
|
|
5484
|
+
====
|
|
5485
|
+
|
|
5486
|
+
Graph-level serialization uses `members` to emit all contained resources as
|
|
5487
|
+
separate subjects in the same document:
|
|
5488
|
+
|
|
5489
|
+
[source,ruby]
|
|
5490
|
+
----
|
|
5491
|
+
class Vocabulary < Lutaml::Model::Serializable
|
|
5492
|
+
attribute :id, :string
|
|
5493
|
+
attribute :concepts, Concept, collection: true
|
|
5494
|
+
|
|
5495
|
+
rdf do
|
|
5496
|
+
namespace SkosNamespace
|
|
5497
|
+
subject { |v| "http://example.org/vocab/#{v.id}" }
|
|
5498
|
+
type "skos:ConceptScheme"
|
|
5499
|
+
predicate :prefLabel, namespace: SkosNamespace, to: :id
|
|
5500
|
+
members :concepts
|
|
5501
|
+
end
|
|
5502
|
+
end
|
|
5503
|
+
|
|
5504
|
+
# Turtle: single document with ConceptScheme + all Concept triples
|
|
5505
|
+
# JSON-LD: @graph array with ConceptScheme + all Concept objects
|
|
5506
|
+
vocab.to_turtle
|
|
5507
|
+
vocab.to_jsonld
|
|
5508
|
+
----
|
|
5509
|
+
|
|
5510
|
+
See link:docs/_guides/rdf-serialization.adoc[Unified RDF Serialization] for the
|
|
5511
|
+
complete guide including language-tagged values, graph serialization, and
|
|
5512
|
+
architecture details.
|
|
5513
|
+
|
|
5514
|
+
|
|
5441
5515
|
== Serialization: XML
|
|
5442
5516
|
|
|
5443
5517
|
=== General
|
|
@@ -6349,7 +6423,8 @@ end
|
|
|
6349
6423
|
====
|
|
6350
6424
|
When a model has `mixed_content`, use `map_content` with `collection: true`
|
|
6351
6425
|
to capture the multiple text segments between child elements.
|
|
6352
|
-
Without `collection: true`,
|
|
6426
|
+
Without `collection: true`, a `MixedContentCollectionError` is raised at
|
|
6427
|
+
finalization time.
|
|
6353
6428
|
====
|
|
6354
6429
|
|
|
6355
6430
|
.Complete round-trip with `mixed_content` and `map_content collection: true`
|
|
@@ -6498,6 +6573,51 @@ Without `mixed_content`, serialization groups all text first then all elements
|
|
|
6498
6573
|
(or vice versa), losing the original interleaving. This is the most common
|
|
6499
6574
|
cause of XML round-trip failures in document-processing applications.
|
|
6500
6575
|
|
|
6576
|
+
===== XML Comment round-trip preservation
|
|
6577
|
+
|
|
6578
|
+
XML comments (`<!-- ... -->`) are preserved during round-trip serialization
|
|
6579
|
+
in `mixed_content` and `ordered` modes. Comments appear in `element_order`
|
|
6580
|
+
as entries with `node_type: :comment` and are reconstructed during output.
|
|
6581
|
+
|
|
6582
|
+
.Comment round-trip in mixed content
|
|
6583
|
+
[example]
|
|
6584
|
+
====
|
|
6585
|
+
[source,ruby]
|
|
6586
|
+
----
|
|
6587
|
+
class Paragraph < Lutaml::Model::Serializable
|
|
6588
|
+
attribute :content, :string, collection: true
|
|
6589
|
+
|
|
6590
|
+
xml do
|
|
6591
|
+
element 'p'
|
|
6592
|
+
mixed_content
|
|
6593
|
+
map_content to: :content
|
|
6594
|
+
end
|
|
6595
|
+
end
|
|
6596
|
+
----
|
|
6597
|
+
|
|
6598
|
+
Input XML with a comment between text and an element:
|
|
6599
|
+
|
|
6600
|
+
[source,xml]
|
|
6601
|
+
----
|
|
6602
|
+
<p>Text before<!-- a comment --> text after</p>
|
|
6603
|
+
----
|
|
6604
|
+
|
|
6605
|
+
[source,ruby]
|
|
6606
|
+
----
|
|
6607
|
+
parsed = Paragraph.from_xml(xml)
|
|
6608
|
+
parsed.element_order
|
|
6609
|
+
# => [#<Lutaml::Xml::Element type: "Text", node_type: :text>,
|
|
6610
|
+
# #<Lutaml::Xml::Element type: "Comment", node_type: :comment, text_content: " a comment ">,
|
|
6611
|
+
# #<Lutaml::Xml::Element type: "Text", node_type: :text>]
|
|
6612
|
+
|
|
6613
|
+
parsed.to_xml
|
|
6614
|
+
# => "<p>Text before<!-- a comment --> text after</p>"
|
|
6615
|
+
----
|
|
6616
|
+
====
|
|
6617
|
+
|
|
6618
|
+
NOTE: Comments are tracked in `element_order` but are **not** included in
|
|
6619
|
+
model attributes or the parsed hash. They exist solely for serialization fidelity.
|
|
6620
|
+
|
|
6501
6621
|
==== (DEPRECATED) Mixed content declaration (`root` method with `mixed:`)
|
|
6502
6622
|
|
|
6503
6623
|
To map this to Lutaml::Model we can use the `mixed` option in either way:
|
|
@@ -6558,6 +6678,13 @@ preserves the order of **XML Elements and Content**.
|
|
|
6558
6678
|
|
|
6559
6679
|
NOTE: When both options are used, `mixed: true` takes precedence.
|
|
6560
6680
|
|
|
6681
|
+
[IMPORTANT]
|
|
6682
|
+
====
|
|
6683
|
+
`ordered` models element-only content -- `map_content` is not allowed.
|
|
6684
|
+
If you need to capture text content between elements, use `mixed_content`
|
|
6685
|
+
instead (see <<mixed-content>>).
|
|
6686
|
+
====
|
|
6687
|
+
|
|
6561
6688
|
To specify ordered content, the `ordered: true` option needs to be set at the
|
|
6562
6689
|
`xml` block's `root` method.
|
|
6563
6690
|
|
|
@@ -10046,8 +10173,14 @@ Key-value data models supported are identified by their short name:
|
|
|
10046
10173
|
`json`:: JSON
|
|
10047
10174
|
`yaml`:: YAML
|
|
10048
10175
|
`toml`:: TOML
|
|
10176
|
+
`jsonld`:: JSON-LD (extends key-value with `@context`, `@type`, `@id`)
|
|
10049
10177
|
`key_value`:: A way to configure key-value mappings for all supported key-value data models.
|
|
10050
10178
|
|
|
10179
|
+
RDF serialization formats::
|
|
10180
|
+
|
|
10181
|
+
`rdf`:: Unified RDF mapping for both JSON-LD and Turtle (see <<mapping-rdf>>)
|
|
10182
|
+
`turtle`:: Turtle (see link:docs/_guides/turtle-serialization.adoc[Turtle Serialization])
|
|
10183
|
+
|
|
10051
10184
|
|
|
10052
10185
|
=== Mapping
|
|
10053
10186
|
|
|
@@ -15681,6 +15814,8 @@ LutaML, out of the box, supports the following serialization formats:
|
|
|
15681
15814
|
* YAML (https://yaml.org/[YAML version 1.2])
|
|
15682
15815
|
* JSON (https://www.ecma-international.org/publications-and-standards/standards/ecma-404/[ECMA-404 The JSON Data Interchange Standard], unofficial link: https://www.json.org[JSON])
|
|
15683
15816
|
* TOML (https://toml.io/en[TOML version 1.0])
|
|
15817
|
+
* JSON-LD (https://www.w3.org/TR/json-ld11/[W3C JSON-LD 1.1])
|
|
15818
|
+
* Turtle (https://www.w3.org/TR/turtle/[W3C RDF 1.1 Turtle])
|
|
15684
15819
|
|
|
15685
15820
|
The adapter interface is also used to support certain transformation of models
|
|
15686
15821
|
into an "end format", which is not a serialization format. For example, the
|
|
@@ -15923,6 +16058,37 @@ end
|
|
|
15923
16058
|
----
|
|
15924
16059
|
|
|
15925
16060
|
|
|
16061
|
+
=== JSON-LD
|
|
16062
|
+
|
|
16063
|
+
Lutaml::Model supports serialization to and from JSON-LD (W3C JSON-LD 1.1).
|
|
16064
|
+
JSON-LD is a key-value format that extends JSON with `@context`, `@type`, and
|
|
16065
|
+
`@id`. No additional gem is required beyond `lutaml-model`.
|
|
16066
|
+
|
|
16067
|
+
For unified RDF mapping (both JSON-LD and Turtle from a single `rdf` block), see
|
|
16068
|
+
link:docs/_guides/rdf-serialization.adoc[Unified RDF Serialization].
|
|
16069
|
+
|
|
16070
|
+
See link:docs/_guides/jsonld-serialization.adoc[JSON-LD Serialization] for the
|
|
16071
|
+
legacy `jsonld do` block DSL and usage examples.
|
|
16072
|
+
|
|
16073
|
+
|
|
16074
|
+
=== Turtle
|
|
16075
|
+
|
|
16076
|
+
Lutaml::Model supports serialization to and from W3C RDF Turtle format.
|
|
16077
|
+
Turtle is a non-key-value format based on RDF triples. Requires the
|
|
16078
|
+
`rdf-turtle` gem:
|
|
16079
|
+
|
|
16080
|
+
[source,ruby]
|
|
16081
|
+
----
|
|
16082
|
+
gem "rdf-turtle", "~> 3.3"
|
|
16083
|
+
----
|
|
16084
|
+
|
|
16085
|
+
For unified RDF mapping (both JSON-LD and Turtle from a single `rdf` block), see
|
|
16086
|
+
link:docs/_guides/rdf-serialization.adoc[Unified RDF Serialization].
|
|
16087
|
+
|
|
16088
|
+
See link:docs/_guides/turtle-serialization.adoc[Turtle Serialization] for the
|
|
16089
|
+
legacy `turtle do` block DSL and usage examples.
|
|
16090
|
+
|
|
16091
|
+
|
|
15926
16092
|
=== Per-operation adapter override
|
|
15927
16093
|
|
|
15928
16094
|
Override the adapter for a single serialization/deserialization call using the `adapter:` option:
|
|
@@ -16938,6 +17104,164 @@ end
|
|
|
16938
17104
|
For a complete architecture overview and migration guide from Register to
|
|
16939
17105
|
GlobalContext, see link:docs/architecture.md[Architecture Documentation].
|
|
16940
17106
|
|
|
17107
|
+
[[document-validation-framework]]
|
|
17108
|
+
== Document Validation Framework
|
|
17109
|
+
|
|
17110
|
+
Lutaml::Model provides a document-level validation framework (`Lutaml::Model::Validation`)
|
|
17111
|
+
for validating structural integrity, cross-references, and conformance against
|
|
17112
|
+
domain-specific rules. This is *orthogonal* to the existing attribute-level
|
|
17113
|
+
validation (`validate`/`validate!` on model instances) -- that validates type
|
|
17114
|
+
constraints, enumerations, and collections; this validates document-level concerns.
|
|
17115
|
+
|
|
17116
|
+
=== Quick start
|
|
17117
|
+
|
|
17118
|
+
[source,ruby]
|
|
17119
|
+
----
|
|
17120
|
+
require "lutaml/model/validation_framework"
|
|
17121
|
+
|
|
17122
|
+
# 1. Define rules by subclassing Lutaml::Model::Validation::Rule
|
|
17123
|
+
class RequiredFieldsRule < Lutaml::Model::Validation::Rule
|
|
17124
|
+
def code = "DOC-001"
|
|
17125
|
+
def severity = "error"
|
|
17126
|
+
|
|
17127
|
+
def check(context)
|
|
17128
|
+
missing = required_fields.select { |f| context[f].nil? || context[f].empty? }
|
|
17129
|
+
missing.map { |f| issue("Missing required field: #{f}") }
|
|
17130
|
+
end
|
|
17131
|
+
|
|
17132
|
+
private
|
|
17133
|
+
|
|
17134
|
+
def required_fields = %w[title author]
|
|
17135
|
+
end
|
|
17136
|
+
|
|
17137
|
+
# 2. Register rules
|
|
17138
|
+
registry = Lutaml::Model::Validation.new_registry
|
|
17139
|
+
registry.register(RequiredFieldsRule)
|
|
17140
|
+
|
|
17141
|
+
# 3. Run validation
|
|
17142
|
+
issues = Lutaml::Model::Validation.validate({ title: "Hello" }, registry)
|
|
17143
|
+
issues.each { |i| puts "[#{i.severity}] #{i.code}: #{i.message}" }
|
|
17144
|
+
# => [error] DOC-001: Missing required field: author
|
|
17145
|
+
|
|
17146
|
+
# 4. Or raise on errors
|
|
17147
|
+
begin
|
|
17148
|
+
Lutaml::Model::Validation.validate!({ title: "Hello" }, registry)
|
|
17149
|
+
rescue Lutaml::Model::Validation::ValidationError => e
|
|
17150
|
+
puts e.message # => "[DOC-001] Missing required field: author"
|
|
17151
|
+
e.issues # => [#<Issue code="DOC-001">]
|
|
17152
|
+
end
|
|
17153
|
+
----
|
|
17154
|
+
|
|
17155
|
+
=== Core components
|
|
17156
|
+
|
|
17157
|
+
[cols="1,4"]
|
|
17158
|
+
|===
|
|
17159
|
+
| Class | Purpose
|
|
17160
|
+
|
|
17161
|
+
| `Validation::Issue`
|
|
17162
|
+
| Serializable issue with severity (`error`/`warning`/`info`/`notice`), code, message, location, line, suggestion
|
|
17163
|
+
|
|
17164
|
+
| `Validation::Rule`
|
|
17165
|
+
| Abstract base class. Override `code`, `severity`, `category`, `applicable?`, and `check`
|
|
17166
|
+
|
|
17167
|
+
| `Validation::Registry`
|
|
17168
|
+
| Instance-based rule registration with cached instantiation via `register`, `all`, `for_category`, `find`
|
|
17169
|
+
|
|
17170
|
+
| `Validation::Profile`
|
|
17171
|
+
| YAML composable profiles with import resolution for rule subsets. `load` validates required `name` key
|
|
17172
|
+
|
|
17173
|
+
| `Validation::Context`
|
|
17174
|
+
| Mutable context with error accumulation and per-rule state (for streaming validation)
|
|
17175
|
+
|
|
17176
|
+
| `Validation::Report` / `LayerResult`
|
|
17177
|
+
| Serializable report models with aggregated severity filtering
|
|
17178
|
+
|
|
17179
|
+
| `Validation::Remediation`
|
|
17180
|
+
| Abstract base for auto-fix logic. Subclass must override `fix` (raises `NotImplementedError` on base class)
|
|
17181
|
+
|===
|
|
17182
|
+
|
|
17183
|
+
=== Composable profiles
|
|
17184
|
+
|
|
17185
|
+
Profiles select *which* rules run, not *how* they run. They are loaded from YAML
|
|
17186
|
+
and support import-based composition.
|
|
17187
|
+
|
|
17188
|
+
[source,yaml]
|
|
17189
|
+
----
|
|
17190
|
+
# profiles/basic.yml
|
|
17191
|
+
name: basic
|
|
17192
|
+
description: Basic DOCX validation
|
|
17193
|
+
rules:
|
|
17194
|
+
- RequiredFieldsRule
|
|
17195
|
+
- StyleReferencesRule
|
|
17196
|
+
----
|
|
17197
|
+
|
|
17198
|
+
[source,yaml]
|
|
17199
|
+
----
|
|
17200
|
+
# profiles/strict.yml
|
|
17201
|
+
name: strict
|
|
17202
|
+
import:
|
|
17203
|
+
- basic
|
|
17204
|
+
rules:
|
|
17205
|
+
- BookmarksRule
|
|
17206
|
+
- ImagesRule
|
|
17207
|
+
----
|
|
17208
|
+
|
|
17209
|
+
[source,ruby]
|
|
17210
|
+
----
|
|
17211
|
+
registry = Lutaml::Model::Validation.new_registry
|
|
17212
|
+
registry.register(RequiredFieldsRule)
|
|
17213
|
+
registry.register(StyleReferencesRule)
|
|
17214
|
+
registry.register(BookmarksRule)
|
|
17215
|
+
registry.register(ImagesRule)
|
|
17216
|
+
|
|
17217
|
+
basic = Lutaml::Model::Validation::Profile.load("profiles/basic.yml")
|
|
17218
|
+
strict = Lutaml::Model::Validation::Profile.load("profiles/strict.yml")
|
|
17219
|
+
profiles = { "basic" => basic, "strict" => strict }
|
|
17220
|
+
|
|
17221
|
+
rules = strict.resolve(registry, profiles) # returns all 4 rule instances
|
|
17222
|
+
|
|
17223
|
+
// Circular imports are detected and raise ArgumentError.
|
|
17224
|
+
// Profile YAML is validated: missing `name` key raises ArgumentError.
|
|
17225
|
+
----
|
|
17226
|
+
|
|
17227
|
+
=== Remediation (auto-fix)
|
|
17228
|
+
|
|
17229
|
+
Subclass `Validation::Remediation` to provide automatic fixes for specific issues:
|
|
17230
|
+
|
|
17231
|
+
[source,ruby]
|
|
17232
|
+
----
|
|
17233
|
+
class FixBrokenReferences < Lutaml::Model::Validation::Remediation
|
|
17234
|
+
def id = "REM-001"
|
|
17235
|
+
def targets = ["DOC-020"]
|
|
17236
|
+
|
|
17237
|
+
def fix(context, report)
|
|
17238
|
+
# ... apply fixes ...
|
|
17239
|
+
Lutaml::Model::Validation::RemediationResult.new(
|
|
17240
|
+
success: true,
|
|
17241
|
+
message: "Fixed 3 broken references",
|
|
17242
|
+
fixed_codes: ["DOC-020"]
|
|
17243
|
+
)
|
|
17244
|
+
end
|
|
17245
|
+
end
|
|
17246
|
+
----
|
|
17247
|
+
|
|
17248
|
+
=== Relationship to attribute-level validation
|
|
17249
|
+
|
|
17250
|
+
|===
|
|
17251
|
+
| Attribute validation (existing) | Document validation framework (new)
|
|
17252
|
+
|
|
17253
|
+
| Validates model instance state (types, ranges, patterns)
|
|
17254
|
+
| Validates document-level concerns (structure, cross-references, conformance)
|
|
17255
|
+
|
|
17256
|
+
| Runs during deserialization via `model.validate`
|
|
17257
|
+
| Runs on parsed documents against domain rules via `Validation.validate`
|
|
17258
|
+
|
|
17259
|
+
| Returns `Array<Error>` error objects
|
|
17260
|
+
| Returns `Array<Issue>` serializable issue objects
|
|
17261
|
+
|===
|
|
17262
|
+
|
|
17263
|
+
See link:docs/_pages/validation.adoc[Validation] for attribute-level validation details.
|
|
17264
|
+
|
|
16941
17265
|
|
|
16942
17266
|
== Comparison with Shale
|
|
16943
17267
|
|