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.
- checksums.yaml +4 -4
- data/.github/workflows/docs.yml +63 -0
- data/.github/workflows/release.yml +8 -3
- data/.gitignore +11 -0
- data/.rubocop.yml +10 -7
- data/.rubocop_todo.yml +229 -23
- data/CHANGELOG.md +317 -0
- data/CLAUDE.md +139 -0
- data/Gemfile +11 -12
- data/README.adoc +1538 -11
- data/Rakefile +11 -3
- data/docs/Gemfile +8 -0
- data/docs/_config.yml +23 -0
- data/docs/getting-started/index.adoc +75 -0
- data/docs/guides/error-handling.adoc +137 -0
- data/docs/guides/external-references.adoc +128 -0
- data/docs/guides/index.adoc +24 -0
- data/docs/guides/parsing-rnc.adoc +141 -0
- data/docs/guides/parsing-rng-xml.adoc +81 -0
- data/docs/guides/rng-to-rnc.adoc +101 -0
- data/docs/guides/validation.adoc +85 -0
- data/docs/index.adoc +52 -0
- data/docs/reference/api.adoc +126 -0
- data/docs/reference/cli.adoc +182 -0
- data/docs/understanding/architecture.adoc +58 -0
- data/docs/understanding/rng-vs-rnc.adoc +118 -0
- data/exe/rng +5 -0
- data/lib/rng/any_name.rb +10 -8
- data/lib/rng/attribute.rb +28 -26
- data/lib/rng/choice.rb +24 -24
- data/lib/rng/cli.rb +607 -0
- data/lib/rng/data.rb +10 -10
- data/lib/rng/datatype_declaration.rb +26 -0
- data/lib/rng/define.rb +44 -41
- data/lib/rng/div.rb +36 -0
- data/lib/rng/documentation.rb +9 -0
- data/lib/rng/element.rb +39 -37
- data/lib/rng/empty.rb +7 -7
- data/lib/rng/except.rb +25 -25
- data/lib/rng/external_ref.rb +8 -8
- data/lib/rng/external_ref_resolver.rb +582 -0
- data/lib/rng/foreign_attribute.rb +26 -0
- data/lib/rng/foreign_element.rb +33 -0
- data/lib/rng/grammar.rb +14 -12
- data/lib/rng/group.rb +26 -24
- data/lib/rng/include.rb +5 -6
- data/lib/rng/include_processor.rb +461 -0
- data/lib/rng/interleave.rb +23 -23
- data/lib/rng/list.rb +22 -22
- data/lib/rng/mixed.rb +23 -23
- data/lib/rng/name.rb +7 -7
- data/lib/rng/namespace_declaration.rb +47 -0
- data/lib/rng/namespaces.rb +15 -0
- data/lib/rng/not_allowed.rb +7 -7
- data/lib/rng/ns_name.rb +9 -9
- data/lib/rng/one_or_more.rb +23 -23
- data/lib/rng/optional.rb +23 -23
- data/lib/rng/param.rb +8 -8
- data/lib/rng/parent_ref.rb +8 -8
- data/lib/rng/parse_tree_processor.rb +695 -0
- data/lib/rng/pattern.rb +7 -7
- data/lib/rng/ref.rb +8 -8
- data/lib/rng/rnc_builder.rb +927 -0
- data/lib/rng/rnc_parser.rb +605 -305
- data/lib/rng/rnc_to_rng_converter.rb +1408 -0
- data/lib/rng/schema_preamble.rb +73 -0
- data/lib/rng/schema_validator.rb +1622 -0
- data/lib/rng/start.rb +27 -25
- data/lib/rng/test_suite_parser.rb +168 -0
- data/lib/rng/text.rb +11 -8
- data/lib/rng/to_rnc.rb +4 -35
- data/lib/rng/value.rb +6 -7
- data/lib/rng/version.rb +1 -1
- data/lib/rng/zero_or_more.rb +23 -23
- data/lib/rng.rb +68 -17
- data/rng.gemspec +18 -19
- data/scripts/extract_spectest_resources.rb +96 -0
- data/spec/fixtures/compacttest.xml +2511 -0
- data/spec/fixtures/external/circular_a.rng +7 -0
- data/spec/fixtures/external/circular_b.rng +7 -0
- data/spec/fixtures/external/circular_main.rng +7 -0
- data/spec/fixtures/external/external_ref_lib.rng +7 -0
- data/spec/fixtures/external/external_ref_main.rng +7 -0
- data/spec/fixtures/external/include_lib.rng +7 -0
- data/spec/fixtures/external/include_main.rng +3 -0
- data/spec/fixtures/external/nested_chain.rng +6 -0
- data/spec/fixtures/external/nested_leaf.rng +7 -0
- data/spec/fixtures/external/nested_mid.rng +8 -0
- data/spec/fixtures/metanorma/3gpp.rnc +35 -0
- data/spec/fixtures/metanorma/3gpp.rng +105 -0
- data/spec/fixtures/metanorma/basicdoc.rnc +11 -0
- data/spec/fixtures/metanorma/bipm.rnc +148 -0
- data/spec/fixtures/metanorma/bipm.rng +376 -0
- data/spec/fixtures/metanorma/bsi.rnc +104 -0
- data/spec/fixtures/metanorma/bsi.rng +332 -0
- data/spec/fixtures/metanorma/csa.rnc +45 -0
- data/spec/fixtures/metanorma/csa.rng +131 -0
- data/spec/fixtures/metanorma/csd.rnc +43 -0
- data/spec/fixtures/metanorma/csd.rng +132 -0
- data/spec/fixtures/metanorma/gbstandard.rnc +99 -0
- data/spec/fixtures/metanorma/gbstandard.rng +316 -0
- data/spec/fixtures/metanorma/iec.rnc +49 -0
- data/spec/fixtures/metanorma/iec.rng +193 -0
- data/spec/fixtures/metanorma/ietf.rnc +275 -0
- data/spec/fixtures/metanorma/ietf.rng +925 -0
- data/spec/fixtures/metanorma/iho.rnc +58 -0
- data/spec/fixtures/metanorma/iho.rng +179 -0
- data/spec/fixtures/metanorma/isodoc.rnc +873 -0
- data/spec/fixtures/metanorma/isodoc.rng +2704 -0
- data/spec/fixtures/metanorma/isostandard-amd.rnc +43 -0
- data/spec/fixtures/metanorma/isostandard-amd.rng +108 -0
- data/spec/fixtures/metanorma/isostandard.rnc +166 -0
- data/spec/fixtures/metanorma/isostandard.rng +494 -0
- data/spec/fixtures/metanorma/itu.rnc +122 -0
- data/spec/fixtures/metanorma/itu.rng +377 -0
- data/spec/fixtures/metanorma/m3d.rnc +41 -0
- data/spec/fixtures/metanorma/m3d.rng +122 -0
- data/spec/fixtures/metanorma/mpfd.rnc +36 -0
- data/spec/fixtures/metanorma/mpfd.rng +95 -0
- data/spec/fixtures/metanorma/nist.rnc +77 -0
- data/spec/fixtures/metanorma/nist.rng +216 -0
- data/spec/fixtures/metanorma/ogc.rnc +51 -0
- data/spec/fixtures/metanorma/ogc.rng +151 -0
- data/spec/fixtures/metanorma/reqt.rnc +6 -0
- data/spec/fixtures/metanorma/rsd.rnc +36 -0
- data/spec/fixtures/metanorma/rsd.rng +95 -0
- data/spec/fixtures/metanorma/un.rnc +103 -0
- data/spec/fixtures/metanorma/un.rng +367 -0
- data/spec/fixtures/rnc/base.rnc +4 -0
- data/spec/fixtures/rnc/grammar_with_trailing.rnc +8 -0
- data/spec/fixtures/rnc/main_include_trailing.rnc +3 -0
- data/spec/fixtures/rnc/main_with_include.rnc +5 -0
- data/spec/fixtures/rnc/test_augment.rnc +10 -0
- data/spec/fixtures/rnc/test_isodoc_simple.rnc +9 -0
- data/spec/fixtures/rnc/top_level_include.rnc +8 -0
- data/spec/fixtures/spectest_external/case_10_4.7/x +3 -0
- data/spec/fixtures/spectest_external/case_10_4.7/y +7 -0
- data/spec/fixtures/spectest_external/case_11_4.7/x +3 -0
- data/spec/fixtures/spectest_external/case_12_4.7/x +3 -0
- data/spec/fixtures/spectest_external/case_13_4.7/x +3 -0
- data/spec/fixtures/spectest_external/case_13_4.7/y +3 -0
- data/spec/fixtures/spectest_external/case_14_4.7/x +7 -0
- data/spec/fixtures/spectest_external/case_15_4.7/x +7 -0
- data/spec/fixtures/spectest_external/case_16_4.7/x +5 -0
- data/spec/fixtures/spectest_external/case_17_4.7/x +5 -0
- data/spec/fixtures/spectest_external/case_18_4.7/x +7 -0
- data/spec/fixtures/spectest_external/case_19_4.7/level1.rng +9 -0
- data/spec/fixtures/spectest_external/case_19_4.7/level2.rng +7 -0
- data/spec/fixtures/spectest_external/case_1_4.5/sub1/x +3 -0
- data/spec/fixtures/spectest_external/case_1_4.5/sub3/x +3 -0
- data/spec/fixtures/spectest_external/case_1_4.5/x +3 -0
- data/spec/fixtures/spectest_external/case_20_4.6/x +3 -0
- data/spec/fixtures/spectest_external/case_2_4.5/x +3 -0
- data/spec/fixtures/spectest_external/case_3_4.6/x +3 -0
- data/spec/fixtures/spectest_external/case_4_4.6/x +3 -0
- data/spec/fixtures/spectest_external/case_5_4.6/x +1 -0
- data/spec/fixtures/spectest_external/case_6_4.6/x +5 -0
- data/spec/fixtures/spectest_external/case_7_4.6/x +1 -0
- data/spec/fixtures/spectest_external/case_7_4.6/y +1 -0
- data/spec/fixtures/spectest_external/case_8_4.7/x +7 -0
- data/spec/fixtures/spectest_external/case_9_4.7/x +7 -0
- data/spec/fixtures/spectest_external/resources.json +149 -0
- data/spec/rng/advanced_rnc_spec.rb +101 -0
- data/spec/rng/compacttest_spec.rb +197 -0
- data/spec/rng/datatype_declaration_spec.rb +28 -0
- data/spec/rng/div_spec.rb +207 -0
- data/spec/rng/external_ref_resolver_spec.rb +122 -0
- data/spec/rng/metanorma_conversion_spec.rb +159 -0
- data/spec/rng/namespace_declaration_spec.rb +60 -0
- data/spec/rng/namespace_support_spec.rb +199 -0
- data/spec/rng/rnc_parser_spec.rb +498 -22
- data/spec/rng/rnc_roundtrip_spec.rb +96 -82
- data/spec/rng/rng_generation_spec.rb +288 -0
- data/spec/rng/roundtrip_spec.rb +342 -0
- data/spec/rng/schema_preamble_spec.rb +145 -0
- data/spec/rng/schema_spec.rb +68 -64
- data/spec/rng/spectest_spec.rb +168 -90
- data/spec/rng_spec.rb +2 -2
- data/spec/spec_helper.rb +7 -42
- metadata +141 -8
data/Rakefile
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
5
|
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
|
8
|
-
require
|
|
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
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
|
+
----
|