shale 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +366 -8
- data/exe/shaleb +123 -0
- data/lib/shale/adapter/json.rb +7 -2
- data/lib/shale/adapter/nokogiri.rb +48 -12
- data/lib/shale/adapter/ox.rb +28 -4
- data/lib/shale/adapter/rexml.rb +56 -13
- data/lib/shale/attribute.rb +7 -1
- data/lib/shale/error.rb +12 -0
- data/lib/shale/mapper.rb +17 -15
- data/lib/shale/mapping/descriptor/dict.rb +57 -0
- data/lib/shale/mapping/descriptor/xml.rb +43 -0
- data/lib/shale/mapping/descriptor/xml_namespace.rb +37 -0
- data/lib/shale/mapping/{key_value.rb → dict.rb} +8 -6
- data/lib/shale/mapping/validator.rb +51 -0
- data/lib/shale/mapping/xml.rb +86 -15
- data/lib/shale/schema/json_compiler/boolean.rb +21 -0
- data/lib/shale/schema/json_compiler/date.rb +21 -0
- data/lib/shale/schema/json_compiler/float.rb +21 -0
- data/lib/shale/schema/json_compiler/integer.rb +21 -0
- data/lib/shale/schema/json_compiler/object.rb +85 -0
- data/lib/shale/schema/json_compiler/property.rb +70 -0
- data/lib/shale/schema/json_compiler/string.rb +21 -0
- data/lib/shale/schema/json_compiler/time.rb +21 -0
- data/lib/shale/schema/json_compiler/utils.rb +52 -0
- data/lib/shale/schema/json_compiler/value.rb +13 -0
- data/lib/shale/schema/json_compiler.rb +333 -0
- data/lib/shale/schema/json_generator/base.rb +41 -0
- data/lib/shale/schema/json_generator/boolean.rb +23 -0
- data/lib/shale/schema/json_generator/collection.rb +39 -0
- data/lib/shale/schema/json_generator/date.rb +23 -0
- data/lib/shale/schema/json_generator/float.rb +23 -0
- data/lib/shale/schema/json_generator/integer.rb +23 -0
- data/lib/shale/schema/json_generator/object.rb +40 -0
- data/lib/shale/schema/json_generator/ref.rb +28 -0
- data/lib/shale/schema/json_generator/schema.rb +59 -0
- data/lib/shale/schema/json_generator/string.rb +23 -0
- data/lib/shale/schema/json_generator/time.rb +23 -0
- data/lib/shale/schema/json_generator/value.rb +23 -0
- data/lib/shale/schema/json_generator.rb +165 -0
- data/lib/shale/schema/xml_generator/attribute.rb +41 -0
- data/lib/shale/schema/xml_generator/complex_type.rb +70 -0
- data/lib/shale/schema/xml_generator/element.rb +55 -0
- data/lib/shale/schema/xml_generator/import.rb +46 -0
- data/lib/shale/schema/xml_generator/ref_attribute.rb +37 -0
- data/lib/shale/schema/xml_generator/ref_element.rb +39 -0
- data/lib/shale/schema/xml_generator/schema.rb +121 -0
- data/lib/shale/schema/xml_generator/typed_attribute.rb +46 -0
- data/lib/shale/schema/xml_generator/typed_element.rb +46 -0
- data/lib/shale/schema/xml_generator.rb +315 -0
- data/lib/shale/schema.rb +70 -0
- data/lib/shale/type/boolean.rb +2 -2
- data/lib/shale/type/composite.rb +78 -72
- data/lib/shale/type/date.rb +35 -2
- data/lib/shale/type/float.rb +2 -2
- data/lib/shale/type/integer.rb +2 -2
- data/lib/shale/type/string.rb +2 -2
- data/lib/shale/type/time.rb +35 -2
- data/lib/shale/type/{base.rb → value.rb} +18 -7
- data/lib/shale/utils.rb +18 -2
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +10 -10
- data/shale.gemspec +6 -2
- metadata +53 -13
- data/lib/shale/mapping/base.rb +0 -32
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Schema
|
7
|
+
class JSONGenerator
|
8
|
+
# Class representing JSON Schema any type
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
class Value < Base
|
12
|
+
# Return JSON Schema fragment as Ruby Hash
|
13
|
+
#
|
14
|
+
# @return [Hash]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def as_type
|
18
|
+
{ 'type' => %w[boolean integer number object string] }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../shale'
|
4
|
+
require_relative 'json_generator/schema'
|
5
|
+
require_relative 'json_generator/boolean'
|
6
|
+
require_relative 'json_generator/collection'
|
7
|
+
require_relative 'json_generator/date'
|
8
|
+
require_relative 'json_generator/float'
|
9
|
+
require_relative 'json_generator/integer'
|
10
|
+
require_relative 'json_generator/object'
|
11
|
+
require_relative 'json_generator/ref'
|
12
|
+
require_relative 'json_generator/string'
|
13
|
+
require_relative 'json_generator/time'
|
14
|
+
require_relative 'json_generator/value'
|
15
|
+
|
16
|
+
module Shale
|
17
|
+
module Schema
|
18
|
+
# Class for generating JSON schema
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
class JSONGenerator
|
22
|
+
@json_types = Hash.new(Shale::Schema::JSONGenerator::String)
|
23
|
+
|
24
|
+
# Register Shale to JSON type mapping
|
25
|
+
#
|
26
|
+
# @param [Shale::Type::Value] shale_type
|
27
|
+
# @param [Shale::Schema::JSONGenerator::Base] json_type
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# Shale::Schema::JSONGenerator.register_json_type(Shale::Type::String, MyCustomJsonType)
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def self.register_json_type(shale_type, json_type)
|
34
|
+
@json_types[shale_type] = json_type
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return JSON type for given Shale type
|
38
|
+
#
|
39
|
+
# @param [Shale::Type::Value] shale_type
|
40
|
+
#
|
41
|
+
# @return [Shale::Schema::JSONGenerator::Base]
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# Shale::Schema::JSONGenerator.get_json_type(Shale::Type::String)
|
45
|
+
# # => Shale::Schema::JSON::String
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
def self.get_json_type(shale_type)
|
49
|
+
@json_types[shale_type]
|
50
|
+
end
|
51
|
+
|
52
|
+
register_json_type(Shale::Type::Boolean, Shale::Schema::JSONGenerator::Boolean)
|
53
|
+
register_json_type(Shale::Type::Date, Shale::Schema::JSONGenerator::Date)
|
54
|
+
register_json_type(Shale::Type::Float, Shale::Schema::JSONGenerator::Float)
|
55
|
+
register_json_type(Shale::Type::Integer, Shale::Schema::JSONGenerator::Integer)
|
56
|
+
register_json_type(Shale::Type::Time, Shale::Schema::JSONGenerator::Time)
|
57
|
+
register_json_type(Shale::Type::Value, Shale::Schema::JSONGenerator::Value)
|
58
|
+
|
59
|
+
# Generate JSON Schema from Shale model and return it as a Ruby Hash
|
60
|
+
#
|
61
|
+
# @param [Shale::Mapper] klass
|
62
|
+
# @param [String, nil] id
|
63
|
+
# @param [String, nil] description
|
64
|
+
#
|
65
|
+
# @raise [NotAShaleMapperError] when attribute is not a Shale model
|
66
|
+
#
|
67
|
+
# @return [Hash]
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# Shale::Schema::JSONGenerator.new.as_schema(Person)
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def as_schema(klass, id: nil, title: nil, description: nil)
|
74
|
+
unless mapper_type?(klass)
|
75
|
+
raise NotAShaleMapperError, "JSON Shema can't be generated for '#{klass}' type"
|
76
|
+
end
|
77
|
+
|
78
|
+
types = []
|
79
|
+
collect_composite_types(types, klass)
|
80
|
+
objects = []
|
81
|
+
|
82
|
+
types.each do |type|
|
83
|
+
properties = []
|
84
|
+
|
85
|
+
type.json_mapping.keys.values.each do |mapping|
|
86
|
+
attribute = type.attributes[mapping.attribute]
|
87
|
+
next unless attribute
|
88
|
+
|
89
|
+
if mapper_type?(attribute.type)
|
90
|
+
json_type = Ref.new(mapping.name, attribute.type.name)
|
91
|
+
else
|
92
|
+
json_klass = self.class.get_json_type(attribute.type)
|
93
|
+
|
94
|
+
if attribute.default && !attribute.collection?
|
95
|
+
value = attribute.type.cast(attribute.default.call)
|
96
|
+
default = attribute.type.as_json(value)
|
97
|
+
end
|
98
|
+
|
99
|
+
json_type = json_klass.new(mapping.name, default: default)
|
100
|
+
end
|
101
|
+
|
102
|
+
json_type = Collection.new(json_type) if attribute.collection?
|
103
|
+
properties << json_type
|
104
|
+
end
|
105
|
+
|
106
|
+
objects << Object.new(type.name, properties)
|
107
|
+
end
|
108
|
+
|
109
|
+
Schema.new(objects, id: id, title: title, description: description).as_json
|
110
|
+
end
|
111
|
+
|
112
|
+
# Generate JSON Schema from Shale model
|
113
|
+
#
|
114
|
+
# @param [Shale::Mapper] klass
|
115
|
+
# @param [String, nil] id
|
116
|
+
# @param [String, nil] description
|
117
|
+
# @param [true, false] pretty
|
118
|
+
#
|
119
|
+
# @return [String]
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# Shale::Schema::JSONGenerator.new.to_schema(Person)
|
123
|
+
#
|
124
|
+
# @api public
|
125
|
+
def to_schema(klass, id: nil, title: nil, description: nil, pretty: false)
|
126
|
+
schema = as_schema(klass, id: id, title: title, description: description)
|
127
|
+
options = pretty ? :pretty : nil
|
128
|
+
|
129
|
+
Shale.json_adapter.dump(schema, options)
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
# Check it type inherits from Shale::Mapper
|
135
|
+
#
|
136
|
+
# @param [Class] type
|
137
|
+
#
|
138
|
+
# @return [true, false]
|
139
|
+
#
|
140
|
+
# @api private
|
141
|
+
def mapper_type?(type)
|
142
|
+
type < Shale::Mapper
|
143
|
+
end
|
144
|
+
|
145
|
+
# Collect recursively Shale::Mapper types
|
146
|
+
#
|
147
|
+
# @param [Array<Shale::Mapper>] types
|
148
|
+
# @param [Shale::Mapper] type
|
149
|
+
#
|
150
|
+
# @api private
|
151
|
+
def collect_composite_types(types, type)
|
152
|
+
types << type
|
153
|
+
|
154
|
+
type.json_mapping.keys.values.each do |mapping|
|
155
|
+
attribute = type.attributes[mapping.attribute]
|
156
|
+
next unless attribute
|
157
|
+
|
158
|
+
if mapper_type?(attribute.type) && !types.include?(attribute.type)
|
159
|
+
collect_composite_types(types, attribute.type)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shale
|
4
|
+
module Schema
|
5
|
+
class XMLGenerator
|
6
|
+
# Class representing XML Schema <attribute> element.
|
7
|
+
# Serves as a base class for TypedAttribute and RefAttribute
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Attribute
|
11
|
+
# Initialize Attribute object
|
12
|
+
#
|
13
|
+
# @param [String, nil] default
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
def initialize(default)
|
17
|
+
@default = default
|
18
|
+
end
|
19
|
+
|
20
|
+
# Append element to the XML document
|
21
|
+
#
|
22
|
+
# @param [Shale::Adapter::<XML adapter>::Document] doc
|
23
|
+
#
|
24
|
+
# @return [Shale::Adapter::<XML adapter>::Node]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def as_xml(doc)
|
28
|
+
attribute = doc.create_element('xs:attribute')
|
29
|
+
|
30
|
+
attributes.each do |name, value|
|
31
|
+
doc.add_attribute(attribute, name, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
doc.add_attribute(attribute, 'default', @default) unless @default.nil?
|
35
|
+
|
36
|
+
attribute
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'attribute'
|
4
|
+
require_relative 'element'
|
5
|
+
|
6
|
+
module Shale
|
7
|
+
module Schema
|
8
|
+
class XMLGenerator
|
9
|
+
# Class representing XML Schema <complexType> element
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class ComplexType
|
13
|
+
# Return name
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# Initialize ComplexType object
|
21
|
+
#
|
22
|
+
# @param [String] name
|
23
|
+
# @param [Array<
|
24
|
+
# Shale::Schema::XMLGenerator::Element,
|
25
|
+
# Shale::Schema::XMLGenerator::Attribute
|
26
|
+
# >] children
|
27
|
+
# @param [true, false] mixed
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def initialize(name, children = [], mixed: false)
|
31
|
+
@name = name
|
32
|
+
@children = children
|
33
|
+
@mixed = mixed
|
34
|
+
end
|
35
|
+
|
36
|
+
# Append element to the XML document
|
37
|
+
#
|
38
|
+
# @param [Shale::Adapter::<XML adapter>::Document] doc
|
39
|
+
#
|
40
|
+
# @return [Shale::Adapter::<XML adapter>::Node]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def as_xml(doc)
|
44
|
+
complex_type = doc.create_element('xs:complexType')
|
45
|
+
|
46
|
+
doc.add_attribute(complex_type, 'name', @name)
|
47
|
+
doc.add_attribute(complex_type, 'mixed', 'true') if @mixed
|
48
|
+
|
49
|
+
elements = @children.select { |e| e.is_a?(Element) }
|
50
|
+
attributes = @children.select { |e| e.is_a?(Attribute) }
|
51
|
+
|
52
|
+
unless elements.empty?
|
53
|
+
sequence = doc.create_element('xs:sequence')
|
54
|
+
doc.add_element(complex_type, sequence)
|
55
|
+
|
56
|
+
elements.each do |element|
|
57
|
+
doc.add_element(sequence, element.as_xml(doc))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
attributes.each do |attribute|
|
62
|
+
doc.add_element(complex_type, attribute.as_xml(doc))
|
63
|
+
end
|
64
|
+
|
65
|
+
complex_type
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shale
|
4
|
+
module Schema
|
5
|
+
class XMLGenerator
|
6
|
+
# Class representing XML Schema <element> element.
|
7
|
+
# Serves as a base class for TypedElement and RefElement
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Element
|
11
|
+
# Initialize Element object
|
12
|
+
#
|
13
|
+
# @param [String, nil] default
|
14
|
+
# @param [true, false] collection
|
15
|
+
# @param [true, false] required
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
def initialize(default, collection, required)
|
19
|
+
@default = default
|
20
|
+
@collection = collection
|
21
|
+
@required = required
|
22
|
+
end
|
23
|
+
|
24
|
+
# Append element to the XML document
|
25
|
+
#
|
26
|
+
# @param [Shale::Adapter::<XML adapter>::Document] doc
|
27
|
+
#
|
28
|
+
# @return [Shale::Adapter::<XML adapter>::Node]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def as_xml(doc)
|
32
|
+
element = doc.create_element('xs:element')
|
33
|
+
|
34
|
+
attributes.each do |name, value|
|
35
|
+
doc.add_attribute(element, name, value)
|
36
|
+
end
|
37
|
+
|
38
|
+
unless @required
|
39
|
+
doc.add_attribute(element, 'minOccurs', 0)
|
40
|
+
end
|
41
|
+
|
42
|
+
if @collection
|
43
|
+
doc.add_attribute(element, 'maxOccurs', 'unbounded')
|
44
|
+
end
|
45
|
+
|
46
|
+
unless @default.nil?
|
47
|
+
doc.add_attribute(element, 'default', @default)
|
48
|
+
end
|
49
|
+
|
50
|
+
element
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shale
|
4
|
+
module Schema
|
5
|
+
class XMLGenerator
|
6
|
+
# Class representing XML Schema <import> element
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Import
|
10
|
+
# Return namespace
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
attr_reader :namespace
|
16
|
+
|
17
|
+
# Initialize Import object
|
18
|
+
#
|
19
|
+
# @param [String, nil] namespace
|
20
|
+
# @param [String, nil] location
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
def initialize(namespace, location)
|
24
|
+
@namespace = namespace
|
25
|
+
@location = location
|
26
|
+
end
|
27
|
+
|
28
|
+
# Append element to the XML document
|
29
|
+
#
|
30
|
+
# @param [Shale::Adapter::<XML adapter>::Document] doc
|
31
|
+
#
|
32
|
+
# @return [Shale::Adapter::<XML adapter>::Node]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def as_xml(doc)
|
36
|
+
import = doc.create_element('xs:import')
|
37
|
+
|
38
|
+
doc.add_attribute(import, 'namespace', @namespace)
|
39
|
+
doc.add_attribute(import, 'schemaLocation', @location)
|
40
|
+
|
41
|
+
import
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'attribute'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Schema
|
7
|
+
class XMLGenerator
|
8
|
+
# Class representing XML Schema <attribute ref=""> element
|
9
|
+
# with a reference
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class RefAttribute < Attribute
|
13
|
+
# Initialize RefAttribute object
|
14
|
+
#
|
15
|
+
# @param [String] ref
|
16
|
+
# @param [String, nil] default
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def initialize(ref:, default: nil)
|
20
|
+
super(default)
|
21
|
+
@ref = ref
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Return attributes as Ruby Hash
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def attributes
|
32
|
+
{ 'ref' => @ref }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Schema
|
7
|
+
class XMLGenerator
|
8
|
+
# Class representing XML Schema <element ref=""> element
|
9
|
+
# with a reference
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class RefElement < Element
|
13
|
+
# Initialize RefElement object
|
14
|
+
#
|
15
|
+
# @param [String] ref
|
16
|
+
# @param [String, nil] default
|
17
|
+
# @param [true, false] collection
|
18
|
+
# @param [true, false] required
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def initialize(ref:, default: nil, collection: false, required: false)
|
22
|
+
super(default, collection, required)
|
23
|
+
@ref = ref
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Return attributes as Ruby Hash
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def attributes
|
34
|
+
{ 'ref' => @ref }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../shale'
|
4
|
+
require_relative 'complex_type'
|
5
|
+
|
6
|
+
module Shale
|
7
|
+
module Schema
|
8
|
+
class XMLGenerator
|
9
|
+
class Schema
|
10
|
+
# XML Schema namespace
|
11
|
+
# @api private
|
12
|
+
NAMESPACE_NAME = 'http://www.w3.org/2001/XMLSchema'
|
13
|
+
|
14
|
+
# Return name
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
# Initialize Schema object
|
22
|
+
#
|
23
|
+
# @param [String] name
|
24
|
+
# @param [String, nil] target_namespace
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def initialize(name, target_namespace)
|
28
|
+
@name = name
|
29
|
+
@target_namespace = target_namespace
|
30
|
+
@namespaces = []
|
31
|
+
@children = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Add namespace to XML Schema
|
35
|
+
#
|
36
|
+
# @param [String] prefix
|
37
|
+
# @param [String] name
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
def add_namespace(prefix, name)
|
41
|
+
@namespaces << { prefix: prefix, name: name }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add child element to XML Schema
|
45
|
+
#
|
46
|
+
# @param [Shale::Schema::XMLGenerator::Import,
|
47
|
+
# Shale::Schema::XMLGenerator::Element,
|
48
|
+
# Shale::Schema::XMLGenerator::Attribute,
|
49
|
+
# Shale::Schema::XMLGenerator::ComplesType] child
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
def add_child(child)
|
53
|
+
@children << child
|
54
|
+
end
|
55
|
+
|
56
|
+
# Append element to the XML document
|
57
|
+
#
|
58
|
+
# @param [Shale::Adapter::<XML adapter>::Document] doc
|
59
|
+
#
|
60
|
+
# @return [Shale::Adapter::REXML::Document,
|
61
|
+
# Shale::Adapter::Nokogiri::Document,
|
62
|
+
# Shale::Adapter::Ox::Document]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
def as_xml
|
66
|
+
doc = Shale.xml_adapter.create_document
|
67
|
+
doc.add_namespace('xs', NAMESPACE_NAME)
|
68
|
+
|
69
|
+
@namespaces.uniq.each do |namespace|
|
70
|
+
doc.add_namespace(namespace[:prefix], namespace[:name])
|
71
|
+
end
|
72
|
+
|
73
|
+
schema = doc.create_element('xs:schema')
|
74
|
+
doc.add_element(doc.doc, schema)
|
75
|
+
|
76
|
+
doc.add_attribute(schema, 'elementFormDefault', 'qualified')
|
77
|
+
doc.add_attribute(schema, 'attributeFormDefault', 'qualified')
|
78
|
+
|
79
|
+
unless @target_namespace.nil?
|
80
|
+
doc.add_attribute(schema, 'targetNamespace', @target_namespace)
|
81
|
+
end
|
82
|
+
|
83
|
+
imports = @children
|
84
|
+
.select { |e| e.is_a?(Import) }
|
85
|
+
.uniq(&:namespace)
|
86
|
+
.sort { |a, b| (a.namespace || '') <=> (b.namespace || '') }
|
87
|
+
|
88
|
+
elements = @children
|
89
|
+
.select { |e| e.is_a?(Element) }
|
90
|
+
.sort { |a, b| a.name <=> b.name }
|
91
|
+
|
92
|
+
attributes = @children
|
93
|
+
.select { |e| e.is_a?(Attribute) }
|
94
|
+
.sort { |a, b| a.name <=> b.name }
|
95
|
+
|
96
|
+
complex_types = @children
|
97
|
+
.select { |e| e.is_a?(ComplexType) }
|
98
|
+
.sort { |a, b| a.name <=> b.name }
|
99
|
+
|
100
|
+
imports.each do |import|
|
101
|
+
doc.add_element(schema, import.as_xml(doc))
|
102
|
+
end
|
103
|
+
|
104
|
+
elements.each do |element|
|
105
|
+
doc.add_element(schema, element.as_xml(doc))
|
106
|
+
end
|
107
|
+
|
108
|
+
attributes.each do |attribute|
|
109
|
+
doc.add_element(schema, attribute.as_xml(doc))
|
110
|
+
end
|
111
|
+
|
112
|
+
complex_types.each do |complex_type|
|
113
|
+
doc.add_element(schema, complex_type.as_xml(doc))
|
114
|
+
end
|
115
|
+
|
116
|
+
doc.doc
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'attribute'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Schema
|
7
|
+
class XMLGenerator
|
8
|
+
# Class representing XML Schema <attribute name="" type=""> element
|
9
|
+
# with a name and a type
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class TypedAttribute < Attribute
|
13
|
+
# Return name
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# Initialize TypedAttribute object
|
21
|
+
#
|
22
|
+
# @param [String] name
|
23
|
+
# @param [String] type
|
24
|
+
# @param [String, nil] default
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def initialize(name:, type:, default: nil)
|
28
|
+
super(default)
|
29
|
+
@name = name
|
30
|
+
@type = type
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Return attributes as Ruby Hash
|
36
|
+
#
|
37
|
+
# @return [Hash]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
def attributes
|
41
|
+
{ 'name' => @name, 'type' => @type }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Schema
|
7
|
+
class XMLGenerator
|
8
|
+
# Class representing XML Schema <element mame="" type=""> element
|
9
|
+
# with a name and a type
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class TypedElement < Element
|
13
|
+
# Return name
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# Initialize TypedElement object
|
21
|
+
#
|
22
|
+
# @param [String] name
|
23
|
+
# @param [String] type
|
24
|
+
# @param [String, nil] default
|
25
|
+
# @param [true, false] collection
|
26
|
+
# @param [true, false] required
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
def initialize(name:, type:, default: nil, collection: false, required: false)
|
30
|
+
super(default, collection, required)
|
31
|
+
@name = name
|
32
|
+
@type = type
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return attributes as Ruby Hash
|
36
|
+
#
|
37
|
+
# @return [Hash]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
def attributes
|
41
|
+
{ 'name' => @name, 'type' => @type }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|