xsd 1.0.0

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