lutaml-model 0.8.11 → 0.8.13

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.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/opal.yml +31 -0
  3. data/.rspec-opal +5 -0
  4. data/.rubocop_todo.yml +45 -34
  5. data/README.adoc +126 -104
  6. data/RELEASE_NOTES.adoc +3 -3
  7. data/benchmark/quick_benchmark.rb +2 -2
  8. data/benchmark/serialization_benchmark.rb +4 -4
  9. data/docs/_guides/advanced-mapping.adoc +1 -1
  10. data/docs/_guides/character-encoding.adoc +3 -3
  11. data/docs/_guides/index.adoc +4 -0
  12. data/docs/_guides/missing-values-handling.adoc +6 -6
  13. data/docs/_guides/ooxml-examples.adoc +7 -7
  14. data/docs/_guides/opal.adoc +221 -0
  15. data/docs/_guides/value-transformations.adoc +7 -7
  16. data/docs/_guides/xml/namespace-presentation.adoc +1 -1
  17. data/docs/_guides/xml/namespace-semantics.adoc +15 -15
  18. data/docs/_guides/xml/type-namespaces.adoc +9 -9
  19. data/docs/_guides/xml-mapping.adoc +32 -26
  20. data/docs/_guides/xml-namespace-qualification.adoc +4 -4
  21. data/docs/_guides/xml-namespaces.adoc +2 -2
  22. data/docs/_guides/xml_mappings/04_xml_namespace_class.adoc +18 -18
  23. data/docs/_guides/xml_mappings/05_common_patterns.adoc +16 -16
  24. data/docs/_guides/xml_mappings/06_migration_guide.adoc +5 -5
  25. data/docs/_guides/xml_mappings/07_best_practices.adoc +13 -12
  26. data/docs/_migrations/0-8-0-namespace-restructuring.adoc +2 -2
  27. data/docs/_pages/attributes.adoc +2 -2
  28. data/docs/_pages/collections.adoc +26 -20
  29. data/docs/_pages/configuration.adoc +9 -4
  30. data/docs/_pages/consolidation-mapping.adoc +4 -4
  31. data/docs/_pages/importable_models.adoc +14 -13
  32. data/docs/_pages/index.adoc +1 -0
  33. data/docs/_pages/quick-start.adoc +1 -1
  34. data/docs/_pages/serialization_adapters.adoc +3 -2
  35. data/docs/_pages/value_types.adoc +10 -10
  36. data/docs/_references/custom_registers.adoc +7 -7
  37. data/docs/_references/format-independent-features.adoc +4 -4
  38. data/docs/_references/instance-serialization.adoc +1 -1
  39. data/docs/_references/parent-root-context.adoc +3 -3
  40. data/docs/_tutorials/basic-model-definition.adoc +1 -1
  41. data/docs/_tutorials/first-xml-serialization.adoc +4 -4
  42. data/docs/_tutorials/lutaml-xml-architecture.adoc +4 -4
  43. data/docs/_tutorials/validation-basics.adoc +1 -1
  44. data/docs/_tutorials/working-with-collections.adoc +2 -2
  45. data/docs/_tutorials/xml-namespaces-basics.adoc +1 -1
  46. data/docs/_tutorials/xml-schema-primer-style-guide.adoc +29 -29
  47. data/docs/cli_compare.adoc +1 -1
  48. data/docs/index.adoc +2 -1
  49. data/docs/namespace-management.adoc +14 -14
  50. data/lib/lutaml/hash_format/adapter/mapping.rb +2 -4
  51. data/lib/lutaml/json/adapter/mapping.rb +2 -4
  52. data/lib/lutaml/jsonl/adapter/mapping.rb +2 -4
  53. data/lib/lutaml/key_value/adapter/hash/mapping.rb +2 -4
  54. data/lib/lutaml/key_value/adapter/json/mapping.rb +2 -4
  55. data/lib/lutaml/key_value/adapter/jsonl/mapping.rb +2 -4
  56. data/lib/lutaml/key_value/adapter/toml/mapping.rb +2 -4
  57. data/lib/lutaml/key_value/adapter/yaml/mapping.rb +2 -4
  58. data/lib/lutaml/key_value/adapter/yamls/mapping.rb +2 -4
  59. data/lib/lutaml/key_value/mapping.rb +35 -10
  60. data/lib/lutaml/model/adapter_resolver.rb +5 -8
  61. data/lib/lutaml/model/collection.rb +11 -11
  62. data/lib/lutaml/model/error/no_root_mapping_error.rb +6 -5
  63. data/lib/lutaml/model/error/no_root_namespace_error.rb +6 -5
  64. data/lib/lutaml/model/error/type_only_mapping_error.rb +13 -0
  65. data/lib/lutaml/model/error/type_only_namespace_error.rb +12 -0
  66. data/lib/lutaml/model/mapping/mapping.rb +12 -0
  67. data/lib/lutaml/model/version.rb +1 -1
  68. data/lib/lutaml/model.rb +3 -0
  69. data/lib/lutaml/toml/adapter/mapping.rb +2 -4
  70. data/lib/lutaml/xml/adapter/base_adapter.rb +0 -9
  71. data/lib/lutaml/xml/adapter/nokogiri_adapter.rb +0 -1
  72. data/lib/lutaml/xml/adapter/oga_adapter.rb +0 -1
  73. data/lib/lutaml/xml/adapter/ox_adapter.rb +0 -1
  74. data/lib/lutaml/xml/adapter/rexml_adapter.rb +0 -1
  75. data/lib/lutaml/xml/adapter/xml_serializer.rb +42 -22
  76. data/lib/lutaml/xml/adapter.rb +4 -0
  77. data/lib/lutaml/xml/builder/base.rb +64 -25
  78. data/lib/lutaml/xml/builder/nokogiri.rb +0 -2
  79. data/lib/lutaml/xml/builder/oga.rb +0 -2
  80. data/lib/lutaml/xml/builder/ox.rb +0 -2
  81. data/lib/lutaml/xml/builder/rexml.rb +0 -2
  82. data/lib/lutaml/xml/builder.rb +1 -0
  83. data/lib/lutaml/xml/configurable.rb +2 -2
  84. data/lib/lutaml/xml/declaration_handler.rb +3 -105
  85. data/lib/lutaml/xml/mapping.rb +3 -3
  86. data/lib/lutaml/xml/schema/xsd/documentation.rb +1 -1
  87. data/lib/lutaml/xml/schema/xsd.rb +5 -4
  88. data/lib/lutaml/xml/schema.rb +8 -5
  89. data/lib/lutaml/xml/serialization/collection_ext.rb +7 -7
  90. data/lib/lutaml/xml/serialization/format_conversion.rb +1 -1
  91. data/lib/lutaml/xml/serialization/instance_methods.rb +1 -1
  92. data/lib/lutaml/xml/xml_orderable.rb +17 -0
  93. data/lib/lutaml/xml.rb +9 -13
  94. data/lib/lutaml/yaml/adapter/mapping.rb +2 -4
  95. data/lib/lutaml/yamls/adapter/mapping.rb +7 -3
  96. data/lib/tasks/memory_profile.rb +2 -2
  97. data/lib/tasks/performance_benchmark.rb +5 -5
  98. data/lutaml-model.gemspec +1 -1
  99. data/spec/lutaml/key_value/transformation/rule_compiler_spec.rb +1 -1
  100. data/spec/lutaml/key_value/transformation/value_serializer_spec.rb +1 -1
  101. data/spec/lutaml/model/attribute_collection_spec.rb +1 -1
  102. data/spec/lutaml/model/cli_spec.rb +1 -1
  103. data/spec/lutaml/model/collection_spec.rb +1 -1
  104. data/spec/lutaml/model/collection_validation_spec.rb +6 -6
  105. data/spec/lutaml/model/consolidation_spec.rb +8 -8
  106. data/spec/lutaml/model/custom_collection_spec.rb +3 -3
  107. data/spec/lutaml/model/default_register_spec.rb +23 -23
  108. data/spec/lutaml/model/delegation_spec.rb +3 -10
  109. data/spec/lutaml/model/derived_attribute_serialization_spec.rb +1 -1
  110. data/spec/lutaml/model/dynamic_attribute_spec.rb +2 -2
  111. data/spec/lutaml/model/enum_spec.rb +1 -1
  112. data/spec/lutaml/model/group_spec.rb +12 -12
  113. data/spec/lutaml/model/lazy_collection_spec.rb +4 -4
  114. data/spec/lutaml/model/mixed_content_spec.rb +2 -2
  115. data/spec/lutaml/model/namespace_versioning_spec.rb +4 -4
  116. data/spec/lutaml/model/opal_smoke_spec.rb +117 -0
  117. data/spec/lutaml/model/processing_instruction_spec.rb +11 -11
  118. data/spec/lutaml/model/register_methods_spec.rb +2 -2
  119. data/spec/lutaml/model/render_empty_spec.rb +1 -1
  120. data/spec/lutaml/model/serialize_perf_guard_spec.rb +1 -1
  121. data/spec/lutaml/model/transform_dynamic_attributes_spec.rb +1 -1
  122. data/spec/lutaml/model/transformation_builder_spec.rb +2 -2
  123. data/spec/lutaml/model/xml_decoupling_spec.rb +3 -3
  124. data/spec/lutaml/model/xsd_patterns_spec.rb +2 -3
  125. data/spec/lutaml/xml/adapter/order_spec.rb +1 -1
  126. data/spec/lutaml/xml/clear_parse_state_spec.rb +1 -1
  127. data/spec/lutaml/xml/content_model_validation_spec.rb +4 -2
  128. data/spec/lutaml/xml/doubly_defined_namespace_spec.rb +5 -5
  129. data/spec/lutaml/xml/enhanced_mapping_spec.rb +2 -1
  130. data/spec/lutaml/xml/entity_fragmentation_spec.rb +5 -5
  131. data/spec/lutaml/xml/indent_spec.rb +109 -0
  132. data/spec/lutaml/xml/line_ending_spec.rb +66 -0
  133. data/spec/lutaml/xml/mapping_finalization_guard_spec.rb +2 -2
  134. data/spec/lutaml/xml/model_transform_guard_spec.rb +4 -4
  135. data/spec/lutaml/xml/namespace_alias_spec.rb +4 -4
  136. data/spec/lutaml/xml/namespace_aware_parsing_spec.rb +3 -3
  137. data/spec/lutaml/xml/namespace_bound_element_roundtrip_spec.rb +2 -2
  138. data/spec/lutaml/xml/namespace_format_preservation_spec.rb +1 -1
  139. data/spec/lutaml/xml/namespace_inheritance_spec.rb +3 -3
  140. data/spec/lutaml/xml/namespace_preservation_spec.rb +5 -5
  141. data/spec/lutaml/xml/opal_xml_spec.rb +145 -0
  142. data/spec/lutaml/xml/pipeline_integration_spec.rb +145 -0
  143. data/spec/lutaml/xml/schema_primer_spec.rb +5 -5
  144. data/spec/lutaml/xml/transformation_spec.rb +20 -20
  145. data/spec/lutaml/xml/type_namespace/collector_spec.rb +1 -1
  146. data/spec/lutaml/xml/type_namespace/planner_spec.rb +3 -3
  147. data/spec/lutaml/xml/xml_spec.rb +64 -13
  148. data/spec/support/opal.rb +6 -0
  149. metadata +16 -4
