xsd 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3b12830c536c37e72b109727f470d45de29b6c852e62476cd3aa5578dd3b9c7
4
- data.tar.gz: 248b65a3794a6c83a6aca695b0d565d55b971991272fd5f7f0a8a841fb8847ec
3
+ metadata.gz: ab9eaf4eb6b8aacde5379acdc08cc16c3d85e3dc9d75a5887b2f1db05ea6ed58
4
+ data.tar.gz: 8c5fdbf108a6867689ff3292a5e208a33160f232b4a3d3a96eb55e42e9b6da7e
5
5
  SHA512:
6
- metadata.gz: ac15d2c2c163bd70f007fd76b5c007fbc786ed09d5609a2d6dba5aa8836144917a5159a32c1b7f47aa250bd18034d8339f445180fc4cd330745138ec60283e32
7
- data.tar.gz: 7db0b9ac2ba0c97aab16d84db5145b4a8a18c901f3c24c8fd13a73b96a1998083a41cff38c3b0f7098dc53457b693e0ee5d3d941ceb1712f38a54924d32ce544
6
+ metadata.gz: d75af5531e7763eb3bc9359b2992e03704d963cfbc394a863022a3ff8db87d97db368409666bc7540f2fc772b78e2b25ab59905301e19d370827750050823462
7
+ data.tar.gz: 2b06fd643f69e41017683b689e614dbef7c42dca4fefbdec753f7f8edcc0978caf80eefe8c7d68e4acdc86aadd2777160a5cd7105a776d13ebfc2c57fc5af45c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.2.0] - 2023-07-10
4
+
5
+ - Fixed built-in types detection for unprefixed schema namespace
6
+ - Move validation to Schema object
7
+
3
8
  ## [2.1.0] - 2023-07-10
4
9
 
5
10
  - Add support for <xs:include> element
@@ -346,5 +346,12 @@ module XSD
346
346
  name.to_sym
347
347
  end
348
348
  end
349
+
350
+ # Return string if it is not empty, or nil otherwise
351
+ # @param [String, nil] string
352
+ # @return String, nil
353
+ def nil_if_empty(string)
354
+ string&.empty? ? nil : string
355
+ end
349
356
  end
350
357
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tmpdir'
4
+ require 'securerandom'
5
+
3
6
  module XSD
4
7
  # The schema element defines the root element of a schema.
5
8
  # Parent elements: NONE
@@ -108,23 +111,23 @@ module XSD
108
111
  attributes
109
112
  end
110
113
 
111
- # Get target namespace prefix. There may be more than one prefix, but we return only first defined
112
- # @return String
114
+ # Get target namespace prefix
115
+ # @return String, nil
113
116
  def target_namespace_prefix
114
- @target_namespace_prefix ||= namespaces.key(target_namespace)&.sub(/^xmlns:?/, '') || ''
117
+ nil_if_empty(@target_namespace_prefix ||= namespaces.key(target_namespace)&.sub(/^xmlns:?/, '') || '')
115
118
  end
116
119
 
117
120
  # Get schema namespace prefix
118
- # @return String
121
+ # @return String, nil
119
122
  def namespace_prefix
120
- @namespace_prefix ||= namespaces.key(XML_SCHEMA).sub(/^xmlns:?/, '')
123
+ nil_if_empty(@namespace_prefix ||= namespaces.key(XML_SCHEMA).sub(/^xmlns:?/, ''))
121
124
  end
122
125
 
123
126
  # Check if namespace is a target namespace
124
127
  # @param [String, nil] namespace
125
128
  # @return Boolean
126
129
  def targets_namespace?(namespace)
127
- namespace == target_namespace || namespaces[namespace.empty? ? 'xmlns' : "xmlns:#{namespace}"] == target_namespace
130
+ namespace == target_namespace || namespaces[namespace.nil? ? 'xmlns' : "xmlns:#{namespace}"] == target_namespace
128
131
  end
129
132
 
130
133
  # Override map_children on schema to get objects from all loaded schemas
@@ -157,5 +160,97 @@ module XSD
157
160
  aliases = [ns, namespaces["xmlns:#{(ns || '').gsub(/^xmlns:/, '')}"], reader.namespace_prefixes[ns]].compact
158
161
  imports.find { |import| aliases.include?(import.namespace) }
