xsd 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|