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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +124 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE +21 -0
  8. data/Makefile +7 -0
  9. data/README.md +68 -0
  10. data/Rakefile +25 -0
  11. data/lib/xsd/base_object.rb +347 -0
  12. data/lib/xsd/exceptions.rb +12 -0
  13. data/lib/xsd/generator.rb +137 -0
  14. data/lib/xsd/objects/all.rb +22 -0
  15. data/lib/xsd/objects/annotation.rb +19 -0
  16. data/lib/xsd/objects/any.rb +31 -0
  17. data/lib/xsd/objects/any_attribute.rb +30 -0
  18. data/lib/xsd/objects/appinfo.rb +13 -0
  19. data/lib/xsd/objects/attribute.rb +72 -0
  20. data/lib/xsd/objects/attribute_group.rb +18 -0
  21. data/lib/xsd/objects/choice.rb +33 -0
  22. data/lib/xsd/objects/complex_content.rb +25 -0
  23. data/lib/xsd/objects/complex_type.rb +82 -0
  24. data/lib/xsd/objects/documentation.rb +18 -0
  25. data/lib/xsd/objects/element.rb +130 -0
  26. data/lib/xsd/objects/extension.rb +14 -0
  27. data/lib/xsd/objects/facet.rb +12 -0
  28. data/lib/xsd/objects/field.rb +13 -0
  29. data/lib/xsd/objects/group.rb +32 -0
  30. data/lib/xsd/objects/import.rb +67 -0
  31. data/lib/xsd/objects/key.rb +25 -0
  32. data/lib/xsd/objects/keyref.rb +33 -0
  33. data/lib/xsd/objects/list.rb +18 -0
  34. data/lib/xsd/objects/restriction.rb +49 -0
  35. data/lib/xsd/objects/schema.rb +155 -0
  36. data/lib/xsd/objects/selector.rb +15 -0
  37. data/lib/xsd/objects/sequence.rb +33 -0
  38. data/lib/xsd/objects/simple_content.rb +19 -0
  39. data/lib/xsd/objects/simple_type.rb +35 -0
  40. data/lib/xsd/objects/union.rb +23 -0
  41. data/lib/xsd/objects/unique.rb +18 -0
  42. data/lib/xsd/shared/attribute_container.rb +17 -0
  43. data/lib/xsd/shared/based.rb +37 -0
  44. data/lib/xsd/shared/complex_typed.rb +28 -0
  45. data/lib/xsd/shared/element_container.rb +12 -0
  46. data/lib/xsd/shared/min_max_occurs.rb +46 -0
  47. data/lib/xsd/shared/referenced.rb +24 -0
  48. data/lib/xsd/shared/simple_typed.rb +14 -0
  49. data/lib/xsd/validator.rb +90 -0
  50. data/lib/xsd/version.rb +5 -0
  51. data/lib/xsd/xml.rb +111 -0
  52. data/lib/xsd.rb +42 -0
  53. data/xsd.gemspec +45 -0
  54. metadata +239 -0
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The schema element defines the root element of a schema.
5
+ # Parent elements: NONE
6
+ # https://www.w3schools.com/xml/el_schema.asp
7
+ class Schema < BaseObject
8
+ include AttributeContainer
9
+ include ElementContainer
10
+
11
+ # Optional. The form for attributes declared in the target namespace of this schema. The value must be "qualified"
12
+ # or "unqualified". Default is "unqualified". "unqualified" indicates that attributes from the target namespace
13
+ # are not required to be qualified with the namespace prefix. "qualified" indicates that attributes from the target
14
+ # namespace must be qualified with the namespace prefix
15
+ # @!attribute attribute_form_default
16
+ # @return [String]
17
+ property :attributeFormDefault, :string, default: 'unqualified'
18
+
19
+ # Optional. The form for elements declared in the target namespace of this schema. The value must be "qualified"
20
+ # or "unqualified". Default is "unqualified". "unqualified" indicates that elements from the target namespace are
21
+ # not required to be qualified with the namespace prefix. "qualified" indicates that elements from the target
22
+ # namespace must be qualified with the namespace prefix
23
+ # @!attribute element_form_default
24
+ # @return [String]
25
+ property :elementFormDefault, :string, default: 'unqualified'
26
+
27
+ # Optional. Specifies the default value of the block attribute on element and complexType elements in the target
28
+ # namespace. The block attribute prevents a complex type (or element) that has a specified type of derivation from
29
+ # being used in place of this complex type. This value can contain #all or a list that is a subset of extension,
30
+ # restriction, or substitution:
31
+ # extension - prevents complex types derived by extension
32
+ # restriction - prevents complex types derived by restriction
33
+ # substitution - prevents substitution of elements
34
+ # #all - prevents all derived complex types
35
+ # @!attribute block_default
36
+ # @return [String]
37
+ property :blockDefault, :string
38
+
39
+ # Optional. Specifies the default value of the final attribute on element, simpleType, and complexType elements in
40
+ # the target namespace. The final attribute prevents a specified type of derivation of an element, simpleType, or
41
+ # complexType element. For element and complexType elements, this value can contain #all or a list that is a subset
42
+ # of extension or restriction. For simpleType elements, this value can additionally contain list and union:
43
+ # extension - prevents derivation by extension
44
+ # restriction - prevents derivation by restriction
45
+ # list - prevents derivation by list
46
+ # union - prevents derivation by union
47
+ # #all - prevents all derivation
48
+ # @!attribute final_default
49
+ # @return [String]
50
+ property :finalDefault, :string
51
+
52
+ # Optional. A URI reference of the namespace of this schema
53
+ # @!attribute target_namespace
54
+ # @return [String]
55
+ property :targetNamespace, :string
56
+
57
+ # Optional. Specifies the version of the schema
58
+ # @!attribute version
59
+ # @return [String]
60
+ property :version, :string
61
+
62
+ # A URI reference that specifies one or more namespaces for use in this schema. If no prefix is assigned, the schema
63
+ # components of the namespace can be used with unqualified references
64
+ # @!attribute xmlns
65
+ # @return [String]
66
+ property :xmlns, :string
67
+
68
+ # Global complex types
69
+ # @!attribute complex_types
70
+ # @return [Array<ComplexType>]
71
+ child :complex_types, [:complexType]
72
+
73
+ # Global simple types
74
+ # @!attribute simple_types
75
+ # @return [Array<SimpleType>]
76
+ child :simple_types, [:simpleType]
77
+
78
+ # Global groups
79
+ # @!attribute groups
80
+ # @return [Array<Group>]
81
+ child :groups, [:group]
82
+
83
+ # Get nested groups
84
+ # @!attribute imports
85
+ # @return [Array<Import>]
86
+ child :imports, [:import]
87
+
88
+ # Get current schema object
89
+ # @return [Schema]
90
+ def schema
91
+ self
92
+ end
93
+
94
+ # Get all available root elements. Overrides base implementation for better speed
95
+ # @return [Array<Element>]
96
+ def all_elements(*)
97
+ elements
98
+ end
99
+
100
+ # Get all available root attributes. Overrides base implementation for better speed
101
+ # @return [Array<Attribute>]
102
+ def all_attributes(*)
103
+ attributes
104
+ end
105
+
106
+ # Get target namespace prefix. There may be more than one prefix, but we return only first defined
107
+ # @return [String]
108
+ def target_namespace_prefix
109
+ @target_namespace_prefix ||= namespaces.key(target_namespace)&.sub(/^xmlns:?/, '') || ''
110
+ end
111
+
112
+ # Get schema namespace prefix
113
+ # @return [String]
114
+ def namespace_prefix
115
+ @namespace_prefix ||= namespaces.key(XML_SCHEMA).sub(/^xmlns:?/, '')
116
+ end
117
+
118
+ # Check if namespace is a target namespace
119
+ # @param [String] prefix
120
+ # @return [Boolean]
121
+ def targets_namespace?(prefix)
122
+ namespaces[prefix.empty? ? 'xmlns' : "xmlns:#{prefix}"] == target_namespace
123
+ end
124
+
125
+ # Override map_children on schema to get objects from all imported schemas
126
+ # @param [Symbol] name
127
+ # @return [Array<BaseObject>]
128
+ def map_children(name, cache = {})
129
+ super(name) + import_map_children(name, cache)
130
+ end
131
+
132
+ # Get children from all imported schemas
133
+ # @param [Symbol] name
134
+ # @return [Array<BaseObject>]
135
+ # TODO: better recursion handling, may be refactor needed 1 reader for all schemas with centralized cache
136
+ def import_map_children(name, cache)
137
+ return [] if name.to_sym == :import
138
+
139
+ imports.map do |import|
140
+ if cache[import.namespace]
141
+ reader.logger.debug(XSD) { "Schema '#{import.namespace}' already parsed, skiping" }
142
+ nil
143
+ else
144
+ cache[import.namespace] = true
145
+ import.imported_reader.schema.map_children(name, cache)
146
+ end
147
+ end.compact.flatten
148
+ end
149
+
150
+ def import_by_namespace(ns)
151
+ aliases = [ns, namespaces["xmlns:#{(ns || '').gsub(/^xmlns:/, '')}"]].compact
152
+ imports.find { |import| aliases.include?(import.namespace) }
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The selector element specifies an XPath expression that selects a set of elements for an identity constraint
5
+ # (unique, key, and keyref elements).
6
+ # Parent elements: key, keyref, unique
7
+ # https://www.w3schools.com/xml/el_selector.asp
8
+ class Selector < BaseObject
9
+ # Required. Specifies an XPath expression, relative to the element being declared, that identifies the child
10
+ # elements to which the identity constraint applies
11
+ # @!attribute xpath
12
+ # @return [String]
13
+ property :xpath, :string, required: true
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The sequence element specifies that the child elements must appear in a sequence.
5
+ # Each child element can occur from 0 to any number of times.
6
+ # Parent elements: group, choice, sequence, complexType, restriction (both simpleContent and complexContent),
7
+ # extension (both simpleContent and complexContent)
8
+ # https://www.w3schools.com/xml/el_sequence.asp
9
+ class Sequence < BaseObject
10
+ include MinMaxOccurs
11
+ include ElementContainer
12
+
13
+ # Nested groups
14
+ # @!attribute groups
15
+ # @return [Array<Group>]
16
+ child :groups, [:group]
17
+
18
+ # Nested choices
19
+ # @!attribute choices
20
+ # @return [Array<Choice>]
21
+ child :choices, [:choice]
22
+
23
+ # Nested sequences
24
+ # @!attribute sequences
25
+ # @return [Array<Sequence>]
26
+ child :sequences, [:sequence]
27
+
28
+ # Nested anys
29
+ # @!attribute anys
30
+ # @return [Array<Any>]
31
+ child :anys, [:any]
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The simpleContent element contains extensions or restrictions on a text-only complex type or on a simple type as
5
+ # content and contains no elements.
6
+ # Parent elements: complexType
7
+ # https://www.w3schools.com/xml/el_simpleContent.asp
8
+ class SimpleContent < BaseObject
9
+ # Nested extension
10
+ # @!attribute extension
11
+ # @return [Extension, nil]
12
+ child :extension, :extension
13
+
14
+ # Nested restriction
15
+ # @!attribute restriction
16
+ # @return [Restriction, nil]
17
+ child :restriction, :restriction
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The simpleType element defines a simple type and specifies the constraints and information about the values
5
+ # of attributes or text-only elements.
6
+ # Parent elements: attribute, element, list, restriction, schema, union
7
+ # https://www.w3schools.com/xml/el_simpletype.asp
8
+ class SimpleType < BaseObject
9
+ # Optional. Specifies the name of the attribute. Name and ref attributes cannot both be present
10
+ # @!attribute name
11
+ # @return [String]
12
+ property :name, :string
13
+
14
+ # Nested restriction
15
+ # @!attribute restriction
16
+ # @return [Restriction, nil]
17
+ child :restriction, :restriction
18
+
19
+ # Nested union
20
+ # @!attribute union
21
+ # @return [Union, nil]
22
+ child :union, :union
23
+
24
+ # Nested list
25
+ # @!attribute list
26
+ # @return [List, nil]
27
+ child :list, :list
28
+
29
+ # Determine if this is a linked type
30
+ # @return [Boolean]
31
+ def linked?
32
+ !name.nil?
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The union element defines a simple type as a collection (union) of values from specified simple data types.
5
+ # Parent elements: simpleType
6
+ # https://www.w3schools.com/xml/el_union.asp
7
+ class Union < BaseObject
8
+ # Optional. Specifies a list of built-in data types or simpleType elements defined in a schema
9
+ # @!attribute member_types
10
+ # @return [Array<String>]
11
+ property :memberTypes, :array, default: [] do |union|
12
+ union.node['memberTypes']&.split(' ')
13
+ end
14
+
15
+ # Nested simple and built-in types
16
+ # @return [Array<SimpleType, String>]
17
+ def types
18
+ @types ||= map_children(:simpleType) + member_types.map do |name|
19
+ object_by_name(:simpleType, name) || name
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The unique element defines that an element or an attribute value must be unique within the scope.
5
+ # Parent elements: element
6
+ # https://www.w3schools.com/xml/el_unique.asp
7
+ class Unique < BaseObject
8
+ # Get nested selector object
9
+ # @!attribute selector
10
+ # @return [Selector]
11
+ child :selector, :selector
12
+
13
+ # Get nested field objects
14
+ # @!attribute fields
15
+ # @return [Array<Field>]
16
+ child :fields, [:field]
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ module AttributeContainer
5
+ # Nested attributes
6
+ # @!attribute attributes
7
+ # @return [Array<Attribute>]
8
+
9
+ # Nested attribute groups
10
+ # @!attribute attribute_groups
11
+ # @return [Array<AttributeGroup>]
12
+ def self.included(obj)
13
+ obj.child :attributes, [:attribute]
14
+ obj.child :attribute_groups, [:attributeGroup]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # Used by extension and restriction elements
5
+ module Based
6
+ # Required. Specifies the name of a built-in data type, a simpleType element, or a complexType element
7
+ # @!attribute base
8
+ # @return [String]
9
+
10
+ # Base complexType
11
+ # @!attribute base_complex_type
12
+ # @return [ComplexType, nil]
13
+
14
+ # Base simpleType
15
+ # @!attribute base_simple_type
16
+ # @return [SimpleType, nil]
17
+ def self.included(obj)
18
+ obj.property :base, :string, required: true
19
+ obj.link :base_complex_type, :complexType, property: :base
20
+ obj.link :base_simple_type, :simpleType, property: :base
21
+ end
22
+
23
+ # Get all available elements on the current stack level, optionally including base type elements
24
+ # @param [Boolean] include_base
25
+ # @return [Array<Element>]
26
+ def all_elements(include_base = true)
27
+ (include_base && base_complex_type ? base_complex_type.all_elements : []) + super
28
+ end
29
+
30
+ # Get all available attributes on the current stack level, optionally including base type attributes
31
+ # @param [Boolean] include_base
32
+ # @return [Array<Attribute>]
33
+ def all_attributes(include_base = true)
34
+ (include_base && base_complex_type ? base_complex_type.all_attributes : []) + super
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # Provides object an ability to have complex type (nested or linked)
5
+ module ComplexTyped
6
+ # Child/linked complex type
7
+ # @!attribute complex_type
8
+ # @return [ComplexType, nil]
9
+ def self.included(obj)
10
+ obj.child :complex_type, :complexType
11
+ obj.link :complex_type, :complexType, property: obj::TYPE_PROPERTY
12
+ end
13
+
14
+ # Get all available elements on the current stack level or linked type elements
15
+ # @param [Boolean] linked_type
16
+ # @return [Array<Element>]
17
+ def all_elements(linked_type = true)
18
+ (linked_type && complex_type&.linked? ? complex_type.all_elements : super)
19
+ end
20
+
21
+ # Get all available attributes on the current stack level or linked type attributes
22
+ # @param [Boolean] linked_type
23
+ # @return [Array<Attribute>]
24
+ def all_attributes(linked_type = true)
25
+ (linked_type && complex_type&.linked? ? complex_type.all_attributes : super)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ module ElementContainer
5
+ # Nested elements
6
+ # @!attribute elements
7
+ # @return [Array<Element>]
8
+ def self.included(obj)
9
+ obj.child :elements, [:element]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ module MinMaxOccurs
5
+ # Optional. Specifies the minimum number of times the choice element can occur in the parent the element.
6
+ # The value can be any number >= 0. Default value is 1
7
+ # @!attribute min_occurs
8
+ # @return [Integer]
9
+
10
+ # Optional. Specifies the maximum number of times the choice element can occur in the parent element.
11
+ # The value can be any number >= 0, or if you want to set no limit on the maximum number, use the value "unbounded".
12
+ # Default value is 1
13
+ # @!attribute max_occurs
14
+ # @return [Integer, Symbol]
15
+ def self.included(obj)
16
+ obj.property :minOccurs, :integer, default: 1
17
+ obj.property :maxOccurs, :integer, default: 1
18
+ end
19
+
20
+ # Compute actual max_occurs accounting parents
21
+ # @return [Integer, Symbol]
22
+ def computed_max_occurs
23
+ @computed_max_occurs ||= if parent.is_a?(MinMaxOccurs)
24
+ if max_occurs == :unbounded || parent.computed_max_occurs == :unbounded
25
+ :unbounded
26
+ else
27
+ [max_occurs, parent.computed_max_occurs].max
28
+ end
29
+ else
30
+ max_occurs
31
+ end
32
+ end
33
+
34
+ # Compute actual min_occurs accounting parents
35
+ # @return [Integer]
36
+ def computed_min_occurs
37
+ @computed_min_occurs ||= if parent.is_a?(Choice)
38
+ 0
39
+ elsif parent.is_a?(MinMaxOccurs)
40
+ [min_occurs, parent.computed_min_occurs].min
41
+ else
42
+ min_occurs
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ module Referenced
5
+ # Optional. Specifies a reference to a named attribute. Name and ref attributes cannot both be present.
6
+ # If ref is present, simpleType element, form, and type cannot be present
7
+ # @!attribute ref
8
+ # @return [String]
9
+
10
+ # Reference object
11
+ # @!attribute reference
12
+ # @return [BaseObject]
13
+ def self.included(obj)
14
+ obj.property :ref, :string
15
+ obj.link :reference, obj.mapped_name, property: :ref
16
+ end
17
+
18
+ # Is object referenced?
19
+ # @return [Boolean]
20
+ def referenced?
21
+ !ref.nil?
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # Provides object an ability to have simple type (nested or linked)
5
+ module SimpleTyped
6
+ # Get child/linked simple type
7
+ # @!attribute simple_type
8
+ # @return [SimpleType, nil]
9
+ def self.included(obj)
10
+ obj.child :simple_type, :simpleType
11
+ obj.link :simple_type, :simpleType, property: obj::TYPE_PROPERTY
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,90 @@
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ VERSION = '1.0.0'
5
+ end