ruby_rnv 0.3.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/rnv/extconf.rb +1 -1
- data/ext/rnv/ruby_rnv.c +88 -381
- data/ext/rnv/ruby_rnv.h +62 -0
- data/ext/rnv/ruby_rnv_err.c +548 -0
- data/ext/rnv/src/ary.c +1 -2
- data/ext/rnv/src/drv.c +78 -62
- data/ext/rnv/src/drv.h +3 -2
- data/ext/rnv/src/er.c +1 -1
- data/ext/rnv/src/er.h +1 -1
- data/ext/rnv/src/erbit.h +3 -0
- data/ext/rnv/src/rn.c +24 -26
- data/ext/rnv/src/rn.h +1 -1
- data/ext/rnv/src/rnc.c +28 -16
- data/ext/rnv/src/rnc.h +3 -23
- data/ext/rnv/src/rnd.c +24 -20
- data/ext/rnv/src/rnd.h +3 -2
- data/ext/rnv/src/rnl.c +24 -20
- data/ext/rnv/src/rnl.h +2 -3
- data/ext/rnv/src/rnv.c +20 -18
- data/ext/rnv/src/rnv.h +2 -2
- data/ext/rnv/src/rnx.c +15 -17
- data/ext/rnv/src/rnx.h +2 -3
- data/ext/rnv/src/rx.c +44 -32
- data/ext/rnv/src/rx.h +7 -8
- data/ext/rnv/src/sc.c +5 -0
- data/ext/rnv/src/sc.h +1 -0
- data/ext/rnv/src/type.h +61 -28
- data/ext/rnv/src/xcl.c +24 -27
- data/ext/rnv/src/xsd.c +10 -23
- data/ext/rnv/src/xsd.h +1 -2
- data/lib/rnv/data_type_library.rb +5 -7
- data/lib/rnv/error.rb +105 -3
- data/lib/rnv/validator.rb +75 -7
- metadata +4 -2
data/ext/rnv/src/xsd.h
CHANGED
@@ -14,10 +14,9 @@
|
|
14
14
|
#define XSD_ER_WS 5
|
15
15
|
#define XSD_ER_ENUM 6
|
16
16
|
|
17
|
-
extern void xsd_default_verror_handler(
|
17
|
+
extern void xsd_default_verror_handler(void *data, int erno, int (*handler)(void *data, int erno,char *format, va_list ap), va_list ap);
|
18
18
|
|
19
19
|
extern void xsd_init(rx_st_t *rx_st);
|
20
|
-
extern void xsd_clear(void);
|
21
20
|
|
22
21
|
extern int xsd_allows(rx_st_t *rx_st, char *typ,char *ps,char *s,int n);
|
23
22
|
extern int xsd_equal(rx_st_t *rx_st, char *typ,char *val,char *s,int n);
|
@@ -2,21 +2,19 @@ module RNV
|
|
2
2
|
# Datatype library callback object
|
3
3
|
# @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
|
4
4
|
class DataTypeLibrary
|
5
|
-
# @param [String] typ
|
5
|
+
# @param [String] typ the data type
|
6
6
|
# @param [String] val
|
7
7
|
# @param [String] s
|
8
|
-
# @param [Integer] n
|
9
8
|
# @return [Boolean]
|
10
|
-
def equal(typ, val, s
|
9
|
+
def equal(typ, val, s)
|
11
10
|
true
|
12
11
|
end
|
13
12
|
|
14
|
-
# @param [String] typ
|
13
|
+
# @param [String] typ the data type
|
15
14
|
# @param [String] ps
|
16
|
-
# @param [String] s
|
17
|
-
# @param [Integer] n
|
15
|
+
# @param [String] s the value
|
18
16
|
# @return [Boolean]
|
19
|
-
def allows(typ, ps, s
|
17
|
+
def allows(typ, ps, s)
|
20
18
|
true
|
21
19
|
end
|
22
20
|
end
|
data/lib/rnv/error.rb
CHANGED
@@ -1,13 +1,115 @@
|
|
1
1
|
module RNV
|
2
2
|
class Error
|
3
|
+
attr_reader :original_message, :original_expected
|
4
|
+
attr_reader :ns_uri, :element, :attr, :value
|
5
|
+
attr_reader :xpath
|
6
|
+
|
7
|
+
# @return [String]
|
8
|
+
def message
|
9
|
+
@original_message
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
def expected
|
14
|
+
@original_expected
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String]
|
18
|
+
def compact_message
|
19
|
+
case @code
|
20
|
+
when :rnv_er_elem
|
21
|
+
"element <#{@element}> is not allowed"
|
22
|
+
when :rnv_er_ufin
|
23
|
+
"element <#{@element}> is incomplete"
|
24
|
+
when :rnv_er_akey
|
25
|
+
"attribute #{@attr} is not allowed"
|
26
|
+
when :rnv_er_aval
|
27
|
+
"attribute #{@attr} has invalid value '#{@value}'"
|
28
|
+
when :rnv_er_amis
|
29
|
+
"element <#{@element}> attribute missing"
|
30
|
+
else
|
31
|
+
@original_message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
def compact_expected
|
37
|
+
[(compact_required_set.length > 0 ? compact_expected_phrase(compact_required_set) + " required" : nil),
|
38
|
+
(compact_allowed_set.length > 0 ? compact_expected_phrase(compact_allowed_set) + " allowed" : nil)].join("; ")
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param [String] data original content
|
42
|
+
# @return [String] context
|
43
|
+
def contextualize(data, max_len = 60)
|
44
|
+
out = ""
|
45
|
+
if data and @line
|
46
|
+
err_data = data.split("\n")[@line - 1]
|
47
|
+
if err_data && err_data.length > @col - 1
|
48
|
+
err_data.insert(@col - 1, "🢑")
|
49
|
+
|
50
|
+
start = 0
|
51
|
+
if @col > max_len
|
52
|
+
start = @col - max_len
|
53
|
+
end
|
54
|
+
out += (start > 0 ? "…" : "") + err_data[start..(@col + max_len)].strip + (@col + max_len < err_data.length ? "…" : "")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
out
|
58
|
+
end
|
59
|
+
|
3
60
|
# @return [String]
|
4
61
|
def to_s
|
5
|
-
"#{@line}:#{@col}:error: #{
|
62
|
+
"#{@line}:#{@col}:error: #{self.message}\n#{self.expected}"
|
6
63
|
end
|
7
64
|
|
8
65
|
# @return [String]
|
9
66
|
def inspect
|
10
|
-
"#<RNV::Error code: :#{@code}, message: '#{
|
67
|
+
"#<RNV::Error code: :#{@code}, message: '#{self.message}', expected: '#{self.expected}, line: #{@line}, column: #{@col}>"
|
68
|
+
end
|
69
|
+
|
70
|
+
def required
|
71
|
+
@required.select{|a| @attr ? a.first == :rn_p_attribute : true}
|
72
|
+
end
|
73
|
+
|
74
|
+
def allowed
|
75
|
+
@allowed.select{|a| @attr ? a.first == :rn_p_attribute : true}
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def compact_expected_to_s(e, with_ns = false)
|
81
|
+
case e.first
|
82
|
+
when :rn_p_attribute
|
83
|
+
compact_expected_to_s(e.last, with_ns)
|
84
|
+
when :rn_p_element
|
85
|
+
"<" + compact_expected_to_s(e.last, with_ns) + ">"
|
86
|
+
when :rn_p_data
|
87
|
+
compact_expected_to_s(e.last, with_ns)
|
88
|
+
when :rn_p_value
|
89
|
+
"\"#{e.last}\""
|
90
|
+
when :rn_nc_datatype
|
91
|
+
"datatype #{e[-2]}:#{e.last}"
|
92
|
+
when :rn_nc_qname
|
93
|
+
with_ns ? "#{e.first}:#{e.last}" : e.last
|
94
|
+
else
|
95
|
+
"unknown #{e.first}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def compact_required_set
|
100
|
+
@compact_required_set ||= required.map { |r| compact_expected_to_s(r) }.compact.uniq
|
101
|
+
end
|
102
|
+
|
103
|
+
def compact_allowed_set
|
104
|
+
@compact_allowed_set ||= allowed.map { |r| compact_expected_to_s(r) }.compact.uniq
|
105
|
+
end
|
106
|
+
|
107
|
+
def compact_expected_phrase(set)
|
108
|
+
if set.length > 1
|
109
|
+
set[0..-2].join(", ") + " or " + set.last
|
110
|
+
else
|
111
|
+
set.last
|
112
|
+
end
|
11
113
|
end
|
12
114
|
end
|
13
|
-
end
|
115
|
+
end
|
data/lib/rnv/validator.rb
CHANGED
@@ -3,36 +3,98 @@ require 'rnv/rnv'
|
|
3
3
|
require 'rnv/pre_processor'
|
4
4
|
|
5
5
|
module RNV
|
6
|
+
class DocumentEmpty < StandardError; end
|
7
|
+
|
8
|
+
# @!visibility private
|
9
|
+
class XpathNode
|
10
|
+
attr_accessor :name
|
11
|
+
attr_accessor :uri, :namespaces
|
12
|
+
attr_accessor :parent
|
13
|
+
attr_accessor :children
|
14
|
+
|
15
|
+
def initialize(name)
|
16
|
+
@name = name
|
17
|
+
@children = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_child(name, uri = nil, namespaces = {})
|
21
|
+
child = XpathNode.new(name)
|
22
|
+
child.uri = uri
|
23
|
+
child.namespaces = namespaces
|
24
|
+
child.parent = self
|
25
|
+
@children << child
|
26
|
+
child
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_xpath
|
30
|
+
xpath = []
|
31
|
+
current = self
|
32
|
+
namespaces = {}
|
33
|
+
rev_namespaces = {}
|
34
|
+
ns_current = self
|
35
|
+
while ns_current.name
|
36
|
+
ns_current.namespaces.each do |prefix, uri|
|
37
|
+
rev_namespaces[uri] ||= []
|
38
|
+
rev_namespaces[uri] << prefix
|
39
|
+
end
|
40
|
+
ns_current = ns_current.parent
|
41
|
+
end
|
42
|
+
|
43
|
+
rev_namespaces.each do |uri, prefixes|
|
44
|
+
if prefixes.length > 0
|
45
|
+
prefixes.select! { |prefix| prefix != "xmlns" }
|
46
|
+
end
|
47
|
+
namespaces[prefixes.first||"xmlns"] = uri
|
48
|
+
end
|
49
|
+
|
50
|
+
while current.name
|
51
|
+
xpath << "#{rev_namespaces[current.uri]&.first||"xmlns"}:#{current.name}[#{current.parent.children.select { |child| child.name == current.name }.index(current) + 1}]"
|
52
|
+
current = current.parent
|
53
|
+
end
|
54
|
+
[xpath.reverse, namespaces]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
6
58
|
# @!visibility private
|
7
59
|
class NokogiriSaxDocument < Nokogiri::XML::SAX::Document
|
8
60
|
# @return [Nokogiri::XML::SAX::ParserContext]
|
9
|
-
attr_accessor :ctx
|
61
|
+
attr_accessor :ctx
|
62
|
+
attr_accessor :pre_processor
|
63
|
+
|
10
64
|
# @param [RNV::Document] document
|
11
65
|
def initialize(document)
|
12
66
|
@document = document
|
67
|
+
@xpath_tree = XpathNode.new(nil)
|
13
68
|
end
|
14
69
|
|
15
70
|
def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = nil)
|
16
|
-
update_line_col
|
17
71
|
tag_attrs = attrs.map { |attr| [attr.uri ? "#{attr.uri}:#{attr.localname}" : attr.localname, attr.value] }
|
18
72
|
tag_name = uri ? "#{uri}:#{name}" : name
|
73
|
+
namespaces = {}
|
74
|
+
ns.each do |n|
|
75
|
+
namespaces[n.first || "xmlns"] = n.last
|
76
|
+
end
|
77
|
+
@xpath_tree = @xpath_tree.add_child(name, uri, namespaces)
|
78
|
+
|
79
|
+
update_line_col
|
19
80
|
@document.start_tag(@pre_processor.tag(tag_name), @pre_processor.attributes(tag_attrs))
|
20
81
|
end
|
21
82
|
|
22
83
|
def end_element_namespace(name, prefix = nil, uri = nil)
|
23
|
-
|
84
|
+
@xpath_tree = @xpath_tree.parent
|
24
85
|
tag_name = uri ? "#{uri}:#{name}" : name
|
86
|
+
update_line_col
|
25
87
|
@document.end_tag(@pre_processor.tag(tag_name))
|
26
88
|
end
|
27
89
|
|
28
|
-
def characters
|
90
|
+
def characters(value)
|
29
91
|
update_line_col
|
30
|
-
@document.characters(@pre_processor.text(
|
92
|
+
@document.characters(@pre_processor.text(value))
|
31
93
|
end
|
32
94
|
|
33
|
-
def cdata_block
|
95
|
+
def cdata_block(value)
|
34
96
|
update_line_col
|
35
|
-
@document.characters(@pre_processor.text(
|
97
|
+
@document.characters(@pre_processor.text(value))
|
36
98
|
end
|
37
99
|
|
38
100
|
private
|
@@ -40,6 +102,8 @@ module RNV
|
|
40
102
|
def update_line_col
|
41
103
|
@document.last_line = @ctx.line
|
42
104
|
@document.last_col = @ctx.column
|
105
|
+
xpath = @xpath_tree.to_xpath
|
106
|
+
@document.xpath = ["/" + xpath.first.join("/"), xpath.last]
|
43
107
|
end
|
44
108
|
end
|
45
109
|
|
@@ -78,6 +142,8 @@ module RNV
|
|
78
142
|
rnv_doc = NokogiriSaxDocument.new(@document)
|
79
143
|
rnv_doc.pre_processor = pre_processor
|
80
144
|
|
145
|
+
raise RNV::DocumentEmpty if str.nil? or str.empty?
|
146
|
+
|
81
147
|
parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
|
82
148
|
parser.parse_memory(str) do |ctx|
|
83
149
|
ctx.replace_entities = true
|
@@ -98,6 +164,8 @@ module RNV
|
|
98
164
|
|
99
165
|
file = xml.is_a?(File) ? xml : File.open(xml)
|
100
166
|
|
167
|
+
raise RNV::DocumentEmpty if file.size == 0
|
168
|
+
|
101
169
|
parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
|
102
170
|
parser.parse(file) do |ctx|
|
103
171
|
ctx.replace_entities = true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_rnv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Boulnois
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -104,6 +104,8 @@ files:
|
|
104
104
|
- Gemfile
|
105
105
|
- ext/rnv/extconf.rb
|
106
106
|
- ext/rnv/ruby_rnv.c
|
107
|
+
- ext/rnv/ruby_rnv.h
|
108
|
+
- ext/rnv/ruby_rnv_err.c
|
107
109
|
- ext/rnv/src/ary.c
|
108
110
|
- ext/rnv/src/ary.h
|
109
111
|
- ext/rnv/src/drv.c
|