rng 0.1.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +63 -0
  3. data/.github/workflows/release.yml +8 -3
  4. data/.gitignore +11 -0
  5. data/.rubocop.yml +10 -7
  6. data/.rubocop_todo.yml +229 -23
  7. data/CHANGELOG.md +317 -0
  8. data/CLAUDE.md +139 -0
  9. data/Gemfile +11 -12
  10. data/README.adoc +1538 -11
  11. data/Rakefile +11 -3
  12. data/docs/Gemfile +8 -0
  13. data/docs/_config.yml +23 -0
  14. data/docs/getting-started/index.adoc +75 -0
  15. data/docs/guides/error-handling.adoc +137 -0
  16. data/docs/guides/external-references.adoc +128 -0
  17. data/docs/guides/index.adoc +24 -0
  18. data/docs/guides/parsing-rnc.adoc +141 -0
  19. data/docs/guides/parsing-rng-xml.adoc +81 -0
  20. data/docs/guides/rng-to-rnc.adoc +101 -0
  21. data/docs/guides/validation.adoc +85 -0
  22. data/docs/index.adoc +52 -0
  23. data/docs/reference/api.adoc +126 -0
  24. data/docs/reference/cli.adoc +182 -0
  25. data/docs/understanding/architecture.adoc +58 -0
  26. data/docs/understanding/rng-vs-rnc.adoc +118 -0
  27. data/exe/rng +5 -0
  28. data/lib/rng/any_name.rb +10 -8
  29. data/lib/rng/attribute.rb +28 -26
  30. data/lib/rng/choice.rb +24 -24
  31. data/lib/rng/cli.rb +607 -0
  32. data/lib/rng/data.rb +10 -10
  33. data/lib/rng/datatype_declaration.rb +26 -0
  34. data/lib/rng/define.rb +44 -41
  35. data/lib/rng/div.rb +36 -0
  36. data/lib/rng/documentation.rb +9 -0
  37. data/lib/rng/element.rb +39 -37
  38. data/lib/rng/empty.rb +7 -7
  39. data/lib/rng/except.rb +25 -25
  40. data/lib/rng/external_ref.rb +8 -8
  41. data/lib/rng/external_ref_resolver.rb +602 -0
  42. data/lib/rng/foreign_attribute.rb +26 -0
  43. data/lib/rng/foreign_element.rb +33 -0
  44. data/lib/rng/grammar.rb +14 -12
  45. data/lib/rng/group.rb +26 -24
  46. data/lib/rng/include.rb +5 -6
  47. data/lib/rng/include_processor.rb +461 -0
  48. data/lib/rng/interleave.rb +23 -23
  49. data/lib/rng/list.rb +22 -22
  50. data/lib/rng/mixed.rb +23 -23
  51. data/lib/rng/name.rb +6 -7
  52. data/lib/rng/namespace_declaration.rb +47 -0
  53. data/lib/rng/namespaces.rb +15 -0
  54. data/lib/rng/not_allowed.rb +7 -7
  55. data/lib/rng/ns_name.rb +9 -9
  56. data/lib/rng/one_or_more.rb +23 -23
  57. data/lib/rng/optional.rb +23 -23
  58. data/lib/rng/param.rb +7 -8
  59. data/lib/rng/parent_ref.rb +8 -8
  60. data/lib/rng/parse_tree_processor.rb +695 -0
  61. data/lib/rng/pattern.rb +7 -7
  62. data/lib/rng/ref.rb +8 -8
  63. data/lib/rng/rnc_builder.rb +927 -0
  64. data/lib/rng/rnc_parser.rb +605 -305
  65. data/lib/rng/rnc_to_rng_converter.rb +1408 -0
  66. data/lib/rng/schema_preamble.rb +73 -0
  67. data/lib/rng/schema_validator.rb +1622 -0
  68. data/lib/rng/start.rb +27 -25
  69. data/lib/rng/test_suite_parser.rb +168 -0
  70. data/lib/rng/text.rb +11 -8
  71. data/lib/rng/to_rnc.rb +4 -35
  72. data/lib/rng/value.rb +6 -7
  73. data/lib/rng/version.rb +1 -1
  74. data/lib/rng/zero_or_more.rb +23 -23
  75. data/lib/rng.rb +68 -17
  76. data/rng.gemspec +18 -19
  77. data/scripts/extract_spectest_resources.rb +96 -0
  78. data/spec/fixtures/compacttest.xml +2511 -0
  79. data/spec/fixtures/external/circular_a.rng +7 -0
  80. data/spec/fixtures/external/circular_b.rng +7 -0
  81. data/spec/fixtures/external/circular_main.rng +7 -0
  82. data/spec/fixtures/external/external_ref_lib.rng +7 -0
  83. data/spec/fixtures/external/external_ref_main.rng +7 -0
  84. data/spec/fixtures/external/include_lib.rng +7 -0
  85. data/spec/fixtures/external/include_main.rng +3 -0
  86. data/spec/fixtures/external/nested_chain.rng +6 -0
  87. data/spec/fixtures/external/nested_leaf.rng +7 -0
  88. data/spec/fixtures/external/nested_mid.rng +8 -0
  89. data/spec/fixtures/metanorma/3gpp.rnc +35 -0
  90. data/spec/fixtures/metanorma/3gpp.rng +105 -0
  91. data/spec/fixtures/metanorma/basicdoc.rnc +11 -0
  92. data/spec/fixtures/metanorma/bipm.rnc +148 -0
  93. data/spec/fixtures/metanorma/bipm.rng +376 -0
  94. data/spec/fixtures/metanorma/bsi.rnc +104 -0
  95. data/spec/fixtures/metanorma/bsi.rng +332 -0
  96. data/spec/fixtures/metanorma/csa.rnc +45 -0
  97. data/spec/fixtures/metanorma/csa.rng +131 -0
  98. data/spec/fixtures/metanorma/csd.rnc +43 -0
  99. data/spec/fixtures/metanorma/csd.rng +132 -0
  100. data/spec/fixtures/metanorma/gbstandard.rnc +99 -0
  101. data/spec/fixtures/metanorma/gbstandard.rng +316 -0
  102. data/spec/fixtures/metanorma/iec.rnc +49 -0
  103. data/spec/fixtures/metanorma/iec.rng +193 -0
  104. data/spec/fixtures/metanorma/ietf.rnc +275 -0
  105. data/spec/fixtures/metanorma/ietf.rng +925 -0
  106. data/spec/fixtures/metanorma/iho.rnc +58 -0
  107. data/spec/fixtures/metanorma/iho.rng +179 -0
  108. data/spec/fixtures/metanorma/isodoc.rnc +873 -0
  109. data/spec/fixtures/metanorma/isodoc.rng +2704 -0
  110. data/spec/fixtures/metanorma/isostandard-amd.rnc +43 -0
  111. data/spec/fixtures/metanorma/isostandard-amd.rng +108 -0
  112. data/spec/fixtures/metanorma/isostandard.rnc +166 -0
  113. data/spec/fixtures/metanorma/isostandard.rng +494 -0
  114. data/spec/fixtures/metanorma/itu.rnc +122 -0
  115. data/spec/fixtures/metanorma/itu.rng +377 -0
  116. data/spec/fixtures/metanorma/m3d.rnc +41 -0
  117. data/spec/fixtures/metanorma/m3d.rng +122 -0
  118. data/spec/fixtures/metanorma/mpfd.rnc +36 -0
  119. data/spec/fixtures/metanorma/mpfd.rng +95 -0
  120. data/spec/fixtures/metanorma/nist.rnc +77 -0
  121. data/spec/fixtures/metanorma/nist.rng +216 -0
  122. data/spec/fixtures/metanorma/ogc.rnc +51 -0
  123. data/spec/fixtures/metanorma/ogc.rng +151 -0
  124. data/spec/fixtures/metanorma/reqt.rnc +6 -0
  125. data/spec/fixtures/metanorma/rsd.rnc +36 -0
  126. data/spec/fixtures/metanorma/rsd.rng +95 -0
  127. data/spec/fixtures/metanorma/un.rnc +103 -0
  128. data/spec/fixtures/metanorma/un.rng +367 -0
  129. data/spec/fixtures/rnc/base.rnc +4 -0
  130. data/spec/fixtures/rnc/grammar_with_trailing.rnc +8 -0
  131. data/spec/fixtures/rnc/main_include_trailing.rnc +3 -0
  132. data/spec/fixtures/rnc/main_with_include.rnc +5 -0
  133. data/spec/fixtures/rnc/test_augment.rnc +10 -0
  134. data/spec/fixtures/rnc/test_isodoc_simple.rnc +9 -0
  135. data/spec/fixtures/rnc/top_level_include.rnc +8 -0
  136. data/spec/fixtures/spectest_external/case_10_4.7/x +3 -0
  137. data/spec/fixtures/spectest_external/case_10_4.7/y +7 -0
  138. data/spec/fixtures/spectest_external/case_11_4.7/x +3 -0
  139. data/spec/fixtures/spectest_external/case_12_4.7/x +3 -0
  140. data/spec/fixtures/spectest_external/case_13_4.7/x +3 -0
  141. data/spec/fixtures/spectest_external/case_13_4.7/y +3 -0
  142. data/spec/fixtures/spectest_external/case_14_4.7/x +7 -0
  143. data/spec/fixtures/spectest_external/case_15_4.7/x +7 -0
  144. data/spec/fixtures/spectest_external/case_16_4.7/x +5 -0
  145. data/spec/fixtures/spectest_external/case_17_4.7/x +5 -0
  146. data/spec/fixtures/spectest_external/case_18_4.7/x +7 -0
  147. data/spec/fixtures/spectest_external/case_19_4.7/level1.rng +9 -0
  148. data/spec/fixtures/spectest_external/case_19_4.7/level2.rng +7 -0
  149. data/spec/fixtures/spectest_external/case_1_4.5/sub1/x +3 -0
  150. data/spec/fixtures/spectest_external/case_1_4.5/sub3/x +3 -0
  151. data/spec/fixtures/spectest_external/case_1_4.5/x +3 -0
  152. data/spec/fixtures/spectest_external/case_20_4.6/x +3 -0
  153. data/spec/fixtures/spectest_external/case_2_4.5/x +3 -0
  154. data/spec/fixtures/spectest_external/case_3_4.6/x +3 -0
  155. data/spec/fixtures/spectest_external/case_4_4.6/x +3 -0
  156. data/spec/fixtures/spectest_external/case_5_4.6/x +1 -0
  157. data/spec/fixtures/spectest_external/case_6_4.6/x +5 -0
  158. data/spec/fixtures/spectest_external/case_7_4.6/x +1 -0
  159. data/spec/fixtures/spectest_external/case_7_4.6/y +1 -0
  160. data/spec/fixtures/spectest_external/case_8_4.7/x +7 -0
  161. data/spec/fixtures/spectest_external/case_9_4.7/x +7 -0
  162. data/spec/fixtures/spectest_external/resources.json +149 -0
  163. data/spec/rng/advanced_rnc_spec.rb +101 -0
  164. data/spec/rng/compacttest_spec.rb +197 -0
  165. data/spec/rng/datatype_declaration_spec.rb +28 -0
  166. data/spec/rng/div_spec.rb +207 -0
  167. data/spec/rng/external_ref_resolver_spec.rb +122 -0
  168. data/spec/rng/metanorma_conversion_spec.rb +159 -0
  169. data/spec/rng/namespace_declaration_spec.rb +60 -0
  170. data/spec/rng/namespace_support_spec.rb +199 -0
  171. data/spec/rng/rnc_parser_spec.rb +498 -22
  172. data/spec/rng/rnc_roundtrip_spec.rb +96 -82
  173. data/spec/rng/rng_generation_spec.rb +288 -0
  174. data/spec/rng/roundtrip_spec.rb +342 -0
  175. data/spec/rng/schema_preamble_spec.rb +145 -0
  176. data/spec/rng/schema_spec.rb +68 -64
  177. data/spec/rng/spectest_spec.rb +168 -90
  178. data/spec/rng_spec.rb +2 -2
  179. data/spec/spec_helper.rb +7 -42
  180. metadata +141 -8
