nokogiri_schematron_builder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +32 -0
- data/README.md +109 -0
- data/Rakefile +2 -0
- data/WARRANTY.txt +22 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/nokogiri/xml/schematron.rb +8 -0
- data/lib/nokogiri/xml/schematron/assertion.rb +46 -0
- data/lib/nokogiri/xml/schematron/base.rb +143 -0
- data/lib/nokogiri/xml/schematron/internal/core_ext/array.rb +33 -0
- data/lib/nokogiri/xml/schematron/namespace.rb +42 -0
- data/lib/nokogiri/xml/schematron/nodes/base.rb +189 -0
- data/lib/nokogiri/xml/schematron/nodes/context.rb +13 -0
- data/lib/nokogiri/xml/schematron/nodes/permit.rb +24 -0
- data/lib/nokogiri/xml/schematron/nodes/reject.rb +24 -0
- data/lib/nokogiri/xml/schematron/nodes/require.rb +24 -0
- data/lib/nokogiri/xml/schematron/nodes/validations/exclusion.rb +51 -0
- data/lib/nokogiri/xml/schematron/nodes/validations/inclusion.rb +51 -0
- data/lib/nokogiri/xml/schematron/nodes/validations/numericality.rb +142 -0
- data/lib/nokogiri/xml/schematron/paragraph.rb +36 -0
- data/lib/nokogiri/xml/schematron/pattern.rb +150 -0
- data/lib/nokogiri/xml/schematron/rule.rb +53 -0
- data/lib/nokogiri/xml/schematron/schema.rb +85 -0
- data/lib/nokogiri/xml/schematron/version.rb +7 -0
- data/nokogiri_schematron_builder.gemspec +38 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 24f02a10a7493555198daad2202e63376d1e7bbc9af7b91c79318d4c36239c41
|
4
|
+
data.tar.gz: 9bf5e2b1ac5e0e6a7949bcef45331e8277a823a13cecb5b8c387ccdadee41c34
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: babe38706760546dfbb24513d9a9453c4156769837279c75967a253e8fd5bea48fb101c014c25299973e960d59d280dc5de5413a2ce63aac80de9a64320a4928
|
7
|
+
data.tar.gz: 175f4df54fa99d350c8823519c3d22c68be65c5912f98bf4605b949580bbd803590ffe703a6aa662d4a47509aff00a0439b65ca5b455e9f8c05e94b908b0bce7
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
nokogiri_schematron_builder
|
2
|
+
|
3
|
+
Copyright (c) 2019, Battelle Memorial Institute
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
1. Battelle Memorial Institute (hereinafter Battelle) hereby grants permission
|
7
|
+
to any person or entity lawfully obtaining a copy of this software and
|
8
|
+
associated documentation files (hereinafter "the Software") to redistribute
|
9
|
+
and use the Software in source and binary forms, with or without
|
10
|
+
modification. Such person or entity may use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and may permit
|
12
|
+
others to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
* Redistributions of source code must retain the above copyright notice, this
|
15
|
+
list of conditions and the following disclaimers.
|
16
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
17
|
+
this list of conditions and the following disclaimer in the documentation
|
18
|
+
and/or other materials provided with the distribution.
|
19
|
+
* Other than as used herein, neither the name Battelle Memorial Institute or
|
20
|
+
Battelle may be used in any form whatsoever without the express written
|
21
|
+
consent of Battelle.
|
22
|
+
|
23
|
+
2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
DISCLAIMED. IN NO EVENT SHALL BATTELLE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
27
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
28
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
29
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
30
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
31
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
32
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# nokogiri_schematron_builder
|
2
|
+
|
3
|
+
Build [Schematron](http://schematron.com) XML documents using [Nokogiri](https://nokogiri.org).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "nokogiri_schematron_builder"
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install nokogiri_schematron_builder
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Add this line to your application:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require "nokogiri/xml/schematron/schema"
|
27
|
+
```
|
28
|
+
|
29
|
+
Create the schema using the domain-specific language:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
schema = Nokogiri::XML::Schematron::Schema.new(title: "Example schema") do
|
33
|
+
ns(prefix: "ex", uri: "http://example.com/ns#")
|
34
|
+
pattern(name: "Example pattern") do
|
35
|
+
rule(context: "/") do
|
36
|
+
assert(test: "count(ex:A) >= 1", message: "element \"ex:A\" is REQUIRED")
|
37
|
+
end
|
38
|
+
rule(context: "/ex:A") do
|
39
|
+
assert(test: "count(ex:B) >= 0", message: "element \"ex:B\" is OPTIONAL")
|
40
|
+
end
|
41
|
+
rule(context: "/ex:A/ex:B") do
|
42
|
+
assert(test: "not(ex:C)", message: "element \"ex:C\" is NOT RECOMMENDED")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Or, equivalently:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
schema = Nokogiri::XML::Schematron::Schema.new(title: "Example schema") do
|
52
|
+
ns(prefix: "ex", uri: "http://example.com/ns#")
|
53
|
+
pattern(name: "Example pattern") do
|
54
|
+
context("/") do
|
55
|
+
require("ex:A") do
|
56
|
+
permit("ex:B") do
|
57
|
+
reject("ex:C")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
Next, construct a [`Nokogiri::XML::Builder`](https://nokogiri.org/rdoc/Nokogiri/XML/Builder.html) object:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
builder = schema.to_builder(encoding: "UTF-8")
|
69
|
+
```
|
70
|
+
|
71
|
+
Finally, generate the XML:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
xml = builder.to_xml
|
75
|
+
```
|
76
|
+
|
77
|
+
The result is:
|
78
|
+
|
79
|
+
```xml
|
80
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
81
|
+
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" title="Example schema">
|
82
|
+
<sch:ns prefix="ex" uri="http://example.com/ns#"/>
|
83
|
+
<sch:pattern name="Example pattern">
|
84
|
+
<sch:rule context="/">
|
85
|
+
<sch:assert test="count(ex:A) >= 1">element "ex:A" is REQUIRED</sch:assert>
|
86
|
+
</sch:rule>
|
87
|
+
<sch:rule context="/ex:A">
|
88
|
+
<sch:assert test="count(ex:B) >= 0">element "ex:B" is OPTIONAL</sch:assert>
|
89
|
+
</sch:rule>
|
90
|
+
<sch:rule context="/ex:A/ex:B">
|
91
|
+
<sch:assert test="not(ex:C)">element "ex:C" is NOT RECOMMENDED</sch:assert>
|
92
|
+
</sch:rule>
|
93
|
+
</sch:pattern>
|
94
|
+
</sch:schema>
|
95
|
+
```
|
96
|
+
|
97
|
+
## Development
|
98
|
+
|
99
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
100
|
+
|
101
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
102
|
+
|
103
|
+
## License
|
104
|
+
|
105
|
+
[The 2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause)
|
106
|
+
|
107
|
+
## Contributing
|
108
|
+
|
109
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pnnl/nokogiri_schematron_builder.
|
data/Rakefile
ADDED
data/WARRANTY.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
This material was prepared as an account of work sponsored by an agency of the
|
2
|
+
United States Government. Neither the United States Government nor the United
|
3
|
+
States Department of Energy, nor Battelle, nor any of their employees, nor any
|
4
|
+
jurisdiction or organization that has cooperated in the development of these
|
5
|
+
materials, makes any warranty, express or implied, or assumes any legal
|
6
|
+
liability or responsibility for the accuracy, completeness, or usefulness or any
|
7
|
+
information, apparatus, product, software, or process disclosed, or represents
|
8
|
+
that its use would not infringe privately owned rights.
|
9
|
+
|
10
|
+
Reference herein to any specific commercial product, process, or service by
|
11
|
+
trade name, trademark, manufacturer, or otherwise does not necessarily
|
12
|
+
constitute or imply its endorsement, recommendation, or favoring by the United
|
13
|
+
States Government or any agency thereof, or Battelle Memorial Institute. The
|
14
|
+
views and opinions of authors expressed herein do not necessarily state or
|
15
|
+
reflect those of the United States Government or any agency thereof.
|
16
|
+
|
17
|
+
PACIFIC NORTHWEST NATIONAL LABORATORY
|
18
|
+
operated by
|
19
|
+
BATTELLE
|
20
|
+
for the
|
21
|
+
UNITED STATES DEPARTMENT OF ENERGY
|
22
|
+
under Contract DE-AC05-76RL01830
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "nokogiri/xml/schematron"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "nokogiri/xml/schematron/base"
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module XML
|
5
|
+
module Schematron
|
6
|
+
# The internal representation of the +<sch:assert>+ XML element.
|
7
|
+
#
|
8
|
+
# For example:
|
9
|
+
#
|
10
|
+
# assertion = Nokogiri::XML::Schematron::Assertion.new(nil, test: "not(ex:Example)", message: "element \"ex:Example\" is NOT RECOMMENDED")
|
11
|
+
# # => #<Nokogiri::XML::Schematron::Assertion:0x00007fa739a55dd8 @parent=nil, @children=[], @options={:test=>"not(ex:Example)", :message=>"element \"ex:Example\" is NOT RECOMMENDED"}>
|
12
|
+
# assertion.to_builder.to_xml
|
13
|
+
# # => "<?xml version=\"1.0\"?>\n<sch:assert xmlns:sch=\"http://purl.oclc.org/dsdl/schematron\" test=\"not(ex:Example)\">element \"ex:Example\" is NOT RECOMMENDED</sch:assert>\n"
|
14
|
+
#
|
15
|
+
class Assertion < Nokogiri::XML::Schematron::Base
|
16
|
+
# @!attribute [rw] message
|
17
|
+
# @return [String] the text content of the +<sch:assert>+ XML element.
|
18
|
+
attribute :message
|
19
|
+
|
20
|
+
# @!attribute [rw] test
|
21
|
+
# @return [String] the value of the +@test+ XML attribute.
|
22
|
+
attribute :test
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def build!(xml)
|
27
|
+
xml["sch"].send(:assert, %w(test).inject(xmlns) { |acc, method_name|
|
28
|
+
unless (s = send(method_name.to_sym)).nil?
|
29
|
+
acc[method_name.to_s] = s
|
30
|
+
end
|
31
|
+
|
32
|
+
acc
|
33
|
+
}) do
|
34
|
+
unless (s = send(:message)).nil?
|
35
|
+
xml.text(s)
|
36
|
+
end
|
37
|
+
|
38
|
+
super(xml)
|
39
|
+
end
|
40
|
+
|
41
|
+
return
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Nokogiri
|
4
|
+
module XML
|
5
|
+
module Schematron
|
6
|
+
# The base class for internal representations of Schematron types.
|
7
|
+
# @abstract
|
8
|
+
class Base
|
9
|
+
class << self
|
10
|
+
# Defines methods for a named XML attribute.
|
11
|
+
#
|
12
|
+
# For example:
|
13
|
+
#
|
14
|
+
# attribute :name
|
15
|
+
#
|
16
|
+
# defines reader and writer methods that are equivalent to:
|
17
|
+
#
|
18
|
+
# def name
|
19
|
+
# @options[:name]
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def name=(value)
|
23
|
+
# @options[:name] = value
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @param name [#to_sym] the method name.
|
27
|
+
# @param options [Hash<Symbol, Object>] the options.
|
28
|
+
# @option options [Boolean] :reader (true) define the reader method?
|
29
|
+
# @option options [Boolean] :writer (true) define the writer method?
|
30
|
+
# @return [void]
|
31
|
+
def attribute(name, **options)
|
32
|
+
unless options[:reader] == false
|
33
|
+
define_method(name.to_sym) do
|
34
|
+
instance_variable_get(:@options).send(:[], name.to_sym)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
unless options[:writer] == false
|
39
|
+
define_method(:"#{name.to_sym}=") do |value|
|
40
|
+
instance_variable_get(:@options).send(:[]=, name.to_sym, value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
# Defines methods for a named XML element.
|
48
|
+
#
|
49
|
+
# For example:
|
50
|
+
#
|
51
|
+
# element :name, DescendentOfBase
|
52
|
+
#
|
53
|
+
# where
|
54
|
+
#
|
55
|
+
# class DescendentOfBase < Base; end
|
56
|
+
#
|
57
|
+
# is a descendent of this class, defines methods that are equivalent to:
|
58
|
+
#
|
59
|
+
# def name(*args, &block)
|
60
|
+
# base = DescendentOfBase.new(self, *args, &block)
|
61
|
+
# @children << base
|
62
|
+
# base
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# @param name [#to_sym] the method name.
|
66
|
+
# @param klass [Class] the class.
|
67
|
+
# @return [void]
|
68
|
+
def element(name, klass)
|
69
|
+
define_method(name.to_sym) do |*args, &block|
|
70
|
+
base = klass.send(:new, self, *args, &block)
|
71
|
+
instance_variable_get(:@children) << base
|
72
|
+
base
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Nokogiri::XML::Schematron::Base] the parent object.
|
78
|
+
attr_reader :parent
|
79
|
+
|
80
|
+
# @return [Array<Nokogiri::XML::Schematron::Base>] the children of the internal representation of the Schematron type.
|
81
|
+
attr_reader :children
|
82
|
+
|
83
|
+
# @return [Hash<Symbol, Object>] the options.
|
84
|
+
attr_reader :options
|
85
|
+
|
86
|
+
# Create a new +Base+ object.
|
87
|
+
#
|
88
|
+
# @param parent [Nokogiri::XML::Schematron::Base] the parent object.
|
89
|
+
# @param options [Hash<Symbol, Object>] the options.
|
90
|
+
# @yieldparam base [Nokogiri::XML::Schematron::Base] the internal representation of the Schematron type.
|
91
|
+
# @yieldreturn [void]
|
92
|
+
def initialize(parent, **options, &block)
|
93
|
+
@parent = parent
|
94
|
+
@children = []
|
95
|
+
|
96
|
+
@options = options
|
97
|
+
|
98
|
+
if block_given?
|
99
|
+
case block.arity
|
100
|
+
when 1 then block.call(self)
|
101
|
+
else instance_eval(&block)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Convert this +Base+ object to a +Builder+ object.
|
107
|
+
#
|
108
|
+
# @return [Nokogiri::XML::Builder]
|
109
|
+
# @see https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Builder#initialize-instance_method
|
110
|
+
def to_builder(*args)
|
111
|
+
::Nokogiri::XML::Builder.new(*args) do |xml|
|
112
|
+
build!(xml)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
# Build the XML representation of the Schematron type.
|
119
|
+
#
|
120
|
+
# @param xml [Nokogiri::XML::Builder] the XML builder.
|
121
|
+
# @return [void]
|
122
|
+
def build!(xml)
|
123
|
+
@children.each do |base|
|
124
|
+
base.send(:build!, xml)
|
125
|
+
end
|
126
|
+
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Hash<String, String>] the hash of XML namespaces (URI by prefix).
|
131
|
+
def xmlns
|
132
|
+
if @parent.nil?
|
133
|
+
{
|
134
|
+
"xmlns:sch" => "http://purl.oclc.org/dsdl/schematron",
|
135
|
+
}
|
136
|
+
else
|
137
|
+
{}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nokogiri
|
2
|
+
module XML
|
3
|
+
module Schematron
|
4
|
+
module Internal
|
5
|
+
module CoreExt
|
6
|
+
module Array
|
7
|
+
# Converts the array to a comma-separated sentence where the last
|
8
|
+
# element is joined by the connector word.
|
9
|
+
#
|
10
|
+
# @param array [Array<String>] the array of strings.
|
11
|
+
# @param options [Hash<Symbol, Object>] the options.
|
12
|
+
# @option options [String] :words_connector the sign or word used to join the elements in arrays with two or more elements.
|
13
|
+
# @option options [String] :two_words_connector the sign or word used to join the elements in arrays with two elements.
|
14
|
+
# @option options [String] :last_word_connector the sign or word used to join the last element in arrays with three or more elements.
|
15
|
+
# @return [String] the comma-separated sentence.
|
16
|
+
def self.to_sentence(array, options = {})
|
17
|
+
case array.length
|
18
|
+
when 0
|
19
|
+
''
|
20
|
+
when 1
|
21
|
+
array[0].to_s.dup
|
22
|
+
when 2
|
23
|
+
"#{array[0]}#{options[:two_words_connector]}#{array[1]}"
|
24
|
+
else
|
25
|
+
"#{array[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{array[-1]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|