xsd 1.0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +124 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/Makefile +7 -0
- data/README.md +68 -0
- data/Rakefile +25 -0
- data/lib/xsd/base_object.rb +347 -0
- data/lib/xsd/exceptions.rb +12 -0
- data/lib/xsd/generator.rb +137 -0
- data/lib/xsd/objects/all.rb +22 -0
- data/lib/xsd/objects/annotation.rb +19 -0
- data/lib/xsd/objects/any.rb +31 -0
- data/lib/xsd/objects/any_attribute.rb +30 -0
- data/lib/xsd/objects/appinfo.rb +13 -0
- data/lib/xsd/objects/attribute.rb +72 -0
- data/lib/xsd/objects/attribute_group.rb +18 -0
- data/lib/xsd/objects/choice.rb +33 -0
- data/lib/xsd/objects/complex_content.rb +25 -0
- data/lib/xsd/objects/complex_type.rb +82 -0
- data/lib/xsd/objects/documentation.rb +18 -0
- data/lib/xsd/objects/element.rb +130 -0
- data/lib/xsd/objects/extension.rb +14 -0
- data/lib/xsd/objects/facet.rb +12 -0
- data/lib/xsd/objects/field.rb +13 -0
- data/lib/xsd/objects/group.rb +32 -0
- data/lib/xsd/objects/import.rb +67 -0
- data/lib/xsd/objects/key.rb +25 -0
- data/lib/xsd/objects/keyref.rb +33 -0
- data/lib/xsd/objects/list.rb +18 -0
- data/lib/xsd/objects/restriction.rb +49 -0
- data/lib/xsd/objects/schema.rb +155 -0
- data/lib/xsd/objects/selector.rb +15 -0
- data/lib/xsd/objects/sequence.rb +33 -0
- data/lib/xsd/objects/simple_content.rb +19 -0
- data/lib/xsd/objects/simple_type.rb +35 -0
- data/lib/xsd/objects/union.rb +23 -0
- data/lib/xsd/objects/unique.rb +18 -0
- data/lib/xsd/shared/attribute_container.rb +17 -0
- data/lib/xsd/shared/based.rb +37 -0
- data/lib/xsd/shared/complex_typed.rb +28 -0
- data/lib/xsd/shared/element_container.rb +12 -0
- data/lib/xsd/shared/min_max_occurs.rb +46 -0
- data/lib/xsd/shared/referenced.rb +24 -0
- data/lib/xsd/shared/simple_typed.rb +14 -0
- data/lib/xsd/validator.rb +90 -0
- data/lib/xsd/version.rb +5 -0
- data/lib/xsd/xml.rb +111 -0
- data/lib/xsd.rb +42 -0
- data/xsd.gemspec +45 -0
- metadata +239 -0
@@ -0,0 +1,347 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# Base object
|
5
|
+
class BaseObject
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
# Objects that can not have nested elements
|
9
|
+
NO_ELEMENTS_CONTAINER = %i[annotation simpleType attributeGroup attribute
|
10
|
+
unique union simpleContent list any anyAttribute key keyref].freeze
|
11
|
+
|
12
|
+
# Objects that cannot have nested attributes
|
13
|
+
NO_ATTRIBUTES_CONTAINER = %i[annotation unique anyAttribute all
|
14
|
+
attribute choice sequence group simpleType facet key keyref].freeze
|
15
|
+
|
16
|
+
# Base XMLSchema namespace
|
17
|
+
XML_SCHEMA = 'http://www.w3.org/2001/XMLSchema'
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_reader :properties, :children, :links
|
21
|
+
|
22
|
+
def properties
|
23
|
+
@properties ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def links
|
27
|
+
@links ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def children
|
31
|
+
@children ||= {}
|
32
|
+
end
|
33
|
+
end
|
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
|
+
def initialize(options = {})
|
44
|
+
@options = options
|
45
|
+
@cache = {}
|
46
|
+
|
47
|
+
raise Error, "#{self.class}.new expects a hash parameter" unless @options.is_a?(Hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get current XML node
|
51
|
+
# @return [Nokogiri::XML::Node]
|
52
|
+
def node
|
53
|
+
options[:node]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get current namespaces
|
57
|
+
# @return [Hash]
|
58
|
+
def namespaces
|
59
|
+
node.namespaces || {}
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get child nodes
|
63
|
+
# @param [Symbol] name
|
64
|
+
# @return [Nokogiri::XML::NodeSet]
|
65
|
+
def nodes(name = :*)
|
66
|
+
node.xpath("./xs:#{name}", { 'xs' => XML_SCHEMA })
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get schema object for specified namespace prefix
|
70
|
+
# @param [String] prefix
|
71
|
+
# @return [Schema]
|
72
|
+
def schema_for_namespace(prefix)
|
73
|
+
if schema.targets_namespace?(prefix)
|
74
|
+
schema
|
75
|
+
elsif (import = schema.import_by_namespace(prefix))
|
76
|
+
import.imported_reader.schema
|
77
|
+
else
|
78
|
+
raise Error, "Schema not found for namespace '#{prefix}' in '#{schema.id || schema.target_namespace}'"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get element or attribute by path
|
83
|
+
# @return [Element, Attribute, nil]
|
84
|
+
def [](*args)
|
85
|
+
result = self
|
86
|
+
|
87
|
+
args.flatten.each do |curname|
|
88
|
+
next if result.nil?
|
89
|
+
|
90
|
+
curname = curname.to_s
|
91
|
+
|
92
|
+
if curname[0] == '@'
|
93
|
+
result = result.all_attributes.find { |attr| attr.name == curname[1..-1] }
|
94
|
+
else
|
95
|
+
result = result.all_elements.find { |elem| elem.name == curname }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
result
|
100
|
+
end
|
101
|
+
|
102
|
+
# Search node by name in all available schemas and return its object
|
103
|
+
# @param [Symbol] node_name
|
104
|
+
# @param [String] name
|
105
|
+
# @return [BaseObject, nil]
|
106
|
+
def object_by_name(node_name, name)
|
107
|
+
# get prefix and local name
|
108
|
+
name_prefix = get_prefix(name)
|
109
|
+
name_local = strip_prefix(name)
|
110
|
+
|
111
|
+
# do not search for built-in types
|
112
|
+
return nil if schema.namespace_prefix == name_prefix
|
113
|
+
|
114
|
+
# determine schema for namespace
|
115
|
+
search_schema = schema_for_namespace(name_prefix)
|
116
|
+
|
117
|
+
# find element in target schema
|
118
|
+
result = search_schema.node.xpath("./xs:#{node_name}[@name=\"#{name_local}\"]", { 'xs' => XML_SCHEMA }).first
|
119
|
+
|
120
|
+
result ? search_schema.node_to_object(result) : nil
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get reader object for node
|
124
|
+
# @param [Nokogiri::XML::Node]
|
125
|
+
# @return [BaseObject]
|
126
|
+
def node_to_object(node)
|
127
|
+
# check object in cache first
|
128
|
+
# TODO: проверить работу!
|
129
|
+
return reader.object_cache[node.object_id] if reader.object_cache[node.object_id]
|
130
|
+
|
131
|
+
klass = XML::CLASS_MAP[node.name]
|
132
|
+
raise Error, "Object class not found for '#{node.name}'" unless klass
|
133
|
+
|
134
|
+
reader.object_cache[node.object_id] = klass.new(options.merge(node: node, schema: schema))
|
135
|
+
end
|
136
|
+
|
137
|
+
# Get xml parent object
|
138
|
+
# @return [BaseObject, nil]
|
139
|
+
def parent
|
140
|
+
node.respond_to?(:parent) && node.parent ? node_to_object(node.parent) : nil
|
141
|
+
end
|
142
|
+
|
143
|
+
# Get current schema object
|
144
|
+
# @return [Schema]
|
145
|
+
def schema
|
146
|
+
options[:schema]
|
147
|
+
end
|
148
|
+
|
149
|
+
# Get child objects
|
150
|
+
# @param [Symbol] name
|
151
|
+
# @return [Array<BaseObject>]
|
152
|
+
def map_children(name)
|
153
|
+
nodes(name).map { |node| node_to_object(node) }
|
154
|
+
end
|
155
|
+
|
156
|
+
# Get child object
|
157
|
+
# @param [Symbol] name
|
158
|
+
# @return [BaseObject, nil]
|
159
|
+
def map_child(name)
|
160
|
+
map_children(name).first
|
161
|
+
end
|
162
|
+
|
163
|
+
# Strip namespace prefix from node name
|
164
|
+
# @param [String, nil] name Name to strip from
|
165
|
+
# @return [String, nil]
|
166
|
+
def strip_prefix(name)
|
167
|
+
name&.include?(':') ? name.split(':').last : name
|
168
|
+
end
|
169
|
+
|
170
|
+
# Get namespace prefix from node name
|
171
|
+
# @param [String, nil] name Name to strip from
|
172
|
+
# @return [String]
|
173
|
+
def get_prefix(name)
|
174
|
+
name&.include?(':') ? name.split(':').first : ''
|
175
|
+
end
|
176
|
+
|
177
|
+
# Return element documentation
|
178
|
+
# @return [Array<String>]
|
179
|
+
def documentation
|
180
|
+
documentation_for(node)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Return documentation for specified node
|
184
|
+
# @param [Nokogiri::XML::Node] node
|
185
|
+
# @return [Array<String>]
|
186
|
+
def documentation_for(node)
|
187
|
+
node.xpath('./xs:annotation/xs:documentation/text()', { 'xs' => XML_SCHEMA }).map(&:to_s).map(&:strip)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Get all available elements on the current stack level
|
191
|
+
# @return [Array<Element>]
|
192
|
+
def all_elements(*)
|
193
|
+
# exclude element that can not have elements
|
194
|
+
return [] if NO_ELEMENTS_CONTAINER.include?(self.class.mapped_name)
|
195
|
+
|
196
|
+
if is_a?(Referenced) && ref
|
197
|
+
reference.all_elements
|
198
|
+
else
|
199
|
+
# map children recursive
|
200
|
+
map_children(:*).map do |obj|
|
201
|
+
if obj.is_a?(Element)
|
202
|
+
obj
|
203
|
+
else
|
204
|
+
# get elements considering references
|
205
|
+
(obj.is_a?(Referenced) && obj.ref ? obj.reference : obj).all_elements
|
206
|
+
end
|
207
|
+
end.flatten
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Get all available attributes on the current stack level
|
212
|
+
# @return [Array<Attribute>]
|
213
|
+
def all_attributes(*)
|
214
|
+
# exclude element that can not have elements
|
215
|
+
return [] if NO_ATTRIBUTES_CONTAINER.include?(self.class.mapped_name)
|
216
|
+
|
217
|
+
if is_a?(Referenced) && ref
|
218
|
+
reference.all_attributes
|
219
|
+
else
|
220
|
+
# map children recursive
|
221
|
+
map_children(:*).map do |obj|
|
222
|
+
if obj.is_a?(Attribute)
|
223
|
+
obj
|
224
|
+
else
|
225
|
+
# get attributes considering references
|
226
|
+
(obj.is_a?(Referenced) && obj.ref ? obj.reference : obj).all_attributes
|
227
|
+
end
|
228
|
+
end.flatten
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Get reader instance
|
233
|
+
# @return [XML]
|
234
|
+
def reader
|
235
|
+
options[:reader]
|
236
|
+
end
|
237
|
+
|
238
|
+
protected
|
239
|
+
|
240
|
+
def self.to_underscore(string)
|
241
|
+
string.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').sub(':', '_').downcase.to_sym
|
242
|
+
end
|
243
|
+
|
244
|
+
# Define new object property
|
245
|
+
# @param [Symbol] name
|
246
|
+
# @param [Symbol] type
|
247
|
+
# @param [Hash] options
|
248
|
+
def self.property(name, type, options = {}, &block)
|
249
|
+
properties[to_underscore(name)] = {
|
250
|
+
name: name,
|
251
|
+
type: type,
|
252
|
+
resolve: block,
|
253
|
+
**options
|
254
|
+
}
|
255
|
+
end
|
256
|
+
|
257
|
+
# Define new object child
|
258
|
+
# @param [Symbol] name
|
259
|
+
# @param [Symbol, Array<Symbol>] type
|
260
|
+
# @param [Hash] options
|
261
|
+
def self.child(name, type, options = {})
|
262
|
+
children[to_underscore(name)] = {
|
263
|
+
type: type,
|
264
|
+
**options
|
265
|
+
}
|
266
|
+
end
|
267
|
+
|
268
|
+
# Define new object child
|
269
|
+
# @param [Symbol] name
|
270
|
+
# @param [Symbol] type
|
271
|
+
# @param [Hash] options
|
272
|
+
def self.link(name, type, options = {})
|
273
|
+
links[to_underscore(name)] = {
|
274
|
+
type: type,
|
275
|
+
**options
|
276
|
+
}
|
277
|
+
end
|
278
|
+
|
279
|
+
# Lookup for properties
|
280
|
+
# @param [Symbol] method
|
281
|
+
# @param [Array] args
|
282
|
+
def method_missing(method, *args)
|
283
|
+
# check cache first
|
284
|
+
return @cache[method] if @cache[method]
|
285
|
+
|
286
|
+
# check for property first
|
287
|
+
if (property = self.class.properties[method])
|
288
|
+
value = property[:resolve] ? property[:resolve].call(self) : node[property[:name].to_s]
|
289
|
+
result = if value.nil?
|
290
|
+
# if object has reference - search property in referenced object
|
291
|
+
node['ref'] ? reference.send(method, *args) : property[:default]
|
292
|
+
else
|
293
|
+
case property[:type]
|
294
|
+
when :integer
|
295
|
+
property[:name] == :maxOccurs && value == 'unbounded' ? :unbounded : value.to_i
|
296
|
+
when :boolean
|
297
|
+
!!value
|
298
|
+
else
|
299
|
+
value
|
300
|
+
end
|
301
|
+
end
|
302
|
+
return @cache[method] = result
|
303
|
+
end
|
304
|
+
|
305
|
+
# if object has ref it cannot contain any type and children, so proxy call to target object
|
306
|
+
if node['ref'] && method != :ref && method != :reference
|
307
|
+
return reference.send(method, *args)
|
308
|
+
end
|
309
|
+
|
310
|
+
# then check for linked types
|
311
|
+
if (link = self.class.links[method])
|
312
|
+
name = link[:property] ? send(link[:property]) : nil
|
313
|
+
if name
|
314
|
+
return @cache[method] = object_by_name(link[:type], name)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# last check for nested objects
|
319
|
+
if (child = self.class.children[method])
|
320
|
+
result = child[:type].is_a?(Array) ? map_children(child[:type][0]) : map_child(child[:type])
|
321
|
+
return @cache[method] = result
|
322
|
+
end
|
323
|
+
|
324
|
+
super
|
325
|
+
# api = self.class.properties.keys + self.class.links.keys + self.class.children.keys
|
326
|
+
# raise Error, "Tried to access unknown object '#{method}' on '#{self.class.name}'. Available options are: #{api}"
|
327
|
+
end
|
328
|
+
|
329
|
+
# Does object has property/link/child?
|
330
|
+
# @param [Symbol] method
|
331
|
+
# @param [Array] args
|
332
|
+
def respond_to_missing?(method, *args)
|
333
|
+
self.class.properties[method] || self.class.links[method] || self.class.children[method] || super
|
334
|
+
end
|
335
|
+
|
336
|
+
# Get mapped element name
|
337
|
+
# @return [Symbol]
|
338
|
+
def self.mapped_name
|
339
|
+
# @mapped_name ||= XML::CLASS_MAP.each { |k, v| return k.to_sym if v == self }
|
340
|
+
@mapped_name ||= begin
|
341
|
+
name = self.name.split('::').last
|
342
|
+
name[0] = name[0].downcase
|
343
|
+
name.to_sym
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'builder'
|
4
|
+
|
5
|
+
module XSD
|
6
|
+
module Generator
|
7
|
+
# Generate XML from provided data
|
8
|
+
# @param [Hash] data
|
9
|
+
# @param [String, Array<String>] element
|
10
|
+
# @param [Builder::XmlMarkup] builder
|
11
|
+
# @return [Builder::XmlMarkup]
|
12
|
+
def generate(data, element = nil, builder = nil)
|
13
|
+
# find root element
|
14
|
+
root = find_root_element(element)
|
15
|
+
|
16
|
+
# create builder
|
17
|
+
builder ||= default_builder
|
18
|
+
|
19
|
+
# build element tree
|
20
|
+
@namespace_index = 0
|
21
|
+
build_element(builder, root, data)
|
22
|
+
|
23
|
+
builder
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Build element tree
|
29
|
+
# @param [Builder::XmlMarkup] xml
|
30
|
+
# @param [Element] element
|
31
|
+
# @param [Hash] data
|
32
|
+
# @param [Hash] namespaces
|
33
|
+
def build_element(xml, element, data, namespaces = {})
|
34
|
+
# get item data
|
35
|
+
elements = (element.abstract ? [] : [element]) + element.substitution_elements
|
36
|
+
provided_element = elements.find { |elem| !data[elem.name].nil? }
|
37
|
+
|
38
|
+
if element.required? && provided_element.nil?
|
39
|
+
raise Error, "Element #{element.name} is required, but no data in provided for it"
|
40
|
+
end
|
41
|
+
return unless provided_element
|
42
|
+
|
43
|
+
element = provided_element
|
44
|
+
data = data[element.name]
|
45
|
+
|
46
|
+
# handle repeated items
|
47
|
+
if element.multiple_allowed?
|
48
|
+
unless data.is_a?(Array)
|
49
|
+
raise Error, "Element #{element.name} is allowed to occur multiple times, but non-array is provided"
|
50
|
+
end
|
51
|
+
else
|
52
|
+
if data.is_a?(Array)
|
53
|
+
raise Error, "Element #{element.name} is not allowed to occur multiple times, but an array is provided"
|
54
|
+
end
|
55
|
+
|
56
|
+
data = [data]
|
57
|
+
end
|
58
|
+
|
59
|
+
# configure namespaces
|
60
|
+
# TODO: попытаться использовать collect_namespaces?
|
61
|
+
attributes = {}
|
62
|
+
all_attributes = element.all_attributes
|
63
|
+
if element.complex?
|
64
|
+
all_elements = element.all_elements
|
65
|
+
|
66
|
+
# get namespaces for current element and it's children
|
67
|
+
prefix = nil
|
68
|
+
[*all_elements, element].each do |elem|
|
69
|
+
prefix = get_namespace_prefix(elem, attributes, namespaces)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
prefix = get_namespace_prefix(element, attributes, namespaces)
|
73
|
+
end
|
74
|
+
|
75
|
+
# iterate through each item
|
76
|
+
data.each do |item|
|
77
|
+
# prepare attributes
|
78
|
+
all_attributes.each do |attribute|
|
79
|
+
value = item["@#{attribute.name}"]
|
80
|
+
if value
|
81
|
+
attributes[attribute.name] = value
|
82
|
+
else
|
83
|
+
attributes.delete(attribute.name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# generate element
|
88
|
+
if element.complex?
|
89
|
+
# generate tag recursively
|
90
|
+
xml.tag!("#{prefix}:#{element.name}", attributes) do
|
91
|
+
all_elements.each do |elem|
|
92
|
+
build_element(xml, elem, item, namespaces.dup)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
value = item.is_a?(Hash) ? item['#text'] : item
|
97
|
+
xml.tag!("#{prefix}:#{element.name}", attributes, (value == '' ? nil : value))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get namespace prefix for element
|
103
|
+
# @param [Element] element
|
104
|
+
# @param [Hash] attributes
|
105
|
+
# @param [Hash] namespaces
|
106
|
+
# @return [String]
|
107
|
+
def get_namespace_prefix(element, attributes, namespaces)
|
108
|
+
namespace = (element.referenced? ? element.reference : element).target_namespace
|
109
|
+
prefix = namespaces.key(namespace)
|
110
|
+
unless prefix
|
111
|
+
prefix = "tns#{@namespace_index += 1}"
|
112
|
+
namespaces[prefix] = attributes["xmlns:#{prefix}"] = namespace
|
113
|
+
end
|
114
|
+
|
115
|
+
prefix
|
116
|
+
end
|
117
|
+
|
118
|
+
# Find root element with provided lookup
|
119
|
+
# @param [String, Array<String>, nil] lookup
|
120
|
+
def find_root_element(lookup)
|
121
|
+
if lookup
|
122
|
+
element = schema[*lookup]
|
123
|
+
raise Error, "Cant find start element #{lookup}" unless element.is_a?(Element)
|
124
|
+
|
125
|
+
element
|
126
|
+
else
|
127
|
+
raise Error, 'XSD contains more that one root element. Please, specify starting element' if elements.size > 1
|
128
|
+
|
129
|
+
elements.first
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def default_builder
|
134
|
+
Builder::XmlMarkup.new
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The all element specifies that the child elements can appear in any order and that each child element can
|
5
|
+
# occur zero or one time.
|
6
|
+
# Parent elements: group, complexType, restriction (both simpleContent and complexContent),
|
7
|
+
# extension (both simpleContent and complexContent)
|
8
|
+
# https://www.w3schools.com/xml/el_all.asp
|
9
|
+
class All < BaseObject
|
10
|
+
include ElementContainer
|
11
|
+
|
12
|
+
# Optional. Specifies the minimum number of times the element can occur. The value can be 0 or 1. Default value is 1
|
13
|
+
# @!attribute min_occurs
|
14
|
+
# @return [Integer]
|
15
|
+
property :minOccurs, :integer, default: 1
|
16
|
+
|
17
|
+
# Optional. Specifies the maximum number of times the element can occur. The value must be 1.
|
18
|
+
# @!attribute max_occurs
|
19
|
+
# @return [Integer]
|
20
|
+
property :maxOccurs, :integer, default: 1
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The annotation element is a top level element that specifies schema comments. The comments serve as inline
|
5
|
+
# documentation.
|
6
|
+
# Parent elements: Any element
|
7
|
+
# https://www.w3schools.com/xml/el_annotation.asp
|
8
|
+
class Annotation < BaseObject
|
9
|
+
# Nested appinfos
|
10
|
+
# @!attribute appinfos
|
11
|
+
# @return [Array<Appinfo>]
|
12
|
+
child :appinfos, [:appinfo]
|
13
|
+
|
14
|
+
# Nested documentations
|
15
|
+
# @!attribute documentations
|
16
|
+
# @return [Array<Documentation>]
|
17
|
+
child :documentations, [:documentation]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The any element enables the author to extend the XML document with elements not specified by the schema.
|
5
|
+
# Parent elements: choice, sequence
|
6
|
+
# https://www.w3schools.com/xml/el_any.asp
|
7
|
+
class Any < BaseObject
|
8
|
+
include MinMaxOccurs
|
9
|
+
|
10
|
+
# Optional. Specifies the namespaces containing the elements that can be used. Can be set to one of the following:
|
11
|
+
# ##any - elements from any namespace is allowed (this is default)
|
12
|
+
# ##other - elements from any namespace that is not the namespace of the parent element can be present
|
13
|
+
# ##local - elements must come from no namespace
|
14
|
+
# ##targetNamespace - elements from the namespace of the parent element can be present
|
15
|
+
# List of {URI references of namespaces, ##targetNamespace, ##local} - elements from a space-delimited list of
|
16
|
+
# the namespaces can be present
|
17
|
+
# @!attribute namespace
|
18
|
+
# @return [String]
|
19
|
+
property :namespace, :string, default: '##any'
|
20
|
+
|
21
|
+
# Optional. Specifies how the XML processor should handle validation against the elements specified by this any
|
22
|
+
# element. Can be set to one of the following:
|
23
|
+
# strict - the XML processor must obtain the schema
|
24
|
+
# for the required namespaces and validate the elements (this is default)
|
25
|
+
# lax - same as strict but; if the schema cannot be obtained, no errors will occur
|
26
|
+
# skip - The XML processor does not attempt to validate any elements from the specified namespaces
|
27
|
+
# @!attribute process_contents
|
28
|
+
# @return [String, nil]
|
29
|
+
property :processContents, :string, default: 'strict'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The anyAttribute element enables the author to extend the XML document with attributes not specified by the schema.
|
5
|
+
# Parent elements: complexType, restriction (both simpleContent and complexContent), extension (both simpleContent
|
6
|
+
# and complexContent), attributeGroup
|
7
|
+
# https://www.w3schools.com/xml/el_anyattribute.asp
|
8
|
+
class AnyAttribute < BaseObject
|
9
|
+
# Optional. Specifies the namespaces containing the attributes that can be used. Can be set to one of the following:
|
10
|
+
# ##any - attributes from any namespace is allowed (this is default)
|
11
|
+
# ##other - attributes from any namespace that is not the namespace of the parent element can be present
|
12
|
+
# ##local - attributes must come from no namespace
|
13
|
+
# ##targetNamespace - attributes from the namespace of the parent element can be present
|
14
|
+
# List of {URI references of namespaces, ##targetNamespace, ##local} - attributes from a space-delimited list
|
15
|
+
# of the namespaces can be present
|
16
|
+
# @!attribute namespace
|
17
|
+
# @return [String]
|
18
|
+
property :namespace, :string, default: '##any'
|
19
|
+
|
20
|
+
# Optional. Specifies how the XML processor should handle validation against the elements specified by this any
|
21
|
+
# element. Can be set to one of the following:
|
22
|
+
# strict - the XML processor must obtain the schema for the required namespaces and validate the elements (this
|
23
|
+
# is default)
|
24
|
+
# lax - same as strict but; if the schema cannot be obtained, no errors will occur
|
25
|
+
# skip - The XML processor does not attempt to validate any elements from the specified namespaces
|
26
|
+
# @!attribute process_contents
|
27
|
+
# @return [String, nil]
|
28
|
+
property :processContents, :string, default: 'strict'
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The appinfo element specifies information to be used by the application.
|
5
|
+
# Parent elements: annotation
|
6
|
+
# https://www.w3schools.com/xml/el_appinfo.asp
|
7
|
+
class Appinfo < BaseObject
|
8
|
+
# Optional. A URI reference that specifies the source of the application information
|
9
|
+
# @!attribute source
|
10
|
+
# @return [String]
|
11
|
+
property :source, :string
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XSD
|
4
|
+
# The attribute element defines an attribute.
|
5
|
+
# Parent elements: attributeGroup, schema, complexType, restriction (both simpleContent and complexContent),
|
6
|
+
# extension (both simpleContent and complexContent)
|
7
|
+
# https://www.w3schools.com/xml/el_attribute.asp
|
8
|
+
class Attribute < BaseObject
|
9
|
+
TYPE_PROPERTY = :type
|
10
|
+
|
11
|
+
include SimpleTyped
|
12
|
+
include Referenced
|
13
|
+
|
14
|
+
# Optional. Specifies the name of the attribute. Name and ref attributes cannot both be present
|
15
|
+
# @!attribute name
|
16
|
+
# @return [String]
|
17
|
+
property :name, :string
|
18
|
+
|
19
|
+
# Optional. Specifies a default value for the attribute. Default and fixed attributes cannot both be present
|
20
|
+
# @!attribute default
|
21
|
+
# @return [String, nil]
|
22
|
+
property :default, :string
|
23
|
+
|
24
|
+
# Optional. Specifies a fixed value for the attribute. Default and fixed attributes cannot both be present
|
25
|
+
# @!attribute fixed
|
26
|
+
# @return [String, nil]
|
27
|
+
property :fixed, :string
|
28
|
+
|
29
|
+
# Optional. Specifies the form for the attribute. The default value is the value of the attributeFormDefault
|
30
|
+
# attribute of the element containing the attribute. Can be set to one of the following:
|
31
|
+
# qualified - indicates that this attribute must be qualified with the namespace prefix and the no-colon-name
|
32
|
+
# (NCName) of the attribute
|
33
|
+
# unqualified - indicates that this attribute is not required to be qualified with the namespace prefix and is
|
34
|
+
# matched against the (NCName) of the attribute
|
35
|
+
# @!attribute form
|
36
|
+
# @return [String, nil]
|
37
|
+
# TODO: поддержка default значения с вычислением родителя
|
38
|
+
property :form, :string
|
39
|
+
|
40
|
+
# Optional. Specifies a built-in data type or a simple type. The type attribute can only be present when the
|
41
|
+
# content does not contain a simpleType element
|
42
|
+
# @!attribute type
|
43
|
+
# @return [String, nil]
|
44
|
+
property :type, :string
|
45
|
+
|
46
|
+
# Optional. Specifies how the attribute is used. Can be one of the following values:
|
47
|
+
# optional - the attribute is optional (this is default)
|
48
|
+
# prohibited - the attribute cannot be used
|
49
|
+
# required - the attribute is required
|
50
|
+
# @!attribute use
|
51
|
+
# @return [String]
|
52
|
+
property :use, :string, default: 'optional'
|
53
|
+
|
54
|
+
# Determine if attribute is required
|
55
|
+
# @return [Boolean]
|
56
|
+
def required?
|
57
|
+
use == 'required'
|
58
|
+
end
|
59
|
+
|
60
|
+
# Determine if attribute is optional
|
61
|
+
# @return [Boolean]
|
62
|
+
def optional?
|
63
|
+
use == 'optional'
|
64
|
+
end
|
65
|
+
|
66
|
+
# Determine if attribute is prohibited
|
67
|
+
# @return [Boolean]
|
68
|
+
def prohibited?
|
69
|
+
use == 'prohibited'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|