rng 0.1.2 → 0.3.3

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 +582 -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 +7 -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 +8 -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
data/Rakefile CHANGED
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
12
  task default: %i[spec rubocop]
13
+
14
+ # Extract external test fixtures from Jing-Trang spectest.xml
15
+ namespace :fixtures do
16
+ desc "Extract external test resources from Jing-Trang's spectest.xml"
17
+ task :extract_spectest do
18
+ system('ruby scripts/extract_spectest_resources.rb')
19
+ end
20
+ end
data/docs/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'bundler', '>= 2.0'
6
+ gem 'jekyll', '~> 4.3'
7
+ gem 'jekyll-asciidoc', '~> 3.0'
8
+ gem 'just-the-docs', '~> 0.8'
data/docs/_config.yml ADDED
@@ -0,0 +1,23 @@
1
+ title: RNG Ruby Gem
2
+ description: A Ruby gem for parsing, manipulating, and converting RELAX NG schemas
3
+ theme: just-the-docs
4
+
5
+ plugins:
6
+ - jekyll-asciidoc
7
+
8
+ asciidoc:
9
+ ext: .adoc
10
+ safe: unsafe
11
+
12
+ collections:
13
+ guides:
14
+ output: true
15
+ reference:
16
+ output: true
17
+ getting-started:
18
+ output: true
19
+
20
+ nav_sections:
21
+ getting-started: Getting Started
22
+ guides: Guides
23
+ reference: Reference
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: Getting Started
3
+ layout: default
4
+ nav_order: 2
5
+ has_children: true
6
+ ---
7
+
8
+ # Getting Started
9
+
10
+ Learn how to install and use the RNG gem.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ gem install rng
16
+ ```
17
+
18
+ Or add to your Gemfile:
19
+
20
+ ```ruby
21
+ gem 'rng'
22
+ ```
23
+
24
+ ## Basic Usage
25
+
26
+ ### Parsing RNG XML
27
+
28
+ ```ruby
29
+ require 'rng'
30
+
31
+ # Parse from string
32
+ rng_xml = <<~XML
33
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
34
+ <start>
35
+ <element name="foo">
36
+ <empty/>
37
+ </element>
38
+ </start>
39
+ </grammar>
40
+ XML
41
+
42
+ grammar = Rng.parse(rng_xml)
43
+ ```
44
+
45
+ ### Parsing RNC Compact Syntax
46
+
47
+ ```ruby
48
+ require 'rng'
49
+
50
+ rnc_text = <<~RNC
51
+ element foo { empty }
52
+ RNC
53
+
54
+ grammar = Rng.parse_rnc(rnc_text)
55
+ ```
56
+
57
+ ### Converting Between Formats
58
+
59
+ ```ruby
60
+ # RNG XML to RNC
61
+ rng_xml = File.read('schema.rng')
62
+ grammar = Rng.parse(rng_xml)
63
+ rnc_output = Rng.to_rnc(grammar)
64
+
65
+ # RNC to RNG XML
66
+ rnc_text = File.read('schema.rnc')
67
+ grammar = Rng.parse_rnc(rnc_text)
68
+ rng_xml = grammar.to_xml
69
+ ```
70
+
71
+ ## Next Steps
72
+
73
+ - Read the xref:guides/parsing-rng-xml.adoc[Parsing RNG XML] guide
74
+ - Read the xref:guides/parsing-rnc.adoc[Parsing RNC] guide
75
+ - Learn about xref:guides/external-references.adoc[External References]
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: Error Handling
3
+ layout: default
4
+ nav_order: 5
5
+ parent: Guides
6
+ ---
7
+
8
+ = Error Handling
9
+
10
+ The RNG gem provides specific error classes for different failure scenarios.
11
+
12
+ == Error Classes
13
+
14
+ === `Rng::Error`
15
+
16
+ Base error class for all RNG gem errors.
17
+
18
+ [source,ruby]
19
+ ----
20
+ begin
21
+ # ... RNG operations
22
+ rescue Rng::Error => e
23
+ puts "RNG error: #{e.message}"
24
+ end
25
+ ----
26
+
27
+ === `Rng::SchemaValidationError`
28
+
29
+ Raised when schema validation fails.
30
+
31
+ [source,ruby]
32
+ ----
33
+ begin
34
+ Rng::SchemaValidator.validate(invalid_rng)
35
+ rescue Rng::SchemaValidationError => e
36
+ puts "Validation failed: #{e.message}"
37
+ end
38
+ ----
39
+
40
+ === `Rng::ExternalRefResolver::ExternalRefResolutionError`
41
+
42
+ Raised when external reference resolution fails.
43
+
44
+ [source,ruby]
45
+ ----
46
+ begin
47
+ grammar = Rng.parse(rng_xml, location: path, resolve_external: true)
48
+ rescue Rng::ExternalRefResolver::ExternalRefResolutionError => e
49
+ puts "Failed to resolve: #{e.href}"
50
+ puts "Cause: #{e.cause}"
51
+ end
52
+ ----
53
+
54
+ **Error attributes:**
55
+
56
+ - `href` - The URI that failed to resolve
57
+ - `cause` - The underlying error (`:circular`, `Errno::ENOENT`, or nil)
58
+
59
+ == Common Error Scenarios
60
+
61
+ === File Not Found
62
+
63
+ [source,ruby]
64
+ ----
65
+ begin
66
+ grammar = Rng.parse(rng_xml, location: '/nonexistent/path.rng', resolve_external: true)
67
+ rescue Rng::ExternalRefResolver::ExternalRefResolutionError => e
68
+ if e.cause == Errno::ENOENT
69
+ puts "External file not found: #{e.href}"
70
+ end
71
+ end
72
+ ----
73
+
74
+ === Circular References
75
+
76
+ [source,ruby]
77
+ ----
78
+ begin
79
+ grammar = Rng.parse(circular_rng_xml, location: path, resolve_external: true)
80
+ rescue Rng::ExternalRefResolver::ExternalRefResolutionError => e
81
+ if e.cause == :circular
82
+ puts "Circular reference detected at: #{e.href}"
83
+ end
84
+ end
85
+ ----
86
+
87
+ === Invalid Schema Structure
88
+
89
+ [source,ruby]
90
+ ----
91
+ begin
92
+ grammar = Rng.parse(invalid_rng, validate: true)
93
+ rescue Rng::SchemaValidationError => e
94
+ puts "Schema is invalid: #{e.message}"
95
+ end
96
+ ----
97
+
98
+ === RNC Parse Errors
99
+
100
+ [source,ruby]
101
+ ----
102
+ begin
103
+ grammar = Rng.parse_rnc(invalid_rnc)
104
+ rescue Parslet::ParseFailed => e
105
+ puts "RNC parse error: #{e.message}"
106
+ end
107
+ ----
108
+
109
+ == Handling Multiple Error Types
110
+
111
+ [source,ruby]
112
+ ----
113
+ begin
114
+ grammar = Rng.parse(rng_xml, validate: true, resolve_external: true)
115
+ rescue Rng::SchemaValidationError => e
116
+ puts "Schema validation error: #{e.message}"
117
+ rescue Rng::ExternalRefResolver::ExternalRefResolutionError => e
118
+ puts "External reference error: #{e.href}"
119
+ rescue StandardError => e
120
+ puts "Unexpected error: #{e.class}: #{e.message}"
121
+ end
122
+ ----
123
+
124
+ == Verbose Mode
125
+
126
+ Enable verbose logging for debugging:
127
+
128
+ [source,bash]
129
+ ----
130
+ RNG_VERBOSE=1 bundle exec ruby -e '
131
+ grammar = Rng.parse(File.read("schema.rng"), resolve_external: true)
132
+ '
133
+ ----
134
+
135
+ This outputs warnings for:
136
+ - Unresolvable external references
137
+ - Parsing issues
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: External References
3
+ layout: default
4
+ nav_order: 4
5
+ parent: Guides
6
+ ---
7
+
8
+ = External References
9
+
10
+ The RNG format supports two types of external references that the gem can resolve.
11
+
12
+ == Include Directive (`<include>`)
13
+
14
+ The `<include>` directive at the grammar level merges definitions from an external grammar file.
15
+
16
+ === Example
17
+
18
+ `main.rng`:
19
+ [source,xml]
20
+ ----
21
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
22
+ <include href="library.rng"/>
23
+ <start>
24
+ <ref name="main-element"/>
25
+ </start>
26
+ </grammar>
27
+ ----
28
+
29
+ `library.rng`:
30
+ [source,xml]
31
+ ----
32
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
33
+ <define name="main-element">
34
+ <element name="foo">
35
+ <empty/>
36
+ </element>
37
+ </define>
38
+ </grammar>
39
+ ----
40
+
41
+ === Resolution
42
+
43
+ [source,ruby]
44
+ ----
45
+ grammar = Rng.parse(
46
+ File.read('main.rng'),
47
+ location: '/path/to/main.rng',
48
+ resolve_external: true
49
+ )
50
+ ----
51
+
52
+ After resolution, the `define` from `library.rng` is merged into `main.rng`.
53
+
54
+ == ExternalRef (`<externalRef>`)
55
+
56
+ The `<externalRef>` directive at the pattern level replaces itself with content from an external grammar's start pattern.
57
+
58
+ === Example
59
+
60
+ `main.rng`:
61
+ [source,xml]
62
+ ----
63
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
64
+ <start>
65
+ <group>
66
+ <externalRef href="external.rng"/>
67
+ </group>
68
+ </start>
69
+ </grammar>
70
+ ----
71
+
72
+ `external.rng`:
73
+ [source,xml]
74
+ ----
75
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
76
+ <start>
77
+ <element name="bar">
78
+ <empty/>
79
+ </element>
80
+ </start>
81
+ </grammar>
82
+ ----
83
+
84
+ === Resolution
85
+
86
+ The `<externalRef>` is replaced with the content from `external.rng`'s start pattern:
87
+
88
+ [source,xml]
89
+ ----
90
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
91
+ <start>
92
+ <group>
93
+ <element name="bar">
94
+ <empty/>
95
+ </element>
96
+ </group>
97
+ </start>
98
+ </grammar>
99
+ ----
100
+
101
+ == Circular Reference Detection
102
+
103
+ The resolver detects circular references and raises an error:
104
+
105
+ [source,ruby]
106
+ ----
107
+ begin
108
+ grammar = Rng.parse(
109
+ File.read('circular.rng'),
110
+ location: '/path/to/circular.rng',
111
+ resolve_external: true
112
+ )
113
+ rescue Rng::ExternalRefResolver::ExternalRefResolutionError => e
114
+ puts "Circular reference detected: #{e.href}"
115
+ end
116
+ ----
117
+
118
+ == Error Handling
119
+
120
+ When external files cannot be found, the resolver issues a warning (when `RNG_VERBOSE=1`) and continues:
121
+
122
+ [source,bash]
123
+ ----
124
+ RNG_VERBOSE=1 bundle exec ruby -e '
125
+ grammar = Rng.parse(File.read("main.rng"), location: "/path", resolve_external: true)
126
+ '
127
+ # => Warning: Failed to resolve include "nonexistent.rng": External file not found: nonexistent.rng
128
+ ----
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: Guides
3
+ layout: default
4
+ nav_order: 3
5
+ has_children: true
6
+ ---
7
+
8
+ = Guides
9
+
10
+ Step-by-step guides for common tasks with the RNG gem.
11
+
12
+ == Available Guides
13
+
14
+ * xref:parsing-rng-xml.adoc[Parsing RNG XML] - Parse and work with RNG XML format
15
+
16
+ * xref:parsing-rnc.adoc[Parsing RNC] - Parse and work with RNC compact syntax
17
+
18
+ * xref:rng-to-rnc.adoc[Converting Formats] - Convert between RNG and RNC formats
19
+
20
+ * xref:validation.adoc[Schema Validation] - Validate RNG schemas
21
+
22
+ * xref:external-references.adoc[External References] - Resolve include and externalRef directives
23
+
24
+ * xref:error-handling.adoc[Error Handling] - Handle errors gracefully
@@ -0,0 +1,141 @@
1
+ ---
2
+ title: Parsing RNC Compact Syntax
3
+ layout: default
4
+ nav_order: 2
5
+ parent: Guides
6
+ ---
7
+
8
+ = Parsing RNC Compact Syntax
9
+
10
+ The RNG gem can parse RELAX NG schemas in compact syntax (RNC).
11
+
12
+ == Basic Parsing
13
+
14
+ [source,ruby]
15
+ ----
16
+ require 'rng'
17
+
18
+ rnc_text = <<~RNC
19
+ element foo {
20
+ element bar {
21
+ empty
22
+ }
23
+ }
24
+ RNC
25
+
26
+ grammar = Rng.parse_rnc(rnc_text)
27
+ ----
28
+
29
+ == RNC Syntax Basics
30
+
31
+ RNC is a more concise text representation of RELAX NG schemas.
32
+
33
+ === Elements
34
+
35
+ [source,rnc]
36
+ ----
37
+ element name { content }
38
+ ----
39
+
40
+ === Attributes
41
+
42
+ [source,rnc]
43
+ ----
44
+ attribute name { type }
45
+ ----
46
+
47
+ === Sequences and Choices
48
+
49
+ [source,rnc]
50
+ ----
51
+ # Sequence (both required)
52
+ element a {}, element b {}
53
+
54
+ # Choice (one of)
55
+ element a {} | element b {}
56
+
57
+ # Grouping with parentheses
58
+ (element a {} | element b {}), element c {}
59
+ ----
60
+
61
+ === Occurrence Indicators
62
+
63
+ [source,rnc]
64
+ ----
65
+ # Optional (0 or 1)
66
+ element foo?
67
+
68
+ # Zero or more
69
+ element foo*
70
+
71
+ # One or more
72
+ element foo+
73
+ ----
74
+
75
+ === Named Definitions
76
+
77
+ [source,rnc]
78
+ ----
79
+ # Define a named pattern
80
+ patternName = element foo { empty }
81
+
82
+ # Reference a named pattern
83
+ element bar {
84
+ patternName
85
+ }
86
+ ----
87
+
88
+ === Combining Patterns
89
+
90
+ [source,rnc]
91
+ ----
92
+ # Interleave (interleave is the default for elements)
93
+ element foo { element a {} & element b {} }
94
+
95
+ # Mixed content
96
+ mixed { element p {} | text }
97
+ ----
98
+
99
+ == Working with Parse Results
100
+
101
+ The parsed grammar provides access to all definitions:
102
+
103
+ [source,ruby]
104
+ ----
105
+ grammar = Rng.parse_rnc(rnc_text)
106
+
107
+ # Access start pattern
108
+ grammar.start.each do |start_pattern|
109
+ puts start_pattern.to_xml
110
+ end
111
+
112
+ # Access named definitions
113
+ grammar.define.each do |define|
114
+ puts "#{define.name}: #{define.element.map(&:attr_name).join(', ')}"
115
+ end
116
+ ----
117
+
118
+ == Converting RNC to RNG
119
+
120
+ [source,ruby]
121
+ ----
122
+ # Parse RNC and convert to RNG XML
123
+ grammar = Rng.parse_rnc(rnc_text)
124
+ rng_xml = grammar.to_xml
125
+
126
+ puts rng_xml
127
+ ----
128
+
129
+ == Using with External References
130
+
131
+ When your RNC file uses `include` directives:
132
+
133
+ [source,ruby]
134
+ ----
135
+ grammar = Rng.parse_rnc(
136
+ File.read('schema.rnc'),
137
+ location: '/path/to/schema.rnc'
138
+ )
139
+ ----
140
+
141
+ Note: RNC include resolution is built into the RNC parser itself.
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Parsing RNG XML
3
+ layout: default
4
+ nav_order: 3
5
+ parent: Getting Started
6
+ ---
7
+
8
+ = Parsing RNG XML
9
+
10
+ The RNG gem can parse RELAX NG schemas in XML format.
11
+
12
+ == Basic Parsing
13
+
14
+ [source,ruby]
15
+ ----
16
+ require 'rng'
17
+
18
+ rng_xml = <<~XML
19
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0">
20
+ <start>
21
+ <element name="foo">
22
+ <empty/>
23
+ </element>
24
+ </start>
25
+ </grammar>
26
+ XML
27
+
28
+ grammar = Rng.parse(rng_xml)
29
+ ----
30
+
31
+ == With Location
32
+
33
+ When your RNG file references external resources (via `<include>` or `<externalRef>`), provide the file location for proper relative path resolution:
34
+
35
+ [source,ruby]
36
+ ----
37
+ grammar = Rng.parse(
38
+ File.read('schema.rng'),
39
+ location: '/path/to/schema.rng'
40
+ )
41
+ ----
42
+
43
+ == Resolving External References
44
+
45
+ By default, external references are NOT resolved. To resolve them:
46
+
47
+ [source,ruby]
48
+ ----
49
+ grammar = Rng.parse(
50
+ File.read('schema.rng'),
51
+ location: '/path/to/schema.rng',
52
+ resolve_external: true
53
+ )
54
+ ----
55
+
56
+ This will:
57
+
58
+ - Process `<include href="..."/>` at the grammar level - merges definitions from external grammars
59
+ - Process `<externalRef href="..."/>` at the pattern level - replaces with content from external grammars
60
+
61
+ == Accessing Grammar Elements
62
+
63
+ The parsed grammar provides access to all elements:
64
+
65
+ [source,ruby]
66
+ ----
67
+ grammar.start # => Array of Start patterns
68
+ grammar.define # => Array of Define patterns
69
+ grammar.element # => Array of top-level Element patterns
70
+ grammar.include # => Array of Include directives
71
+ grammar.div # => Array of Div elements
72
+ ----
73
+
74
+ == Generating XML Output
75
+
76
+ Convert the grammar back to XML:
77
+
78
+ [source,ruby]
79
+ ----
80
+ puts grammar.to_xml
81
+ ----