159
162
  end
163
+
164
+ # Validate XML against current schema
165
+ # @param [String, Pathname, Nokogiri::XML::Document] xml
166
+ def validate_xml(xml)
167
+ # validate input
168
+ raise ValidationError unless xml.is_a?(Nokogiri::XML::Document) || xml.is_a?(Pathname) || xml.is_a?(String)
169
+
170
+ begin
171
+ document = xml.is_a?(Nokogiri::XML::Document) ? xml : Nokogiri::XML(xml)
172
+ rescue Nokogiri::XML::SyntaxError => e
173
+ raise ValidationError, e
174
+ end
175
+
176
+ errors = schema_validator.validate(document)
177
+ raise ValidationError, errors.map(&:message).join('; ') if errors.any?
178
+ end
179
+
180
+ # Validate current schema against XMLSchema 1.0
181
+ def validate
182
+ begin
183
+ schema_validator
184
+ rescue Nokogiri::XML::SyntaxError => e
185
+ # TODO: display import map name for imported_xsd
186
+ message = e.message + (e.file ? " in file '#{File.basename(e.file)}'" : '')
187
+ raise ValidationError, message
188
+ end
189
+ end
190
+
191
+ private
192
+
193
+ # Get Nokogiri::XML::Schema object to validate against
194
+ # @return Nokogiri::XML::Schema
195
+ def schema_validator
196
+ return @schema_validator if @schema_validator
197
+
198
+ # if !imported_xsd.empty?
199
+ # imports are explicitly provided - put all files in one tmpdir and update import paths appropriately
200
+ # TODO: save file/path map to display in errors
201
+ Dir.mktmpdir('XSD', reader.tmp_dir) do |dir|
202
+ # create primary xsd file
203
+ file = "#{::SecureRandom.urlsafe_base64}.xsd"
204
+
205
+ # create imported xsd files
206
+ recursive_import_xsd(self, file, Set.new) do |f, data|
207
+ File.write("#{dir}/#{f}", data)
208
+ end
209
+
210
+ # read schema from tmp file descriptor
211
+ io = File.open("#{dir}/#{file}")
212
+ @schema_validator = create_xml_schema(io)
213
+ end
214
+ # else
215
+ # @schema_validator = create_xml_schema(schema.node.to_xml)
216
+ # end
217
+
218
+ @schema_validator
219
+ end
220
+
221
+ # Сформировать имена файлов и содержимое XSD схем для корректной валидации
222
+ # @param [Schema] schema
223
+ # @param [String] file
224
+ # @param [Set] processed
225
+ def recursive_import_xsd(schema, file, processed, &block)
226
+ # handle recursion
227
+ namespace = schema.target_namespace
228
+ return if processed.include?(namespace)
229
+
230
+ processed.add(namespace)
231
+
232
+ data = schema.node.to_xml
233
+
234
+ schema.imports.each do |import|
235
+ name = "#{::SecureRandom.urlsafe_base64}.xsd"
236
+ location = import.schema_location
237
+ namespace = import.namespace
238
+
239
+ if location
240
+ data = data.sub("schemaLocation=\"#{location}\"", "schemaLocation=\"#{name}\"")
241
+ else
242
+ data = data.sub("namespace=\"#{namespace}\"", "namespace=\"#{namespace}\" schemaLocation=\"#{name}\"")
243
+ end
244
+ recursive_import_xsd(import.imported_schema, name, processed, &block)
245
+ end
246
+
247
+ block.call(file, data)
248
+ end
249
+
250
+ # Create Nokogiri XML Schema instance with preconfigured options
251
+ # @param [IO, String] io
252
+ def create_xml_schema(io)
253
+ Nokogiri::XML::Schema(io, Nokogiri::XML::ParseOptions.new.nononet)
254
+ end
160
255
  end
161
256
  end
data/lib/xsd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XSD
4
- VERSION = '2.1.0'
4
+ VERSION = '2.2.0'
5
5
  end
data/lib/xsd/xml.rb CHANGED
@@ -6,7 +6,6 @@ require 'net/http'
6
6
  module XSD
7
7
  class XML
8
8
  include Generator
9
- include Validator
10
9
 
11
10
  attr_reader :options, :object_cache, :schemas, :namespace_prefixes