@@ -46,14 +46,14 @@ end
46
46
  # Repeat namespace details in every model
47
47
  class Model1 < Lutaml::Model::Serializable
48
48
  xml do
49
- root 'model1'
49
+ element "model1"
50
50
  namespace 'https://example.com/project/v1', 'proj'
51
51
  end
52
52
  end
53
53
 
54
54
  class Model2 < Lutaml::Model::Serializable
55
55
  xml do
56
- root 'model2'
56
+ element "model2"
57
57
  namespace 'https://example.com/project/v1', 'proj'
58
58
  end
59
59
  end
@@ -134,7 +134,7 @@ class Document < Lutaml::Model::Serializable
134
134
  attribute :creator, DcCreatorType
135
135
 
136
136
  xml do
137
- root 'document'
137
+ element "document"
138
138
  map_element 'title', to: :title # dc:title automatically
139
139
  map_element 'creator', to: :creator # dc:creator automatically
140
140
  end
@@ -145,7 +145,7 @@ class BookMetadata < Lutaml::Model::Serializable
145
145
  attribute :creator, DcCreatorType
146
146
 
147
147
  xml do
148
- root 'book'
148
+ element "book"
149
149
  map_element 'title', to: :title # dc:title automatically
150
150
  map_element 'creator', to: :creator # dc:creator automatically
