xsd 2.1.0 → 2.2.0

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 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