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.
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(rnv_t *rnv, int erno,va_list ap);
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, n)
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, n)
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: #{@message}\n#{@expected}"
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: '#{@message}', expected: '#{@expected} line: #{@line}, column: #{@col}>"
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, :pre_processor
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
- update_line_col
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 str
90
+ def characters(value)
29
91
  update_line_col
30
- @document.characters(@pre_processor.text(str))
92
+ @document.characters(@pre_processor.text(value))
31
93
  end
32
94
 
33
- def cdata_block str
95
+ def cdata_block(value)
34
96
  update_line_col
35
- @document.characters(@pre_processor.text(str))
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.3.1
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-04-09 00:00:00.000000000 Z
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