151
151
  end
@@ -162,7 +162,7 @@ class Document < Lutaml::Model::Serializable
162
162
  attribute :creator, :string
163
163
 
164
164
  xml do
165
- root 'document'
165
+ element "document"
166
166
  # Repetitive and error-prone
167
167
  map_element 'title', to: :title,
168
168
  namespace: 'http://purl.org/dc/elements/1.1/', prefix: 'dc'
@@ -181,7 +181,7 @@ end
181
181
  # Consolidate frequently-used namespaces at root
182
182
  class Vcard < Lutaml::Model::Serializable
183
183
  xml do
184
- root "vCard"
184
+ element "vCard"
185
185
  namespace VcardNamespace
186
186
  namespace_scope [VcardNamespace, DcNamespace, DctermsNamespace]
187
187
 
@@ -206,7 +206,7 @@ end
206
206
  # Without namespace_scope for multi-namespace documents
207
207
  class Vcard < Lutaml::Model::Serializable
208
208
  xml do
209
- root "vCard"
209
+ element "vCard"
210
210
  namespace VcardNamespace
211
211
  # No namespace_scope
212
212
 
@@ -236,7 +236,7 @@ class Ceramic < Lutaml::Model::Serializable
236
236
  element 'ceramic'
237
237
  namespace CeramicNamespace
238
238
  # namespace_scope [CeramicNamespace] # NOT NEEDED - only one namespace
239
-
239
+
240
240
  map_element 'type', to: :type
241
241
  map_element 'glaze', to: :glaze
242
242
  end
@@ -250,7 +250,7 @@ end
250
250
  # Keep rarely-used namespaces local for clarity
251
251
  class Document < Lutaml::Model::Serializable
252
252
  xml do
253
- root 'document'
253
+ element "document"
254
254
  namespace DocumentNamespace
255
255
  namespace_scope [DocumentNamespace] # Only frequently used
256
256
 
@@ -284,7 +284,7 @@ end
284
284
  ----
285
285
  class Model < Lutaml::Model::Serializable
286
286
  xml do
287
- root 'model' # Backward compatible, still works
287
+ element "model" # Backward compatible, still works
288
288
  map_element 'attr', to: :attr
