xsd 2.1.0 → 2.3.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile +1 -0
- data/lib/xsd/base_object.rb +33 -17
- data/lib/xsd/generator.rb +14 -9
- data/lib/xsd/objects/list.rb +1 -1
- data/lib/xsd/objects/schema.rb +122 -9
- data/lib/xsd/version.rb +1 -1
- data/lib/xsd/xml.rb +5 -15
- data/lib/xsd.rb +0 -1
- metadata +3 -4
- data/lib/xsd/validator.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dce377d21632c6a26b8cf654ec519d7fa7664a6518b136280433a1411580159c
|
4
|
+
data.tar.gz: 57ff6cd7eb787f93d1ab51b8ebcc170da4f9726105a584a3a9d69f24711fdd0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95c494a1699eee86c90989c1de42ef8f1532ea805273e1f35b2b7f2f6d68cc74f4a056ba1c71b5b3f3e9b7b80d9500b206fc684d4bddf4cb3563dda59d21fc48
|
7
|
+
data.tar.gz: d58a3a37ebd8104cbcd58eb416f127bd862f2c9e510bafafc83ffbefb257ce5ef1093d56db8a6ad0682137fbe9de04d67fa8d0e5d2b32f38a56e1b1a3fe0e0cc
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [2.3.0] - 2023-09-06
|
4
|
+
|
5
|
+
- Fixed reading of SimpleType in List
|
6
|
+
- Add support for Restriction without base
|
7
|
+
- Support Any generation in simple scenarios
|
8
|
+
|
9
|
+
## [2.2.0] - 2023-07-10
|
10
|
+
|
11
|
+
- Fixed built-in types detection for unprefixed schema namespace
|
12
|
+
- Move validation to Schema object
|
13
|
+
|
3
14
|
## [2.1.0] - 2023-07-10
|
4
15
|
|
5
16
|
- Add support for <xs:include> element
|
data/Gemfile
CHANGED
data/lib/xsd/base_object.rb
CHANGED
@@ -32,14 +32,6 @@ module XSD
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
# Optional. Specifies a unique ID for the element
|
36
|
-
# @!attribute id
|
37
|
-
# @return String
|
38
|
-
# property :id, :string
|
39
|
-
def id
|
40
|
-
node['id']
|
41
|
-
end
|
42
|
-
|
43
35
|
def initialize(options = {})
|
44
36
|
@options = options
|
45
37
|
@cache = {}
|
@@ -53,6 +45,20 @@ module XSD
|
|
53
45
|
options[:node]
|
54
46
|
end
|
55
47
|
|
48
|
+
# Get object string representation
|
49
|
+
# @return String
|
50
|
+
def inspect
|
51
|
+
"#<#{self.class.name} path=#{node.path}>"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Optional. Specifies a unique ID for the element
|
55
|
+
# @!attribute id
|
56
|
+
# @return String
|
57
|
+
# property :id, :string
|
58
|
+
def id
|
59
|
+
node['id']
|
60
|
+
end
|
61
|
+
|
56
62
|
# Get current namespaces
|
57
63
|
# @return Hash
|
58
64
|
def namespaces
|
@@ -62,20 +68,20 @@ module XSD
|
|
62
68
|
# Get child nodes
|
63
69
|
# @param [Symbol] name
|
64
70
|
# @return Nokogiri::XML::NodeSet
|
65
|
-
def nodes(name =
|
66
|
-
node.xpath("
|
71
|
+
def nodes(name = :*, deep = false)
|
72
|
+
node.xpath("./#{deep ? '/' : ''}xs:#{name}", { 'xs' => XML_SCHEMA })
|
67
73
|
end
|
68
74
|
|
69
|
-
# Get
|
70
|
-
# @param [String, nil]
|
75
|
+
# Get schemas by namespace or prefix
|
76
|
+
# @param [String, nil] ns_or_prefix
|
71
77
|
# @return Array<Schema>
|
72
|
-
def schemas_for_namespace(
|
73
|
-
if schema.targets_namespace?(
|
78
|
+
def schemas_for_namespace(ns_or_prefix)
|
79
|
+
if schema.targets_namespace?(ns_or_prefix)
|
74
80
|
[schema, *schema.includes.map(&:imported_schema)]
|
75
|
-
elsif (import = schema.import_by_namespace(
|
81
|
+
elsif (import = schema.import_by_namespace(ns_or_prefix))
|
76
82
|
[import.imported_schema]
|
77
83
|
else
|
78
|
-
raise Error, "Schema not found for namespace '#{
|
84
|
+
raise Error, "Schema not found for namespace '#{ns_or_prefix}' in '#{schema.id || schema.target_namespace}'"
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
@@ -187,7 +193,7 @@ module XSD
|
|
187
193
|
# @param [Nokogiri::XML::Node] node
|
188
194
|
# @return Array<String>
|
189
195
|
def documentation_for(node)
|
190
|
-
node.xpath('./xs:annotation/xs:documentation/text()', { 'xs' => XML_SCHEMA }).map
|
196
|
+
node.xpath('./xs:annotation/xs:documentation/text()', { 'xs' => XML_SCHEMA }).map { |x| x.to_s.strip }
|
191
197
|
end
|
192
198
|
|
193
199
|
# Get all available elements on the current stack level
|
@@ -315,6 +321,9 @@ module XSD
|
|
315
321
|
name = link[:property] ? send(link[:property]) : nil
|
316
322
|
if name
|
317
323
|
return @cache[method] = object_by_name(link[:type], name)
|
324
|
+
elsif is_a?(Restriction) && method == :base_simple_type
|
325
|
+
# handle restriction without base
|
326
|
+
return nil
|
318
327
|
end
|
319
328
|
end
|
320
329
|
|
@@ -346,5 +355,12 @@ module XSD
|
|
346
355
|
name.to_sym
|
347
356
|
end
|
348
357
|
end
|
358
|
+
|
359
|
+
# Return string if it is not empty, or nil otherwise
|
360
|
+
# @param [String, nil] string
|
361
|
+
# @return String, nil
|
362
|
+
def nil_if_empty(string)
|
363
|
+
string&.empty? ? nil : string
|
364
|
+
end
|
349
365
|
end
|
350
366
|
end
|
data/lib/xsd/generator.rb
CHANGED
@@ -59,13 +59,13 @@ module XSD
|
|
59
59
|
# configure namespaces
|
60
60
|
# TODO: попытаться использовать collect_namespaces?
|
61
61
|
attributes = {}
|
62
|
-
|
62
|
+
all_attributes = element.collect_attributes
|
63
63
|
if element.complex?
|
64
|
-
|
64
|
+
all_elements = element.collect_elements
|
65
65
|
|
66
66
|
# get namespaces for current element and it's children
|
67
67
|
prefix = nil
|
68
|
-
[*
|
68
|
+
[*all_elements, element].each do |elem|
|
69
69
|
prefix = get_namespace_prefix(elem, attributes, namespaces)
|
70
70
|
end
|
71
71
|
else
|
@@ -75,7 +75,7 @@ module XSD
|
|
75
75
|
# iterate through each item
|
76
76
|
data.each do |item|
|
77
77
|
# prepare attributes
|
78
|
-
|
78
|
+
all_attributes.each do |attribute|
|
79
79
|
value = item["@#{attribute.name}"]
|
80
80
|
if value
|
81
81
|
attributes[attribute.name] = value
|
@@ -88,13 +88,18 @@ module XSD
|
|
88
88
|
if element.complex?
|
89
89
|
# generate tag recursively
|
90
90
|
xml.tag!("#{prefix}:#{element.name}", attributes) do
|
91
|
-
|
91
|
+
all_elements.each do |elem|
|
92
92
|
build_element(xml, elem, item, namespaces.dup)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
else
|
96
|
-
|
97
|
-
|
96
|
+
has_text = item.is_a?(Hash)
|
97
|
+
if has_text && element.complex_type&.nodes(:any, true)&.any?
|
98
|
+
xml.tag!("#{prefix}:#{element.name}", attributes) { |res| res << item['#text'].to_s }
|
99
|
+
else
|
100
|
+
value = has_text ? item['#text'] : item
|
101
|
+
xml.tag!("#{prefix}:#{element.name}", attributes, (value == '' ? nil : value))
|
102
|
+
end
|
98
103
|
end
|
99
104
|
end
|
100
105
|
end
|
@@ -108,7 +113,7 @@ module XSD
|
|
108
113
|
namespace = (element.referenced? ? element.reference : element).target_namespace
|
109
114
|
prefix = namespaces.key(namespace)
|
110
115
|
unless prefix
|
111
|
-
prefix = "
|
116
|
+
prefix = "n#{@namespace_index += 1}"
|
112
117
|
namespaces[prefix] = attributes["xmlns:#{prefix}"] = namespace
|
113
118
|
end
|
114
119
|
|
@@ -119,7 +124,7 @@ module XSD
|
|
119
124
|
# @param [String, Array<String>, nil] lookup
|
120
125
|
def find_root_element(lookup)
|
121
126
|
if lookup
|
122
|
-
element =
|
127
|
+
element = self[*lookup]
|
123
128
|
raise Error, "Cant find start element #{lookup}" unless element.is_a?(Element)
|
124
129
|
|
125
130
|
element
|
data/lib/xsd/objects/list.rb
CHANGED
data/lib/xsd/objects/schema.rb
CHANGED
@@ -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
|
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.
|
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
|
@@ -151,11 +154,121 @@ module XSD
|
|
151
154
|
end.compact.flatten
|
152
155
|
end
|
153
156
|
|
154
|
-
# Get import by namespace
|
157
|
+
# Get import by namespace or prefix
|
158
|
+
# @param [String, nil] ns_or_prefix
|
155
159
|
# @return Import
|
156
|
-
def import_by_namespace(
|
157
|
-
aliases = [
|
160
|
+
def import_by_namespace(ns_or_prefix)
|
161
|
+
aliases = [
|
162
|
+
ns_or_prefix,
|
163
|
+
namespaces["xmlns:#{(ns_or_prefix || '').gsub(/^xmlns:/, '')}"]
|
164
|
+
].compact
|
165
|
+
|
158
166
|
imports.find { |import| aliases.include?(import.namespace) }
|
159
167
|
end
|
168
|
+
|
169
|
+
# Validate XML against current schema
|
170
|
+
# @param [String, Pathname, Nokogiri::XML::Document] xml
|
171
|
+
def validate_xml(xml)
|
172
|
+
# validate input
|
173
|
+
raise ValidationError unless xml.is_a?(Nokogiri::XML::Document) || xml.is_a?(Pathname) || xml.is_a?(String)
|
174
|
+
|
175
|
+
begin
|
176
|
+
document = xml.is_a?(Nokogiri::XML::Document) ? xml : Nokogiri::XML(xml)
|
177
|
+
rescue Nokogiri::XML::SyntaxError => e
|
178
|
+
raise ValidationError, e
|
179
|
+
end
|
180
|
+
|
181
|
+
errors = schema_validator.validate(document)
|
182
|
+
raise ValidationError, errors.map(&:message).join('; ') if errors.any?
|
183
|
+
end
|
184
|
+
|
185
|
+
# Validate current schema against XMLSchema 1.0
|
186
|
+
def validate
|
187
|
+
begin
|
188
|
+
schema_validator
|
189
|
+
rescue Nokogiri::XML::SyntaxError => e
|
190
|
+
# TODO: display import map name for imported_xsd
|
191
|
+
message = e.message + (e.file ? " in file '#{File.basename(e.file)}'" : '')
|
192
|
+
raise ValidationError, message
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# Get Nokogiri::XML::Schema object to validate against
|
199
|
+
# @return Nokogiri::XML::Schema
|
200
|
+
def schema_validator
|
201
|
+
return @schema_validator if @schema_validator
|
202
|
+
|
203
|
+
# if !imported_xsd.empty?
|
204
|
+
# imports are explicitly provided - put all files in one tmpdir and update import paths appropriately
|
205
|
+
# TODO: save file/path map to display in errors
|
206
|
+
Dir.mktmpdir('XSD', reader.tmp_dir) do |dir|
|
207
|
+
# create primary xsd file
|
208
|
+
file = "#{::SecureRandom.urlsafe_base64}.xsd"
|
209
|
+
|
210
|
+
# create imported xsd files
|
211
|
+
recursive_import_xsd(self, file, Set.new) do |f, data|
|
212
|
+
File.write("#{dir}/#{f}", data)
|
213
|
+
end
|
214
|
+
|
215
|
+
# read schema from tmp file descriptor
|
216
|
+
io = File.open("#{dir}/#{file}")
|
217
|
+
@schema_validator = create_xml_schema(io)
|
218
|
+
end
|
219
|
+
# else
|
220
|
+
# @schema_validator = create_xml_schema(schema.node.to_xml)
|
221
|
+
# end
|
222
|
+
|
223
|
+
@schema_validator
|
224
|
+
end
|
225
|
+
|
226
|
+
# Сформировать имена файлов и содержимое XSD схем для корректной валидации
|
227
|
+
# @param [Schema] schema
|
228
|
+
# @param [String] file
|
229
|
+
# @param [Set] processed
|
230
|
+
def recursive_import_xsd(schema, file, processed, &block)
|
231
|
+
# handle recursion
|
232
|
+
return if processed.include?(schema.target_namespace)
|
233
|
+
|
234
|
+
processed.add(schema.target_namespace)
|
235
|
+
|
236
|
+
# prepare schema XML with all namespaces included, clone node to avoid mutating original schema
|
237
|
+
node = schema.node
|
238
|
+
if node.namespaces.size != node.namespace_definitions.size
|
239
|
+
prefixes = node.namespace_definitions.map(&:prefix)
|
240
|
+
node = schema.node.dup
|
241
|
+
|
242
|
+
schema.node.namespaces.each do |attr, ns|
|
243
|
+
prefix = attr == 'xmlns' ? nil : attr.sub('xmlns:', '')
|
244
|
+
# does not work!
|
245
|
+
# node.add_namespace_definition(prefix, ns) unless prefixes.include?(prefix)
|
246
|
+
node[attr] = ns unless prefixes.include?(prefix)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
data = node.to_xml
|
251
|
+
|
252
|
+
schema.imports.each do |import|
|
253
|
+
name = "#{::SecureRandom.urlsafe_base64}.xsd"
|
254
|
+
location = import.schema_location
|
255
|
+
namespace = import.namespace
|
256
|
+
|
257
|
+
if location
|
258
|
+
data = data.sub("schemaLocation=\"#{location}\"", "schemaLocation=\"#{name}\"")
|
259
|
+
else
|
260
|
+
data = data.sub("namespace=\"#{namespace}\"", "namespace=\"#{namespace}\" schemaLocation=\"#{name}\"")
|
261
|
+
end
|
262
|
+
recursive_import_xsd(import.imported_schema, name, processed, &block)
|
263
|
+
end
|
264
|
+
|
265
|
+
block.call(file, data)
|
266
|
+
end
|
267
|
+
|
268
|
+
# Create Nokogiri XML Schema instance with preconfigured options
|
269
|
+
# @param [IO, String] io
|
270
|
+
def create_xml_schema(io)
|
271
|
+
Nokogiri::XML::Schema(io, Nokogiri::XML::ParseOptions.new.nononet)
|
272
|
+
end
|
160
273
|
end
|
161
274
|
end
|
data/lib/xsd/version.rb
CHANGED
data/lib/xsd/xml.rb
CHANGED
@@ -6,9 +6,8 @@ require 'net/http'
|
|
6
6
|
module XSD
|
7
7
|
class XML
|
8
8
|
include Generator
|
9
|
-
include Validator
|
10
9
|
|
11
|
-
attr_reader :options, :object_cache, :schemas
|
10
|
+
attr_reader :options, :object_cache, :schemas
|
12
11
|
|
13
12
|
DEFAULT_RESOURCE_RESOLVER = proc do |location, namespace|
|
14
13
|
if location =~ /^https?:/
|
@@ -75,10 +74,9 @@ module XSD
|
|
75
74
|
end
|
76
75
|
|
77
76
|
def initialize(**options)
|
78
|
-
@options
|
79
|
-
@object_cache
|
80
|
-
@schemas
|
81
|
-
@namespace_prefixes = {}
|
77
|
+
@options = options
|
78
|
+
@object_cache = {}
|
79
|
+
@schemas = []
|
82
80
|
end
|
83
81
|
|
84
82
|
def logger
|
@@ -116,24 +114,16 @@ module XSD
|
|
116
114
|
new_schema
|
117
115
|
end
|
118
116
|
|
119
|
-
# Add prefixes defined outside of processed schemas, for example in WSDL document
|
120
|
-
# @param [String] prefix
|
121
|
-
# @param [String] namespace
|
122
|
-
def add_namespace_prefix(prefix, namespace)
|
123
|
-
@namespace_prefixes[prefix] = namespace
|
124
|
-
end
|
125
|
-
|
126
117
|
# Get first added (considered primary) schema
|
127
118
|
# @return Schema, nil
|
128
119
|
def schema
|
129
120
|
schemas.first
|
130
121
|
end
|
131
122
|
|
132
|
-
# Get
|
123
|
+
# Get schemas by namespace
|
133
124
|
# @param [String, nil] namespace
|
134
125
|
# @return Array<Schema>
|
135
126
|
def schemas_for_namespace(namespace)
|
136
|
-
namespace = namespace_prefixes[namespace] if namespace_prefixes.key?(namespace)
|
137
127
|
schemas.select { |schema| schema.target_namespace == namespace }
|
138
128
|
end
|
139
129
|
|
data/lib/xsd.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xsd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- d.arkhipov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: builder
|
@@ -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
|
@@ -135,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
134
|
- !ruby/object:Gem::Version
|
136
135
|
version: '0'
|
137
136
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
137
|
+
rubygems_version: 3.4.10
|
139
138
|
signing_key:
|
140
139
|
specification_version: 4
|
141
140
|
summary: The Ruby XSD library is an XML Schema implementation for Ruby.
|
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
|