@@ -0,0 +1,101 @@
1
+ ---
2
+ title: Converting RNG to RNC
3
+ layout: default
4
+ nav_order: 3
5
+ parent: Guides
6
+ ---
7
+
8
+ = Converting Between RNG and RNC
9
+
10
+ The RNG gem supports converting between RNG XML format and RNC compact syntax.
11
+
12
+ == RNG to RNC Conversion
13
+
14
+ Convert a grammar parsed from RNG XML to RNC compact syntax:
15
+
16
+ [source,ruby]
17
+ ----
18
+ require 'rng'
19
+
20
+ # Parse RNG XML
21
+ rng_xml = File.read('schema.rng')
22
+ grammar = Rng.parse(rng_xml)
23
+
24
+ # Convert to RNC
25
+ rnc_output = Rng.to_rnc(grammar)
26
+
27
+ puts rnc_output
28
+ ----
29
+
30
+ == RNC to RNG Conversion
31
+
32
+ Convert RNC compact syntax to RNG XML:
33
+
34
+ [source,ruby]
35
+ ----
36
+ require 'rng'
37
+
38
+ # Parse RNC
39
+ rnc_text = File.read('schema.rnc')
40
+ grammar = Rng.parse_rnc(rnc_text)
41
+
42
+ # Convert to RNG XML
43
+ rng_xml = grammar.to_xml
44
+
45
+ puts rng_xml
46
+ ----
47
+
48
+ == Using the CLI
49
+
50
+ The gem includes a CLI for quick conversions:
51
+
52
+ [source,bash]
53
+ ----
54
+ # RNG to RNC
55
+ rng convert schema.rng -O rnc -o schema_converted.rnc
56
+
57
+ # RNC to RNG
58
+ rng convert schema.rnc -O rng -o schema_converted.rng
59
+ ----
60
+
61
+ == Round-Trip Conversion
62
+
63
+ The gem is designed to produce correct output that can be re-parsed:
64
+
65
+ [source,ruby]
66
+ ----
67
+ # Parse RNC
68
+ grammar1 = Rng.parse_rnc(rnc_text)
69
+
70
+ # Convert to RNG and back to RNC
71
+ rng_xml = grammar1.to_xml
72
+ grammar2 = Rng.parse(rng_xml)
73
+ rnc_output = Rng.to_rnc(grammar2)
74
+
75
+ # Both grammars should be equivalent
76
+ ----
77
+
78
+ == Limitations
79
+
80
+ 1. **Whitespace handling**: Whitespace in RNC is normalized during parsing
81
+ 2. **Comments**: RNC comments are not preserved in RNG XML output
82
+ 3. **Foreign elements**: Elements from non-RNG namespaces are dropped
83
+ 4. **Name classes**: Complex name classes may serialize differently but remain semantically equivalent
84
+
85
+ == Format Selection
86
+
87
+ The conversion direction is inferred from the input format:
88
+
89
+ | Input Format | Output Format |
90
+ |--------------|---------------|
91
+ | `.rnc` file | RNG XML |
92
+ | `.rng` file | RNC |
93
+ | Unknown | RNG XML |
94
+
95
+ Use explicit format flags when the inference is incorrect:
96
+
97
+ [source,bash]
98
+ ----
99
+ rng convert input.rnc output.rng -O rng
100
+ rng convert input.rng output.rnc -O rnc
101
+ ----
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Schema Validation
3
+ layout: default
4
+ nav_order: 4
5
+ parent: Guides
6
+ ---
7
+
8
+ = Schema Validation
9
+
10
+ The RNG gem provides structural validation of RNG schemas.
11
+
12
+ == Validating a Schema
13
+
14
+ Validate that an RNG schema is well-formed and follows RELAX NG rules:
15
+
16
+ [source,ruby]
17
+ ----
18
+ require 'rng'
19
+
20
+ begin
21
+ Rng::SchemaValidator.validate(rng_xml)
22
+ puts "Schema is valid"
23
+ rescue Rng::SchemaValidationError => e
24
+ puts "Schema validation error: #{e.message}"
25
+ end
26
+ ----
27
+
28
+ == Validation During Parsing
29
+
30
+ You can also validate during parsing with the `validate:` option:
31
+
32
+ [source,ruby]
33
+ ----
34
+ grammar = Rng.parse(rng_xml, validate: true)
35
+ ----
36
+
37
+ This is equivalent to:
38
+
39
+ [source,ruby]
40
+ ----
41
+ Rng::SchemaValidator.validate(rng_xml)
42
+ grammar = Rng.parse(rng_xml)
43
+ ----
44
+
45
+ == Schema Validation Errors
46
+
47
+ When validation fails, a `Rng::SchemaValidationError` is raised:
48
+
49
+ [source,ruby]
50
+ ----
51
+ begin
52
+ Rng::SchemaValidator.validate(invalid_rng_xml)
53
+ rescue Rng::SchemaValidationError => e
54
+ puts e.message
55
+ puts e.errors if e.respond_to?(:errors)
56
+ end
57
+ ----
58
+
59
+ == What Gets Validated
60
+
61
+ The SchemaValidator checks:
62
+
63
+ 1. **Grammar structure**: Start element, proper define elements
64
+ 2. **Pattern validity**: Elements properly nested, correct attributes
65
+ 3. **Name class validity**: NCName, QName, nsName proper usage
66
+ 4. **Datatype Library**: Correct datatype library references
67
+ 5. **Reference integrity**: Refs point to defined patterns
68
+
69
+ == Limitations
70
+
71
+ Schema validation does NOT:
72
+
73
+ - Validate XML documents against the schema (use a validator like Jing for that)
74
+ - Check semantic equivalence of patterns
75
+ - Validate external references (those require I/O)
76
+
77
+ == Schema Structure Validation
78
+
79
+ The gem validates the schema structure when parsing with `validate: true`:
80
+
81
+ [source,ruby]
82
+ ----
83
+ # This will raise if the schema is invalid
84
+ grammar = Rng.parse(File.read('invalid_schema.rng'), validate: true)
85
+ ----
data/docs/index.adoc ADDED
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: RNG Ruby Gem
3
+ nav_order: 1
4
+ ---
5
+
6
+ # RNG Ruby Gem
7
+
8
+ A Ruby gem for parsing, manipulating, and converting RELAX NG schemas (both RNG XML and RNC compact syntax).
9
+
10
+ ## Features
11
+
12
+ - Parse RNG XML format
13
+ - Parse RNC compact syntax
14
+ - Convert between RNG and RNC formats
15
+ - Validate RNG schemas
16
+ - Resolve external references (`<include>` and `<externalRef>`)
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ gem install rng
22
+ ```
23
+
24
+ Or add to your Gemfile:
25
+
26
+ ```ruby
27
+ gem 'rng'
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```ruby
33
+ require 'rng'
34
+
35
+ # Parse RNG XML
36
+ rng_xml = File.read('schema.rng')
37
+ grammar = Rng.parse(rng_xml)
38
+
39
+ # Parse RNC compact syntax
40
+ rnc_text = File.read('schema.rnc')
41
+ grammar = Rng.parse_rnc(rnc_text)
42
+
43
+ # Convert RNG to RNC
44
+ rnc_output = Rng.to_rnc(grammar)
45
+
46
+ # Resolve external references
47
+ grammar = Rng.parse(rng_xml, location: '/path/to/schema.rng', resolve_external: true)
48
+ ```
49
+
50
+ ## Status
51
+
52
+ This gem is under active development. The core parsing functionality is complete and well-tested against the Jing-Trang test suite.
@@ -0,0 +1,126 @@
1
+ ---
2
+ title: API Reference
3
+ layout: default
4
+ nav_order: 5
5
+ has_children: true
6
+ ---
7
+
8
+ = API Reference
9
+
10
+ Complete API documentation for the RNG gem.
11
+
12
+ == Main Module: `Rng`
13
+
14
+ === `Rng.parse`
15
+
16
+ Parse RNG XML format.
17
+
18
+ [source,ruby]
19
+ ----
20
+ Rng.parse(rng_xml, location: nil, nested_schema: false, validate: false, resolve_external: false)
21
+ ----
22
+
23
+ **Parameters:**
24
+
25
+ - `rng_xml` (String) - The RNG XML content
26
+ - `location` (String, optional) - File location for resolving relative external refs
27
+ - `nested_schema` (Boolean, default: false) - Whether this is a nested schema
28
+ - `validate` (Boolean, default: false) - Whether to validate the schema
29
+ - `resolve_external` (Boolean, default: false) - Whether to resolve external refs
30
+
31
+ **Returns:** `Rng::Grammar`
32
+
33
+ === `Rng.parse_rnc`
34
+
35
+ Parse RNC compact syntax.
36
+
37
+ [source,ruby]
38
+ ----
39
+ Rng.parse_rnc(rnc_text, location: nil)
40
+ ----
41
+
42
+ **Parameters:**
43
+
44
+ - `rnc_text` (String) - The RNC compact syntax content
45
+ - `location` (String, optional) - File location for include resolution
46
+
47
+ **Returns:** `Rng::Grammar`
48
+
49
+ === `Rng.to_rnc`
50
+
51
+ Convert a Grammar to RNC compact syntax.
52
+
53
+ [source,ruby]
54
+ ----
55
+ Rng.to_rnc(grammar)
56
+ ----
57
+
58
+ **Parameters:**
59
+
60
+ - `grammar` (Rng::Grammar) - The grammar to convert
61
+
62
+ **Returns:** String (RNC text)
63
+
64
+ === `Rng::Grammar.from_xml`
65
+
66
+ Create a Grammar from XML.
67
+
68
+ [source,ruby]
69
+ ----
70
+ Rng::Grammar.from_xml(xml_string)
71
+ ----
72
+
73
+ === `Rng::SchemaValidator.validate`
74
+
75
+ Validate an RNG schema.
76
+
77
+ [source,ruby]
78
+ ----
79
+ Rng::SchemaValidator.validate(rng_xml)
80
+ ----
81
+
82
+ **Raises:** `Rng::SchemaValidationError` if invalid
83
+
84
+ == Grammar Object Model
85
+
86
+ The gem uses Lutaml::Model for the object model. All classes inherit from `Lutaml::Model::Serializable`.
87
+
88
+ === Core Classes
89
+
90
+ - `Rng::Grammar` - Root container
91
+ - `Rng::Start` - Entry point definition
92
+ - `Rng::Define` - Named pattern definitions
93
+ - `Rng::Element` - XML element patterns
94
+ - `Rng::Attribute` - XML attribute patterns
95
+ - `Rng::Group`, `Rng::Choice`, `Rng::Interleave` - Compositors
96
+ - `Rng::Optional`, `Rng::ZeroOrMore`, `Rng::OneOrMore` - Occurrence indicators
97
+ - `Rng::Ref`, `Rng::ParentRef`, `Rng::ExternalRef` - References
98
+ - `Rng::Text`, `Rng::Empty`, `Rng::NotAllowed` - Basic patterns
99
+ - `Rng::Value`, `Rng::Data`, `Rng::List` - Data patterns
100
+
101
+ === Common Methods
102
+
103
+ All pattern objects support:
104
+
105
+ - `.to_xml` - Convert to XML string
106
+ - `.to_h` - Convert to hash representation
107
+
108
+ == Error Classes
109
+
110
+ === `Rng::Error`
111
+
112
+ Base error class.
113
+
114
+ === `Rng::SchemaValidationError`
115
+
116
+ Raised when schema validation fails.
117
+
118
+ === `Rng::ExternalRefResolver::ExternalRefResolutionError`
119
+
120
+ Raised when external reference resolution fails.
121
+
122
+ [source,ruby]
123
+ ----
124
+ error.href # => The href that failed
125
+ error.cause # => :circular, Errno::ENOENT, or nil
126
+ ----
@@ -0,0 +1,182 @@
1
+ ---
2
+ title: CLI Reference
3
+ layout: default
4
+ nav_order: 2
5
+ parent: Reference
6
+ ---
7
+
8
+ = CLI Reference
9
+
10
+ The RNG gem includes a command-line interface for common tasks.
11
+
12
+ == Installation
13
+
14
+ The CLI is automatically installed with the gem:
15
+
16
+ [source,bash]
17
+ ----
18
+ gem install rng
19
+ rng --version
20
+ ----
21
+
22
+ == Global Options
23
+
24
+ [source,bash]
25
+ ----
26
+ -v, --verbose # Verbose output
27
+ -q, --quiet # Suppress non-error output
28
+ -h, --help # Show help
29
+ --version # Show version number
30
+ ----
31
+
32
+ == Commands
33
+
34
+ === validate
35
+
36
+ Validate an XML document against a RELAX NG schema (replaces Jing).
37
+
38
+ [source,bash]
39
+ ----
40
+ rng validate SCHEMA [DOCUMENT]
41
+ ----
42
+
43
+ **Options:**
44
+
45
+ - `-c, --compact` - Schema is in RNC compact format
46
+ - `-x, --xml` - Schema is in RNG XML format (default: auto-detect)
47
+ - `-o, --output FORMAT` - Output format: text, xml, json
48
+
49
+ **Examples:**
50
+
51
+ [source,bash]
52
+ ----
53
+ # Validate a schema
54
+ rng validate schema.rng
55
+
56
+ # Validate an XML document
57
+ rng validate schema.rng document.xml
58
+
59
+ # Validate with RNC schema
60
+ rng validate -c schema.rnc document.xml
61
+ ----
62
+
63
+ === convert
64
+
65
+ Convert between RNC and RNG formats (replaces Trang).
66
+
67
+ [source,bash]
68
+ ----
69
+ rng convert INPUT [OUTPUT]
70
+ ----
71
+
72
+ **Options:**
73
+
74
+ - `-I, --input-format FORMAT` - Input format: rng, rnc, auto
75
+ - `-O, --output-format FORMAT` - Output format: rng, rnc, auto
76
+
77
+ **Examples:**
78
+
79
+ [source,bash]
80
+ ----
81
+ # RNC to RNG
82
+ rng convert schema.rnc -o schema.rng
83
+
84
+ # RNG to RNC
85
+ rng convert schema.rng schema_converted.rnc
86
+ ----
87
+
88
+ === parse
89
+
90
+ Parse a schema and display its structure.
91
+
92
+ [source,bash]
93
+ ----
94
+ rng parse SCHEMA
95
+ ----
96
+
97
+ **Options:**
98
+
99
+ - `-f, --format FORMAT` - Output format: text, json, yaml, xml
100
+ - `--ast` - Show abstract syntax tree (RNC only)
101
+
102
+ **Examples:**
103
+
104
+ [source,bash]
105
+ ----
106
+ # Text output (default)
107
+ rng parse schema.rng
108
+
109
+ # JSON output
110
+ rng parse -f json schema.rng
111
+ ----
112
+
113
+ === info
114
+
115
+ Show information about a schema.
116
+
117
+ [source,bash]
118
+ ----
119
+ rng info SCHEMA
120
+ ----
121
+
122
+ **Options:**
123
+
124
+ - `--statistics` - Show pattern statistics
125
+ - `--namespaces` - List used namespaces
126
+
127
+ **Examples:**
128
+
129
+ [source,bash]
130
+ ----
131
+ # Basic info
132
+ rng info schema.rng
133
+
134
+ # With statistics
135
+ rng info --statistics schema.rng
136
+ ----
137
+
138
+ === version
139
+
140
+ Show version number.
141
+
142
+ [source,bash]
143
+ ----
144
+ rng version
145
+ ----
146
+
147
+ == Exit Codes
148
+
149
+ - `0` - Success
150
+ - `1` - Invalid input or validation failure
151
+ - `2` - Error (file not found, parse error, etc.)
152
+
153
+ == Examples
154
+
155
+ === Validate a document
156
+
157
+ [source,bash]
158
+ ----
159
+ $ rng validate spec/fixtures/rng/xhtml.rng spec/fixtures/xhtml/sample.xml
160
+ Validating spec/fixtures/rng/xhtml.rng against spec/fixtures/xhtml/sample.xml...
161
+ Document is valid
162
+ ----
163
+
164
+ === Convert a schema
165
+
166
+ [source,bash]
167
+ ----
168
+ $ rng convert spec/fixtures/rng/address_book.rng -o /tmp/address_book.rnc
169
+ Converting spec/fixtures/rng/address_book.rng (rng) to rnc...
170
+ Written to /tmp/address_book.rnc
171
+ ----
172
+
173
+ === Inspect a schema
174
+
175
+ [source,bash]
176
+ ----
177
+ $ rng parse spec/fixtures/rng/address_book.rng
178
+ Schema Structure:
179
+ Start: Start
180
+ Definitions:
181
+ cardContent: element
182
+ ----
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Architecture
3
+ layout: default
4
+ nav_order: 3
5
+ parent: Understanding
6
+ ---
7
+
8
+ = Architecture
9
+
10
+ The RNG gem has two parsing paths and one generation path.
11
+
12
+ == RNG XML Parsing
13
+
14
+ [source]
15
+ ----
16
+ Rng.parse() → Grammar.from_xml() → Lutaml::Model with Nokogiri adapter
17
+ ----
18
+
19
+ All RNG model classes inherit from `Lutaml::Model::Serializable` and define XML mappings via the `xml do` block.
20
+
21
+ == RNC Compact Parsing
22
+
23
+ [source]
24
+ ----
25
+ Rng.parse_rnc() → RncParser.parse() → ParseTreeProcessor.normalize()
26
+ → RncToRngConverter.convert() → Grammar.from_xml()
27
+ ----
28
+
29
+ The RNC parser is a Parslet-based PEG parser in `lib/rng/rnc_parser.rb`.
30
+
31
+ == RNG to RNC Generation
32
+
33
+ [source]
34
+ ----
35
+ Rng.to_rnc() → ToRnc.convert() → RncBuilder.build()
36
+ ----
37
+
38
+ `RncBuilder` traverses the object model and generates RNC text.
39
+
40
+ == Object Model Structure
41
+
42
+ The object model mirrors RELAX NG concepts:
43
+
44
+ - `Grammar` - Root container
45
+ - `Start` - Entry point definition
46
+ - `Define` - Named pattern definitions
47
+ - `Element`, `Attribute` - XML structures
48
+ - Pattern classes: `Choice`, `Group`, `Interleave`, `Mixed`, `Optional`, `ZeroOrMore`, `OneOrMore`, `Text`, `Empty`, `Value`, `Data`, `List`
49
+ - Reference classes: `Ref`, `ParentRef`, `ExternalRef`
50
+ - Name classes: `Name`, `AnyName`, `NsName`, `Except`
51
+ - `Div` - Documentation and grouping container
52
+
53
+ == Dependencies
54
+
55
+ - **lutaml-model** - Object model and XML serialization
56
+ - **nokogiri** - XML parsing and building
57
+ - **parslet** - RNC compact syntax parser
58
+ - **canon** - XML comparison matchers for tests
@@ -0,0 +1,118 @@
1
+ ---
2
+ title: RNG vs RNC
3
+ layout: default
4
+ nav_order: 1
5
+ parent: Understanding
6
+ ---
7
+
8
+ = RNG vs RNC
9
+
10
+ RELAX NG schemas can be written in two formats: XML (RNG) and Compact (RNC).
11
+
12
+ == RNG XML Format
13
+
14
+ RNG is the XML-based representation of RELAX NG schemas.
15
+
16
+ === Example
17
+
18
+ [source,xml]
19
+ ----
20
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
21
+ <start>
22
+ <element name="person">
23
+ <zeroOrMore>
24
+ <element name="child">
25
+ <empty/>
26
+ </element>
27
+ </zeroOrMore>
28
+ </element>
29
+ </start>
30
+ </grammar>
31
+ ----
32
+
33
+ === Advantages
34
+
35
+ - **Standard XML tools**: Can be edited with any XML editor
36
+ - **Explicit structure**: All elements and attributes are visible
37
+ - **Namespaces**: Full namespace support is natural
38
+ - **Transformation**: Can be processed with XSLT
39
+ - **Validation**: Can be validated with XML schemas
40
+
41
+ === Disadvantages
42
+
43
+ - **Verbose**: More characters to type
44
+ - **Less readable**: Harder to scan quickly
45
+ - **XML overhead**: Requires proper escaping
46
+
47
+ == RNC Compact Syntax
48
+
49
+ RNC is a text-based shorthand for RELAX NG schemas.
50
+
51
+ === Example
52
+
53
+ [source,rnc]
54
+ ----
55
+ element person {
56
+ element child {
57
+ empty
58
+ }*
59
+ }
60
+ ----
61
+
62
+ === Advantages
63
+
64
+ - **Concise**: Much shorter than equivalent XML
65
+ - **Readable**: Easier to see the structure at a glance
66
+ - **Programming-like**: Familiar syntax for developers
67
+ - **Quick prototyping**: Faster to write and modify
68
+
69
+ === Disadvantages
70
+
71
+ - **No native tools**: Requires conversion for XML tools
72
+ - **Escaping**: Special characters need escaping
73
+ - **Limited namespace support**: More complex namespace handling
74
+
75
+ == When to Use Each
76
+
77
+ === Use RNG when:
78
+
79
+ - You need to validate the schema itself with XML tools
80
+ - You're integrating with XML processing pipelines
81
+ - Namespace handling is critical
82
+ - You need to embed schema documentation in foreign elements
83
+ - You're working with teams more familiar with XML
84
+
85
+ === Use RNC when:
86
+
87
+ - You want a quick prototype
88
+ - The schema is primarily for Ruby processing
89
+ - Readability is more important than tool compatibility
90
+ - You're writing tests or examples
91
+
92
+ == Conversion
93
+
94
+ Both formats are fully equivalent - you can convert between them without loss:
95
+
96
+ [source,ruby]
97
+ ----
98
+ # RNG to RNC
99
+ grammar = Rng.parse(rng_xml)
100
+ rnc = Rng.to_rnc(grammar)
101
+
102
+ # RNC to RNG
103
+ grammar = Rng.parse_rnc(rnc_text)
104
+ rng_xml = grammar.to_xml
105
+ ----
106
+
107
+ == Quick Reference
108
+
109
+ | Feature | RNG | RNC |
110
+ |---------|-----|-----|
111
+ | Element | `<element name="foo">...</element>` | `element foo { ... }` |
112
+ | Attribute | `<attribute name="bar">...</attribute>` | `attribute bar { ... }` |
113
+ | Optional | `<optional>...</optional>` | `... ?` |
114
+ | Zero or more | `<zeroOrMore>...</zeroOrMore>` | `... *` |
115
+ | One or more | `<oneOrMore>...</oneOrMore>` | `... +` |
116
+ | Choice | `<choice>...</choice>` | `... \| ...` |
117
+ | Sequence | `<group>...</group>` | `..., ...` |
118
+ | Interleave | `<interleave>...</interleave>` | `... & ...` |