289
289
  end
290
290
  end
@@ -441,7 +441,7 @@ end
441
441
  ----
442
442
  class RichText < Lutaml::Model::Serializable
443
443
  xml do
444
- root 'text', mixed: true # DEPRECATED - use mixed_content instead
444
+ element "text", mixed: true # DEPRECATED - use mixed_content instead
445
445
  map_element 'b', to: :bold
446
446
  end
447
447
  end
@@ -723,7 +723,8 @@ end
723
723
 
724
724
  * **Ox**: Fastest, use for performance-critical applications
725
725
  * **Nokogiri**: Most compatible, good balance
726
- * **Oga**: Pure Ruby, works with Opal, use when no native extensions allowed
726
+ * **Oga**: Pure Ruby, use when no native extensions allowed
727
+ * **REXML**: Pure Ruby (bundled with Ruby), Opal-compatible
727
728
 
728
729
  **Configure once:**
729
730
 
@@ -1359,7 +1359,7 @@ Version 0.8.0 unifies the `xml do` syntax for both model classes and custom Type
1359
1359
  class Person < Lutaml::Model::Serializable
1360
1360
  xml do
1361
1361
  namespace "http://example.com/ns", "p" # Different syntax
1362
- root "person"
1362
+ element "person"
1363
1363
  end
1364
1364
  end
1365
1365
 
@@ -1485,7 +1485,7 @@ Version 0.8.0 enforces **model-centric namespace definitions**. Namespaces are d
1485
1485
  ----
1486
1486
  class Parent < Lutaml::Model::Serializable
1487
1487
  xml do
1488
- root "parent"
1488
+ element "parent"
1489
1489
  namespace "http://parent.com", "p"
1490
1490
 
1491
1491
  # ❌ Namespace on mapping - NO LONGER SUPPORTED
@@ -808,7 +808,7 @@ class ReferenceSet < Lutaml::Model::Serializable
808
808
  ]
809
809
 
810
810
  xml do
811
- root "ReferenceSet"
811
+ element "ReferenceSet"
812
812
 