12
11
 
data/lib/xsd.rb CHANGED
@@ -38,6 +38,5 @@ require 'xsd/objects/any_attribute'
38
38
  require 'xsd/objects/key'
39
39
  require 'xsd/objects/keyref'
40
40
  require 'xsd/generator'
41
- require 'xsd/validator'
42
41
  require 'xsd/exceptions'
43
42
  require 'xsd/xml'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - d.arkhipov
@@ -109,7 +109,6 @@ files:
109
109
  - lib/xsd/shared/min_max_occurs.rb
110
110
  - lib/xsd/shared/referenced.rb
111
111
  - lib/xsd/shared/simple_typed.rb
112
- - lib/xsd/validator.rb
113
112
  - lib/xsd/version.rb
114
113
  - lib/xsd/xml.rb
115
114
  - xsd.gemspec
data/lib/xsd/validator.rb DELETED
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module XSD
4
- module Validator
5
- # Validate XML against XSD
6
- # @param [String, Pathname, Nokogiri::XML::Document] xml
7
- def validate_xml(xml)
8
- # validate input
9
- raise ValidationError unless xml.is_a?(Nokogiri::XML::Document) || xml.is_a?(Pathname) || xml.is_a?(String)
10
-
11
- begin
12
- document = xml.is_a?(Nokogiri::XML::Document) ? xml : Nokogiri::XML(xml)
13
- rescue Nokogiri::XML::SyntaxError => e
14
- raise ValidationError, e
15
- end
16
-
17
- errors = schema_validator.validate(document)
18
- raise ValidationError, errors.map(&:message).join('; ') if errors.any?
19
- end
20
-
21
- # Validate XSD against another XSD (by default uses XMLSchema 1.0)
22
- def validate
23
- begin
24
- schema_validator
25
- rescue Nokogiri::XML::SyntaxError => e
26
- # TODO: display import map name for imported_xsd
27
- message = e.message + (e.file ? " in file '#{File.basename(e.file)}'" : '')
28
- raise ValidationError, message
29
- end
30
- end
31
-
32
- private
33
-
34
- # Get Nokogiri::XML::Schema object to validate against
35
- # @return Nokogiri::XML::Schema
36
- def schema_validator
37
- return @schema_validator if @schema_validator
38
-
39
- if !imported_xsd.empty?
40
- # imports are explicitly provided - put all files in one tmpdir and update import paths appropriately
41
- # TODO: save file/path map to display in errors
42
- Dir.mktmpdir('XSD', tmp_dir) do |dir|
43
- # create primary xsd file
44
- file = "#{SecureRandom.urlsafe_base64}.xsd"
45
-
46
- # create imported xsd files
47
- recursive_import_xsd(self, file, Set.new) do |f, data|
48
- File.write("#{dir}/#{f}", data)
49
- end
50
-
51
- # read schema from tmp file descriptor
52
- io = File.open("#{dir}/#{file}")
53
- @schema_validator = create_xml_schema(io)
54
- end
55
- else
56
- @schema_validator = create_xml_schema(self.xsd)
57
- end
58
-
59
- @schema_validator
60
- end
61
-
62
- # Сформировать имена файлов и содержимое XSD схем для корректной валидации
63
- # @param [XML] reader
64
- # @param [String] file
65
- # @param [Set] processed
66
- def recursive_import_xsd(reader, file, processed, &block)
67
- # handle recursion
68
- namespace = reader.schema.target_namespace
69
- return if processed.include?(namespace)
70
-
71
- processed.add(namespace)
72
-
73
- data = reader.xml
74
-
75
- reader.imports.each do |import|
76
- name = "#{SecureRandom.urlsafe_base64}.xsd"
77
- data = data.sub("schemaLocation=\"#{import.schema_location}\"", "schemaLocation=\"#{name}\"")
78
- recursive_import_xsd(import.imported_reader, name, processed, &block)
79
- end
80
-
81
- block.call(file, data)
82
- end
83
-
84
- # Create Nokogiri XML Schema instance with preconfigured options
85
- # @param [IO] io
86
- def create_xml_schema(io)
87
- Nokogiri::XML::Schema(io, Nokogiri::XML::ParseOptions.new.nononet)
88
- end
89
- end
90
- end