813
813
  map_element "reference", to: :references, polymorphic: {
814
814
  # This refers to the attribute in the polymorphic model, you need
@@ -945,7 +945,7 @@ class SomeModel < Lutaml::Model::Serializable
945
945
  attribute :coll, :string, collection: true
946
946
 
947
947
  xml do
948
- root "some-model"
948
+ element "some-model"
949
949
  map_element 'collection', to: :coll
950
950
  end
951
951
 
@@ -145,7 +145,7 @@ class TitleDelimiterCollection < Lutaml::Model::Collection
145
145
  instances :items, :string
146
146
 
147
147
  xml do
148
- root "titles"
148
+ element "titles"
149
149
  map_attribute "title", to: :items, delimiter: "; " <1>
150
150
  end
151
151
  end
@@ -164,7 +164,7 @@ class TitleCollection < Lutaml::Model::Collection
164
164
  instances :items, :string
165
165
 
166
166
  xml do
167
- root "titles"
167
+ element "titles"
168
168
  map_attribute "title", to: :items, as_list: {
169
169
  import: ->(str) { str.split("; ") }, <1>
170
170
  export: ->(arr) { arr.join("; ") }, <2>
@@ -302,7 +302,6 @@ class TitleCollection < Lutaml::Model::Collection
302
302
  instances :titles, Title
303
303
 
304
304
  key_value do
305
- no_root # default
306
305
  map_instances to: :titles
307
306
  end
308
307
  end
@@ -382,7 +381,6 @@ class TitleCollection < Lutaml::Model::Collection
382
381
  instances :titles, Title
383
382
 
384
383
  key_value do
385
- no_root # default
386
384
  map_instances to: :titles
387
385
  end
388
386
  end
@@ -477,11 +475,11 @@ class MyCollection < Lutaml::Model::Collection
477
475
  instances :items, ModelType
478
476
 
479
477
  xml do
480
- root "name-of-xml-container-element"
478
+ element "name-of-xml-container-element"
481
479
  end
482
480
 
483
481
  key_value do
484
- root "name-of-key-value-container-element"
482
+ key "name-of-key-value-wrapper-key"
485
483
  end
486
484
  end
487
485
 
@@ -490,6 +488,15 @@ class ModelType < Lutaml::Model::Serializable
490
488
  end
491
489
  ----
492
490
 
491
+ In the `key_value` block:
492
+
493
+ - `key "key-name"` sets the wrapper key for the collection in key-value formats (JSON, YAML, TOML).
494
+ The serialized output wraps all instances under this key (e.g., `{"titles": [...]}`).
495
+ - Without a `key` call (the default), instances are serialized directly at the top level
496
+ (e.g., `["Item One", "Item Two"]`).
497
+
498
+ NOTE: Key-value formats use `key` to set the wrapper key name, and `element` for XML element names.
499
+
493
500
  A named collection can alternatively be implemented as a non-collection model
494
501
  ("Model class with an attribute") that contains the collection of instances. In
495
502
  this case, the attribute will be an Array object, which does not contain
@@ -504,7 +511,7 @@ class Title < Lutaml::Model::Serializable
504
511
  attribute :title, :string
505
512
 
506
513
  xml do
507
- root "title"
514
+ element "title"
508
515
  map_content to: :title
509
516
  end
510
517
  end
@@ -513,7 +520,7 @@ class DirectTitleCollection < Lutaml::Model::Collection
513
520
  instances :items, Title
514
521
 
515
522
  xml do
516
- root "titles"
523
+ element "titles"
517
524
  map_element "title", to: :items
518
525
  end
519
526
 
@@ -639,7 +646,7 @@ class Title < Lutaml::Model::Serializable
639
646
  attribute :title, :string
640
647
 
641
648
  xml do
642
- root "title"
649
+ element "title"
643
650
  map_element "content", to: :title
644
651
  end
645
652
 
@@ -652,12 +659,12 @@ class TitleCollection < Lutaml::Model::Collection
652
659
  instances :items, Title
653
660
 
654
661
  xml do
655
- root "titles"
662
+ element "titles"
656
663
  map_element 'title', to: :items
657
664
  end
658
665
 
659
666
  key_value do
660
- root "titles"
667
+ key "titles"
661
668
  map_instances to: :items
662
669
  end
663
670
  end
@@ -742,12 +749,12 @@ class BibliographicItem < Lutaml::Model::Serializable
742
749
  attribute :title_parts, :string, collection: StringParts
743
750
 
744
751
  xml do
745
- root "titles"
752
+ element "titles"
746
753
  map_element "title", to: :title_parts
747
754
  end
748
755
 
749
756
  key_value do
750
- root "titles"
757
+ key "titles"
751
758
  map_instances to: :title_parts
752
759
  end
753
760
 
@@ -829,7 +836,7 @@ class TitleCollection < Lutaml::Model::Collection
829
836
  instances :items, Title
830
837
 
831
838
  xml do
832
- root "title-group"
839
+ element "title-group"
833
840
  map_element "artifact", to: :items
834
841
  end
835
842
  end
@@ -838,7 +845,7 @@ class BibItem < Lutaml::Model::Serializable
838
845
  attribute :titles, TitleCollection
839
846
 
840
847
  xml do
841
- root "bibitem"
848
+ element "bibitem"
842
849
  # This overrides the collection's root "title-group"
843
850
  map_element "titles", to: :titles
844
851
  end
@@ -1367,12 +1374,11 @@ class OrderedItemCollection < Lutaml::Model::Collection
1367
1374
  ordered by: :id, order: :desc
1368
1375
 
1369
1376
  xml do
1370
- root "items"
1377
+ element "items"
1371
1378
  map_element "item", to: :items
1372
1379
  end
1373
1380
 
1374
1381
  key_value do
1375
- no_root
1376
1382
  map_instances to: :items
1377
1383
  end
1378
1384
  end
@@ -1401,7 +1407,7 @@ class ProcOrderedItemCollection < Lutaml::Model::Collection
1401
1407
  ordered by: ->(item) { [item.name.length, item.name] }, order: :asc
1402
1408
 
1403
1409
  xml do
1404
- root "items"
1410
+ element "items"
1405
1411
  map_element "item", to: :items
1406
1412
  end
1407
1413
  end
@@ -1543,7 +1549,7 @@ class ReferenceSet < Lutaml::Model::Collection
1543
1549
  ]
1544
1550
 
1545
1551
  xml do
1546
- root "ReferenceSet"
1552
+ element "ReferenceSet"
1547
1553
  map_instances to: :references, polymorphic: {
1548
1554
  attribute: "_class",
1549
1555
  class_map: {
@@ -1640,7 +1646,7 @@ class ReferenceSet < Lutaml::Model::Collection
1640
1646
  ]
1641
1647
 
1642
1648
  xml do
1643
- root "ReferenceSet"
1649
+ element "ReferenceSet"
1644
1650
  map_instances to: :references, polymorphic: {
1645
1651
  attribute: "_class",
1646
1652
  class_map: {
@@ -74,7 +74,7 @@ When an adapter is needed for a format, `AdapterResolver` follows this chain:
74
74
  | Pure Ruby. No compilation needed. Opal-compatible.
75
75
 
76
76
  | `:rexml`
77
- | Pure Ruby. Bundled with Ruby (default gem).
77
+ | Pure Ruby. Bundled with Ruby (default gem). Opal-compatible.
78
78
  |===
79
79
 
80
80
  === JSON adapters
@@ -261,8 +261,8 @@ end
261
261
 
262
262
  * **Nokogiri**: Most projects (default, best compatibility)
263
263
  * **Ox**: Performance-critical applications
264
- * **Oga**: Pure Ruby environments, Opal/JavaScript compilation
265
- * **REXML**: No extra gems, pure Ruby (bundled with Ruby)
264
+ * **Oga**: Pure Ruby environments
265
+ * **REXML**: No extra gems, pure Ruby (bundled with Ruby). Also used under Opal.
266
266
 
267
267
  === Choose JSON adapter based on
268
268
 
@@ -279,12 +279,14 @@ end
279
279
 
280
280
  Lutaml::Model supports running under https://opalrb.com[Opal] (Ruby compiled to JavaScript) with some limitations. The library detects the runtime automatically via `Lutaml::Model::RuntimeCompatibility` and adapts its behavior accordingly.
281
281
 
282
+ The XML parsing layer is provided by the https://github.com/lutaml/moxml[moxml] gem, which has been updated to support Opal. Under Opal, moxml uses the REXML adapter because Opal reimplements `strscan` and `stringio` in its stdlib, enabling REXML (pure Ruby) to compile cleanly to JavaScript.
283
+
282
284
  === Adapter defaults on Opal
283
285
 
284
286
  [cols="1,2",options="header"]
285
287
  |===
286
288
  | Format | Behavior
287
- | XML | Only `:oga` is available (auto-selected). Nokogiri, Ox, and REXML require native extensions.
289
+ | XML | Only `:rexml` is available (auto-selected). Opal reimplements strscan/stringio in its stdlib, enabling REXML to compile to JavaScript.
288
290
  | JSON | Only `:standard` is available. Oj and MultiJson require native extensions.
289
291
  | YAML | `:standard` (Psych ships with Opal's stdlib).
290
292
  | TOML | **Not available.** Both tomlib and toml-rb depend on native extensions.
@@ -299,6 +301,9 @@ The following features raise `NotImplementedError` when called under Opal:
299
301
  * `Lutaml::Model::Schema.to_relaxng` -- RELAX NG generation requires Nokogiri
300
302
  * `Lutaml::Model::Schema.from_xml` -- XML schema compilation is not supported
301
303
  * `Lutaml::Xml::Schema::Xsd::Base#to_formatted_xml` -- XSD formatted output requires the Canon gem
304
+ * XPath queries -- REXML XPath requires features not yet supported by Opal's stdlib
305
+
306
+ See the link:../guides/opal[Opal Usage Guide] for complete setup instructions and limitations.
302
307
 
303
308
  == See also
304
309
 
@@ -76,7 +76,7 @@ class TitleCollection < Lutaml::Model::Collection
76
76
  organizes :per_lang, PerLangTitleGroup
77
77
 
78
78
  xml do
79
- root "titles"
79
+ element "titles"
80
80
  map_instances to: :items
81
81
 
82
82
  consolidate_map by: :lang, to: :per_lang do
@@ -105,7 +105,7 @@ class IndividualTitle < Lutaml::Model::Serializable
105
105
  attribute :content, :string
106
106
 
107
107
  xml do
108
- root "title"
108
+ element "title"
109
109
  map_attribute "lang", to: :lang
110
110
  map_attribute "type", to: :type_of_title
111
111
  map_content to: :content
@@ -127,7 +127,7 @@ class TitleCollection < Lutaml::Model::Collection
127
127
  organizes :per_lang, PerLangTitleGroup
128
128
 
129
129
  xml do
130
- root "titles"
130
+ element "titles"
131
131
  map_instances to: :items
132
132
 
133
133
  consolidate_map by: :lang, to: :per_lang do
@@ -147,7 +147,7 @@ class Bibdata < Lutaml::Model::Serializable
147
147
  attribute :titles, IndividualTitle, collection: TitleCollection
148
148
 
149
149
  xml do
150
- root "bibdata"
150
+ element "bibdata"
151
151
  map_element "title", to: :titles
152
152
  end
153
153
  end
@@ -14,8 +14,9 @@ This feature works both with XML and key-value formats.
14
14
 
15
15
  * The import order determines how elements and attributes are overwritten.
16
16
 
17
- * An importable model with XML serialization mappings requires setting the model's
18
- XML serialization configuration with the `no_root` directive.
17
+ * An importable model with XML serialization mappings is a "type-only model" —
18
+ it has no `element` declaration in its `xml` block, meaning it can only be
19
+ used as an embedded type through a parent model.
19
20
 
20
21
  The model can be imported into another model using the following directives:
21
22
 
@@ -25,11 +26,11 @@ The model can be imported into another model using the following directives:
25
26
 
26
27
  `import_model_mappings`:: imports only mappings.
27
28
 
28
- NOTE: Models with `no_root` can only be parsed through parent models.
29
- Direct calling `NoRootModel.from_xml` will raise a `NoRootMappingError`.
29
+ NOTE: Type-only models (no `element` declaration) can only be parsed through parent models.
30
+ Directly calling `TypeOnlyModel.from_xml` will raise a `TypeOnlyMappingError`.
30
31
 
31
32
  NOTE: Namespaces are not currently supported in importable models.
32
- If `namespace` is defined with `no_root`, `NoRootNamespaceError` will be raised.
33
+ If `namespace` is defined with the deprecated `no_root`, `TypeOnlyNamespaceError` will be raised.
33
34
 
34
35
  .Importing model components using an importable model
35
36
  [example]
@@ -51,7 +52,7 @@ class GroupOfItems < Lutaml::Model::Serializable
51
52
  attribute :code, :string
52
53
 
53
54
  xml do
54
- no_root
55
+ # Type-only model - no element declaration needed
55
56
  sequence do
56
57
  map_element "name", to: :name
57
58
  map_element "type", to: :type
@@ -67,7 +68,7 @@ class ComplexType < Lutaml::Model::Serializable
67
68
  import_model_attributes GroupOfItems
68
69
 
69
70
  xml do
70
- root "GroupOfItems"
71
+ element "GroupOfItems"
71
72
 
72
73
  map_attribute "tag", to: :tag
73
74
  map_content to: :content
@@ -96,7 +97,7 @@ end
96
97
  [source,ruby]
97
98
  ----
98
99
  > parsed = GroupOfItems.from_xml(xml)
99
- > # Lutaml::Model::NoRootMappingError: "GroupOfItems has `no_root`, it allowed only for reusable models"
100
+ > # Lutaml::Model::TypeOnlyMappingError: "GroupOfItems is a type-only model (no element declared), ..."
100
101
  ----
101
102
  ====
102
103
 
@@ -124,7 +125,7 @@ class Address < Lutaml::Model::Serializable
124
125
  attribute :zip, :string
125
126
 
126
127
  xml do
127
- no_root
128
+ # Type-only model - no element declaration needed
128
129
 
129
130
  map_element :street, to: :street
130
131
  map_element :city, to: :city
@@ -137,7 +138,7 @@ class Person < Lutaml::Model::Serializable
137
138
  import_model_attributes Address
138
139
 
139
140
  xml do
140
- root "Person"
141
+ element "Person"
141
142
 
142
143
  map_element :name, to: :name
143
144
  sequence do
@@ -193,7 +194,7 @@ class ContactEmail < Lutaml::Model::Serializable
193
194
  attribute :email, :string
194
195
 
195
196
  xml do
196
- no_root
197
+ # Type-only model - no element declaration needed
197
198
 
198
199
  map_element :email, to: :email
199
200
  end
@@ -203,7 +204,7 @@ class ContactPhone < Lutaml::Model::Serializable
203
204
  attribute :phone, :string
204
205
 
205
206
  xml do
206
- no_root
207
+ # Type-only model - no element declaration needed
207
208
 
208
209
  map_element :phone, to: :phone
209
210
  end
@@ -217,7 +218,7 @@ class Person < Lutaml::Model::Serializable
217
218
  end
218
219
 
219
220
  xml do
220
- root "Person"
221
+ element "Person"
221
222
 
222
223
  map_element :email, to: :email
223
224
  map_element :phone, to: :phone
@@ -22,6 +22,7 @@ Fundamental concepts, configuration, and essential features of Lutaml::Model.
22
22
  * link:breaking-changes[Breaking Changes] - Version compatibility
23
23
  * link:comparison-with-shale[Comparison with Shale] - Migration guide
24
24
  * link:xml-conformance[XML Standards Conformance] - W3C spec compliance status
25
+ * link:../guides/opal[Opal Usage] - Run in the browser via Opal
25
26
  * link:troubleshooting[Troubleshooting] - Common issues and solutions
26
27
 
27
28
  == Getting started
@@ -56,7 +56,7 @@ class Person < Lutaml::Model::Serializable
56
56
  attribute :age, :integer
57
57
 
58
58
  xml do
59
- root "person"
59
+ element "person"
60
60
  map_element "name", to: :name
61
61
  map_element "age", to: :age
62
62
  end
@@ -192,8 +192,7 @@ Requires the `nokogiri` gem.
192
192
  Oga::
193
193
  (optional)
194
194
  Pure Ruby XML parser.
195
- Does not require native extensions and is suitable for
196
- https://opalrb.com[Opal] (Ruby on JavaScript).
195
+ Does not require native extensions.
197
196
  Requires the `oga` gem.
198
197
 
199
198
  Ox::
@@ -206,6 +205,8 @@ REXML::
206
205
  (optional)
207
206
  Pure Ruby XML parser, bundled as a default gem with Ruby.
208
207
  Moved from standard library to a default gem in Ruby 3.0.
208
+ Opal-compatible: Opal reimplements `strscan` and `stringio` in its stdlib,
209
+ enabling REXML to compile cleanly to JavaScript.
209
210
  Requires the `rexml` gem (bundled with Ruby by default).
210
211
 
211
212
 
@@ -92,7 +92,7 @@ class Event < Lutaml::Model::Serializable
92
92
  attribute :start_date, :date
93
93
 
94
94
  xml do
95
- root "event"
95
+ element "event"
96
96
  map_element "startDate", to: :start_date
97
97
  end
98
98
 
@@ -150,7 +150,7 @@ class ProcessingTask < Lutaml::Model::Serializable
150
150
  attribute :processing_time, :duration
151
151
 
152
152
  xml do
153
- root "task"
153
+ element "task"
154
154
  map_element "processingTime", to: :processing_time
155
155
  end
156
156
  end
@@ -180,7 +180,7 @@ class Resource < Lutaml::Model::Serializable
180
180
  attribute :schema_location, :uri
181
181
 
182
182
  xml do
183
- root "resource"
183
+ element "resource"
184
184
  map_element "homepage", to: :homepage
185
185
  map_attribute "schemaLocation", to: :schema_location
186
186
  end
@@ -215,7 +215,7 @@ class Reference < Lutaml::Model::Serializable
215
215
  attribute :target, :qname
216
216
 
217
217
  xml do
218
- root "reference"
218
+ element "reference"
219
219
  map_attribute "type", to: :ref_type
220
220
  map_element "target", to: :target
221
221
  end
@@ -253,7 +253,7 @@ class Attachment < Lutaml::Model::Serializable
253
253
  attribute :filename, :string
254
254
 
255
255
  xml do
256
- root "attachment"
256
+ element "attachment"
257
257
  map_element "content", to: :content
258
258
  map_attribute "filename", to: :filename
259
259
  end
@@ -294,7 +294,7 @@ class Checksum < Lutaml::Model::Serializable
294
294
  attribute :algorithm, :string
295
295
 
296
296
  xml do
297
- root "checksum"
297
+ element "checksum"
298
298
  map_element "value", to: :hash_value
299
299
  map_attribute "algorithm", to: :algorithm
300
300
  end
@@ -360,7 +360,7 @@ class Article < Lutaml::Model::Serializable
360
360
  attribute :title, :string
361
361
 
362
362
  xml do
363
- root "article"
363
+ element "article"
364
364
  map_attribute "lang", to: :lang
365
365
  map_attribute "space", to: :space
366
366
  map_attribute "id", to: :id
@@ -486,7 +486,7 @@ class Task < Lutaml::Model::Serializable
486
486
  attribute :priority, :symbol
487
487
 
488
488
  xml do
489
- root "task"
489
+ element "task"
490
490
  map_element "status", to: :status
491
491
  map_element "priority", to: :priority
492
492
  end
@@ -731,7 +731,7 @@ class Address < Lutaml::Model::Serializable
731
731
 
732
732
  # Define how this complex object maps to different formats
733
733
  xml do
734
- root "Address"
734
+ element "Address"
735
735
  map_element "Street", to: :street
736
736
  map_element "City", to: :city
737
737
  map_element "PostalCode", to: :postal_code
@@ -1051,7 +1051,7 @@ end
1051
1051
  class Ceramic < Lutaml::Model::Serializable
1052
1052
  attribute :kiln_firing_time, HighPrecisionDateTime
1053
1053
  xml do
1054
- root 'ceramic'
1054
+ element "ceramic"
1055
1055
  map_element 'kilnFiringTime', to: :kiln_firing_time
1056
1056
  # ...
1057
1057
  end
@@ -449,7 +449,7 @@ module Mml
449
449
  attribute :mrow, Mrow
450
450
 
451
451
  xml do
452
- root "math"
452
+ element "math"
453
453
  end
454
454
  end
455
455
  end
@@ -545,7 +545,7 @@ class MyDocument < Lutaml::Model::Serializable
545
545
  attribute :math, Mml::V2::Math # Has lutaml_default_register = :mml_v2
546
546
 
547
547
  xml do
548
- root "document"
548
+ element "document"
549
549
  map_element "math", to: :math
550
550
  end
551
551
  end
@@ -639,7 +639,7 @@ module Mml
639
639
  attribute :mi_value, :string
640
640
 
641
641
  xml do
642
- root "mmultiscripts"
642
+ element "mmultiscripts"
643
643
  map_element "mi", to: :mi_value
644
644
  end
645
645
  end
@@ -648,7 +648,7 @@ module Mml
648
648
  attribute :mmultiscripts_value, Mmultiscripts, collection: true
649
649
 
650
650
  xml do
651
- root "math"
651
+ element "math"
652
652
  map_element "mmultiscripts", to: :mmultiscripts_value
653
653
  end
654
654
  end
@@ -665,7 +665,7 @@ class MyDocument < Lutaml::Model::Serializable
665
665
  attribute :math, Mml::Math
666
666
 
667
667
  xml do
668
- root "document"
668
+ element "document"
669
669
  map_attribute "id", to: :id
670
670
  map_element "math", to: :math
671
671
  end
@@ -704,7 +704,7 @@ class MyDocument < Lutaml::Model::Serializable
704
704
  attribute :math, Mml::V2::Math # Has lutaml_default_register = :mml_v2
705
705
 
706
706
  xml do
707
- root "document"
707
+ element "document"
708
708
  map_element "math", to: :math
709
709
  end
710
710
  end
@@ -776,7 +776,7 @@ class Article < Lutaml::Model::Serializable
776
776
  attribute :formula, Mml::V2::Math
777
777
 
778
778
  xml do
779
- root "article"
779
+ element "article"
780
780
  map_element "math", to: :formula
781
781
  end
782
782
  end