xsd 2.4.2 → 2.6.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 +11 -1
- data/README.md +10 -2
- data/lib/xsd/base_object.rb +71 -43
- data/lib/xsd/objects/attribute.rb +13 -2
- data/lib/xsd/objects/attribute_group.rb +3 -2
- data/lib/xsd/objects/complex_type.rb +52 -1
- data/lib/xsd/objects/element.rb +40 -9
- data/lib/xsd/objects/simple_type.rb +23 -2
- data/lib/xsd/shared/named.rb +17 -0
- data/lib/xsd/version.rb +1 -1
- data/lib/xsd/xml.rb +0 -2
- data/lib/xsd.rb +1 -1
- metadata +3 -3
- data/lib/xsd/generator.rb +0 -146
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2a5aa03e831e5cf4e88780b18a4ef57217eff54a14e2138669672f33486ba8bd
|
|
4
|
+
data.tar.gz: b6a9ab392e47192a6a286ffa7dc97c5f624c78d9ab117bdea67e11f801c39363
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a031bc3a3947708a8f6f8e4add4040853f9f8b62cd3465de56421600d9fc2d2b7c45b163efe239c7486dce05bf0427d8f380e119673b644739f736b4598b5276
|
|
7
|
+
data.tar.gz: ad7bbd0268373292a291935599749dc9937784438b398958acf592db4e1648967106f45c1dd402c82f3cdd534f2fe0e177a1250e91f65872fc3aa9d9a8b416a5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [2.6.0] - 2024-04-12
|
|
2
|
+
|
|
3
|
+
- Fix XSD boolean attributes
|
|
4
|
+
- Add support for element lookup with namespace
|
|
5
|
+
- Add element (with simple content) data type calculation
|
|
6
|
+
- Add element mixed type calculation
|
|
7
|
+
|
|
8
|
+
## [2.4.3] - 2024-04-04
|
|
9
|
+
|
|
10
|
+
- Fix detecting types and refs when namespaces are overidden per element
|
|
11
|
+
- Fix documentation encoding issue with no XML declaration
|
|
2
12
|
|
|
3
13
|
## [2.4.1] - 2023-11-13
|
|
4
14
|
|
data/README.md
CHANGED
|
@@ -28,8 +28,13 @@ require 'xsd'
|
|
|
28
28
|
# Load ruby-xsd
|
|
29
29
|
reader = XSD::XML.open('some.xsd')
|
|
30
30
|
|
|
31
|
-
# Get
|
|
31
|
+
# Get element by name with hash lookup
|
|
32
32
|
element = reader['NewReleaseMessage']
|
|
33
|
+
|
|
34
|
+
# Get element by namespace + name with hash lookup
|
|
35
|
+
element = reader['{http://ddex.net/xml/ern/36}NewReleaseMessage']
|
|
36
|
+
|
|
37
|
+
# Get element child elements
|
|
33
38
|
element.collect_elements.map(&:name) # => ['MessageHeader', 'UpdateIndicator', 'IsBackfill', 'CatalogTransfer', 'WorkList', 'CueSheetList', 'ResourceList', 'CollectionList', 'ReleaseList', 'DealList']
|
|
34
39
|
|
|
35
40
|
# Get attributes
|
|
@@ -38,6 +43,7 @@ attribute = reader['NewReleaseMessage']['@MessageSchemaVersionId']
|
|
|
38
43
|
# Get attribute information
|
|
39
44
|
attribute.name # => 'MessageSchemaVersionId'
|
|
40
45
|
attribute.type # => 'xs:string'
|
|
46
|
+
attribute.data_type # => 'string'
|
|
41
47
|
attribute.required? # => true
|
|
42
48
|
attribute.optional? # => false
|
|
43
49
|
attribute.prohibited? # => true
|
|
@@ -48,7 +54,9 @@ element.min_occurs # => 0
|
|
|
48
54
|
element.max_occurs # => :unbounded
|
|
49
55
|
element.type # => 'ern:SoundRecording'
|
|
50
56
|
element.complex_type # => XSD::ComplexType
|
|
51
|
-
element.
|
|
57
|
+
element.complex_content? # => true
|
|
58
|
+
element.simple_content? # => false
|
|
59
|
+
element.mixed_content? # => false
|
|
52
60
|
element.multiple_allowed? # => true
|
|
53
61
|
element.required? # => false
|
|
54
62
|
```
|
data/lib/xsd/base_object.rb
CHANGED
|
@@ -34,7 +34,7 @@ module XSD
|
|
|
34
34
|
|
|
35
35
|
def initialize(options = {})
|
|
36
36
|
@options = options
|
|
37
|
-
@cache
|
|
37
|
+
@cache = {}
|
|
38
38
|
|
|
39
39
|
raise Error, "#{self.class}.new expects a hash parameter" unless @options.is_a?(Hash)
|
|
40
40
|
end
|
|
@@ -76,12 +76,16 @@ module XSD
|
|
|
76
76
|
# @param [String, nil] ns_or_prefix
|
|
77
77
|
# @return Array<Schema>
|
|
78
78
|
def schemas_for_namespace(ns_or_prefix)
|
|
79
|
-
if
|
|
79
|
+
# resolve namespace for current node if prefix was provided
|
|
80
|
+
prefix = node.namespaces["xmlns:#{ns_or_prefix}"]
|
|
81
|
+
ns = prefix || ns_or_prefix
|
|
82
|
+
|
|
83
|
+
if schema.targets_namespace?(ns)
|
|
80
84
|
[schema, *schema.includes.map(&:imported_schema)]
|
|
81
|
-
elsif (import = schema.import_by_namespace(
|
|
85
|
+
elsif (import = schema.import_by_namespace(ns))
|
|
82
86
|
[import.imported_schema]
|
|
83
87
|
else
|
|
84
|
-
raise Error, "Schema not found for namespace '#{
|
|
88
|
+
raise Error, "Schema not found for namespace '#{ns}' in '#{schema.id || schema.target_namespace}'"
|
|
85
89
|
end
|
|
86
90
|
end
|
|
87
91
|
|
|
@@ -96,9 +100,9 @@ module XSD
|
|
|
96
100
|
curname = curname.to_s
|
|
97
101
|
|
|
98
102
|
if curname[0] == '@'
|
|
99
|
-
result = result.collect_attributes.find { |attr| attr
|
|
103
|
+
result = result.collect_attributes.find { |attr| definition_match?(attr, curname[1..]) }
|
|
100
104
|
else
|
|
101
|
-
result = result.collect_elements.find { |elem| elem
|
|
105
|
+
result = result.collect_elements.find { |elem| definition_match?(elem, curname) }
|
|
102
106
|
end
|
|
103
107
|
end
|
|
104
108
|
|
|
@@ -112,7 +116,7 @@ module XSD
|
|
|
112
116
|
def object_by_name(node_name, name)
|
|
113
117
|
# get prefix and local name
|
|
114
118
|
name_prefix = get_prefix(name)
|
|
115
|
-
name_local
|
|
119
|
+
name_local = strip_prefix(name)
|
|
116
120
|
|
|
117
121
|
# do not search for built-in types
|
|
118
122
|
return nil if schema.namespace_prefix == name_prefix
|
|
@@ -122,7 +126,7 @@ module XSD
|
|
|
122
126
|
|
|
123
127
|
# find element in target schema
|
|
124
128
|
search_schemas.each do |s|
|
|
125
|
-
node = s.node.
|
|
129
|
+
node = s.node.at_xpath("./xs:#{node_name}[@name=\"#{name_local}\"]", { 'xs' => XML_SCHEMA })
|
|
126
130
|
return s.node_to_object(node) if node
|
|
127
131
|
end
|
|
128
132
|
|
|
@@ -134,7 +138,6 @@ module XSD
|
|
|
134
138
|
# @return BaseObject
|
|
135
139
|
def node_to_object(node)
|
|
136
140
|
# check object in cache first
|
|
137
|
-
# TODO: проверить работу!
|
|
138
141
|
return reader.object_cache[node.object_id] if reader.object_cache[node.object_id]
|
|
139
142
|
|
|
140
143
|
klass = XML::CLASS_MAP[node.name]
|
|
@@ -199,43 +202,49 @@ module XSD
|
|
|
199
202
|
# Get all available elements on the current stack level
|
|
200
203
|
# @return Array<Element>
|
|
201
204
|
def collect_elements(*)
|
|
202
|
-
|
|
203
|
-
return [] if NO_ELEMENTS_CONTAINER.include?(self.class.mapped_name)
|
|
205
|
+
return @collect_elements if @collect_elements
|
|
204
206
|
|
|
205
|
-
if
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
map_children(:*).map do |obj|
|
|
210
|
-
if obj.is_a?(Element)
|
|
211
|
-
obj
|
|
207
|
+
r = if NO_ELEMENTS_CONTAINER.include?(self.class.mapped_name)
|
|
208
|
+
[]
|
|
209
|
+
elsif is_a?(Referenced) && ref
|
|
210
|
+
reference.collect_elements
|
|
212
211
|
else
|
|
213
|
-
#
|
|
214
|
-
(
|
|
212
|
+
# map children recursive
|
|
213
|
+
map_children(:*).map do |obj|
|
|
214
|
+
if obj.is_a?(Element)
|
|
215
|
+
obj
|
|
216
|
+
else
|
|
217
|
+
# get elements considering references
|
|
218
|
+
(obj.is_a?(Referenced) && obj.ref ? obj.reference : obj).collect_elements
|
|
219
|
+
end
|
|
220
|
+
end.flatten
|
|
215
221
|
end
|
|
216
|
-
|
|
217
|
-
|
|
222
|
+
|
|
223
|
+
@collect_elements = r
|
|
218
224
|
end
|
|
219
225
|
|
|
220
226
|
# Get all available attributes on the current stack level
|
|
221
227
|
# @return Array<Attribute>
|
|
222
228
|
def collect_attributes(*)
|
|
223
|
-
|
|
224
|
-
return [] if NO_ATTRIBUTES_CONTAINER.include?(self.class.mapped_name)
|
|
229
|
+
return @collect_attributes if @collect_attributes
|
|
225
230
|
|
|
226
|
-
if
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
map_children(:*).map do |obj|
|
|
231
|
-
if obj.is_a?(Attribute)
|
|
232
|
-
obj
|
|
231
|
+
r = if NO_ATTRIBUTES_CONTAINER.include?(self.class.mapped_name)
|
|
232
|
+
[]
|
|
233
|
+
elsif is_a?(Referenced) && ref
|
|
234
|
+
reference.collect_attributes
|
|
233
235
|
else
|
|
234
|
-
#
|
|
235
|
-
(
|
|
236
|
+
# map children recursive
|
|
237
|
+
map_children(:*).map do |obj|
|
|
238
|
+
if obj.is_a?(Attribute)
|
|
239
|
+
obj
|
|
240
|
+
else
|
|
241
|
+
# get attributes considering references
|
|
242
|
+
(obj.is_a?(Referenced) && obj.ref ? obj.reference : obj).collect_attributes
|
|
243
|
+
end
|
|
244
|
+
end.flatten
|
|
236
245
|
end
|
|
237
|
-
|
|
238
|
-
|
|
246
|
+
|
|
247
|
+
@collect_attributes = r
|
|
239
248
|
end
|
|
240
249
|
|
|
241
250
|
# Get reader instance
|
|
@@ -256,8 +265,8 @@ module XSD
|
|
|
256
265
|
# @param [Hash] options
|
|
257
266
|
def self.property(name, type, options = {}, &block)
|
|
258
267
|
properties[to_underscore(name)] = {
|
|
259
|
-
name:
|
|
260
|
-
type:
|
|
268
|
+
name: name,
|
|
269
|
+
type: type,
|
|
261
270
|
resolve: block,
|
|
262
271
|
**options
|
|
263
272
|
}
|
|
@@ -294,7 +303,7 @@ module XSD
|
|
|
294
303
|
|
|
295
304
|
# check for property first
|
|
296
305
|
if (property = self.class.properties[method])
|
|
297
|
-
value
|
|
306
|
+
value = property[:resolve] ? property[:resolve].call(self) : node[property[:name].to_s]
|
|
298
307
|
result = if value.nil?
|
|
299
308
|
# if object has reference - search property in referenced object
|
|
300
309
|
node['ref'] ? reference.send(method, *args) : property[:default]
|
|
@@ -303,7 +312,7 @@ module XSD
|
|
|
303
312
|
when :integer
|
|
304
313
|
property[:name] == :maxOccurs && value == 'unbounded' ? :unbounded : value.to_i
|
|
305
314
|
when :boolean
|
|
306
|
-
|
|
315
|
+
value == 'true'
|
|
307
316
|
else
|
|
308
317
|
value
|
|
309
318
|
end
|
|
@@ -350,10 +359,10 @@ module XSD
|
|
|
350
359
|
def self.mapped_name
|
|
351
360
|
# @mapped_name ||= XML::CLASS_MAP.each { |k, v| return k.to_sym if v == self }
|
|
352
361
|
@mapped_name ||= begin
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
362
|
+
name = self.name.split('::').last
|
|
363
|
+
name[0] = name[0].downcase
|
|
364
|
+
name.to_sym
|
|
365
|
+
end
|
|
357
366
|
end
|
|
358
367
|
|
|
359
368
|
# Return string if it is not empty, or nil otherwise
|
|
@@ -362,5 +371,24 @@ module XSD
|
|
|
362
371
|
def nil_if_empty(string)
|
|
363
372
|
string&.empty? ? nil : string
|
|
364
373
|
end
|
|
374
|
+
|
|
375
|
+
private
|
|
376
|
+
|
|
377
|
+
def definition_match?(definition, query)
|
|
378
|
+
actual_definition = definition.referenced? ? definition.reference : definition
|
|
379
|
+
|
|
380
|
+
if query.start_with?('{')
|
|
381
|
+
parts = query[1..].split('}')
|
|
382
|
+
raise Error, "Invalid element/attribute query: #{query}" if parts.size != 2
|
|
383
|
+
|
|
384
|
+
namespace, name = parts
|
|
385
|
+
|
|
386
|
+
return false if namespace != actual_definition.namespace
|
|
387
|
+
else
|
|
388
|
+
name = query
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
name == '*' || actual_definition.name == name
|
|
392
|
+
end
|
|
365
393
|
end
|
|
366
394
|
end
|
|
@@ -10,10 +10,11 @@ module XSD
|
|
|
10
10
|
|
|
11
11
|
include SimpleTyped
|
|
12
12
|
include Referenced
|
|
13
|
+
include Named
|
|
13
14
|
|
|
14
15
|
# Optional. Specifies the name of the attribute. Name and ref attributes cannot both be present
|
|
15
16
|
# @!attribute name
|
|
16
|
-
# @return String
|
|
17
|
+
# @return String, nil
|
|
17
18
|
property :name, :string
|
|
18
19
|
|
|
19
20
|
# Optional. Specifies a default value for the attribute. Default and fixed attributes cannot both be present
|
|
@@ -34,7 +35,7 @@ module XSD
|
|
|
34
35
|
# matched against the (NCName) of the attribute
|
|
35
36
|
# @!attribute form
|
|
36
37
|
# @return String, nil
|
|
37
|
-
# TODO:
|
|
38
|
+
# TODO: support default value from parent
|
|
38
39
|
property :form, :string
|
|
39
40
|
|
|
40
41
|
# Optional. Specifies a built-in data type or a simple type. The type attribute can only be present when the
|
|
@@ -68,5 +69,15 @@ module XSD
|
|
|
68
69
|
def prohibited?
|
|
69
70
|
use == 'prohibited'
|
|
70
71
|
end
|
|
72
|
+
|
|
73
|
+
# Get base data type
|
|
74
|
+
# @return String, nil
|
|
75
|
+
def data_type
|
|
76
|
+
if simple_type
|
|
77
|
+
simple_type.data_type
|
|
78
|
+
else
|
|
79
|
+
strip_prefix(type)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
71
82
|
end
|
|
72
83
|
end
|
|
@@ -9,10 +9,11 @@ module XSD
|
|
|
9
9
|
class AttributeGroup < BaseObject
|
|
10
10
|
include Referenced
|
|
11
11
|
include AttributeContainer
|
|
12
|
+
include Named
|
|
12
13
|
|
|
13
|
-
# Optional. Specifies the name of the attribute. Name and ref attributes cannot both be present
|
|
14
|
+
# Optional. Specifies the name of the attribute group. Name and ref attributes cannot both be present
|
|
14
15
|
# @!attribute name
|
|
15
|
-
# @return String
|
|
16
|
+
# @return String, nil
|
|
16
17
|
property :name, :string
|
|
17
18
|
end
|
|
18
19
|
end
|
|
@@ -7,8 +7,9 @@ module XSD
|
|
|
7
7
|
# https://www.w3schools.com/xml/el_complextype.asp
|
|
8
8
|
class ComplexType < BaseObject
|
|
9
9
|
include AttributeContainer
|
|
10
|
+
include Named
|
|
10
11
|
|
|
11
|
-
# Optional. Specifies
|
|
12
|
+
# Optional. Specifies a name for the element
|
|
12
13
|
# @!attribute name
|
|
13
14
|
# @return String
|
|
14
15
|
property :name, :string
|
|
@@ -78,5 +79,55 @@ module XSD
|
|
|
78
79
|
def linked?
|
|
79
80
|
!name.nil?
|
|
80
81
|
end
|
|
82
|
+
|
|
83
|
+
# Determine if this type has mixed content definition
|
|
84
|
+
# @return Boolean
|
|
85
|
+
def mixed_content?
|
|
86
|
+
return true if mixed
|
|
87
|
+
|
|
88
|
+
if complex_content
|
|
89
|
+
return true if complex_content.mixed
|
|
90
|
+
|
|
91
|
+
return (complex_content.extension || complex_content.restriction).base_complex_type&.mixed_content?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Determine if this type has complex content definition
|
|
98
|
+
# @return Boolean
|
|
99
|
+
def complex_content?
|
|
100
|
+
if simple_content
|
|
101
|
+
false
|
|
102
|
+
elsif complex_content
|
|
103
|
+
true
|
|
104
|
+
else
|
|
105
|
+
group || all || choice || sequence
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Determine if this type has simple content definition
|
|
110
|
+
# @return Boolean
|
|
111
|
+
def simple_content?
|
|
112
|
+
!!simple_content
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Get simple content data type
|
|
116
|
+
# @return String, nil
|
|
117
|
+
def data_type
|
|
118
|
+
return nil unless simple_content
|
|
119
|
+
|
|
120
|
+
restriction = simple_content.restriction
|
|
121
|
+
if restriction
|
|
122
|
+
if restriction.base
|
|
123
|
+
restriction.base_simple_type&.data_type || strip_prefix(restriction.base)
|
|
124
|
+
else
|
|
125
|
+
restriction.simple_type&.data_type
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
extension = simple_content.extension
|
|
129
|
+
extension.base_simple_type&.data_type || strip_prefix(extension.base)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
81
132
|
end
|
|
82
133
|
end
|
data/lib/xsd/objects/element.rb
CHANGED
|
@@ -11,10 +11,11 @@ module XSD
|
|
|
11
11
|
include SimpleTyped
|
|
12
12
|
include ComplexTyped
|
|
13
13
|
include Referenced
|
|
14
|
+
include Named
|
|
14
15
|
|
|
15
|
-
# Optional. Specifies
|
|
16
|
+
# Optional. Specifies a name for the element. This attribute is required if the parent element is the schema element
|
|
16
17
|
# @!attribute name
|
|
17
|
-
# @return String
|
|
18
|
+
# @return String, nil
|
|
18
19
|
property :name, :string
|
|
19
20
|
|
|
20
21
|
# Optional. Specifies either the name of a built-in data type, or the name of a simpleType or complexType element
|
|
@@ -107,8 +108,32 @@ module XSD
|
|
|
107
108
|
|
|
108
109
|
# Determine if element has complex content
|
|
109
110
|
# @return Boolean
|
|
110
|
-
def
|
|
111
|
-
|
|
111
|
+
def complex_content?
|
|
112
|
+
# this is not an opposite to simple_content?, element may have neither
|
|
113
|
+
complex_type&.complex_content? || false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Determine if element has simple content
|
|
117
|
+
# @return Boolean
|
|
118
|
+
def simple_content?
|
|
119
|
+
# this is not an opposite to complex_content?, element may have neither
|
|
120
|
+
if complex_type
|
|
121
|
+
complex_type.simple_content?
|
|
122
|
+
else
|
|
123
|
+
true
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Determine if element has attributes
|
|
128
|
+
# @return Boolean
|
|
129
|
+
def attributes?
|
|
130
|
+
complex_type && collect_attributes.any?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Determine if element has mixed content
|
|
134
|
+
# @return Boolean
|
|
135
|
+
def mixed_content?
|
|
136
|
+
complex_type&.mixed_content? || false
|
|
112
137
|
end
|
|
113
138
|
|
|
114
139
|
# Get elements that can appear instead of this one
|
|
@@ -117,14 +142,20 @@ module XSD
|
|
|
117
142
|
# TODO: for now we do not search in parent schemas (that imported current schema)
|
|
118
143
|
# TODO: refactor for better namespace handling (use xpath with namespaces or correct comparison)
|
|
119
144
|
schema.collect_elements.select do |element|
|
|
120
|
-
element.substitution_group
|
|
145
|
+
strip_prefix(element.substitution_group) == name
|
|
121
146
|
end
|
|
122
147
|
end
|
|
123
148
|
|
|
124
|
-
# Get
|
|
125
|
-
# @return String
|
|
126
|
-
def
|
|
127
|
-
|
|
149
|
+
# Get base data type
|
|
150
|
+
# @return String, nil
|
|
151
|
+
def data_type
|
|
152
|
+
if complex_type
|
|
153
|
+
complex_type.data_type
|
|
154
|
+
elsif simple_type
|
|
155
|
+
simple_type.data_type
|
|
156
|
+
else
|
|
157
|
+
strip_prefix(type)
|
|
158
|
+
end
|
|
128
159
|
end
|
|
129
160
|
end
|
|
130
161
|
end
|
|
@@ -6,9 +6,12 @@ module XSD
|
|
|
6
6
|
# Parent elements: attribute, element, list, restriction, schema, union
|
|
7
7
|
# https://www.w3schools.com/xml/el_simpletype.asp
|
|
8
8
|
class SimpleType < BaseObject
|
|
9
|
-
|
|
9
|
+
include Named
|
|
10
|
+
|
|
11
|
+
# Specifies a name for the element. This attribute is required if the simpleType element is a child of the
|
|
12
|
+
# schema element, otherwise it is not allowed
|
|
10
13
|
# @!attribute name
|
|
11
|
-
# @return String
|
|
14
|
+
# @return String, nil
|
|
12
15
|
property :name, :string
|
|
13
16
|
|
|
14
17
|
# Nested restriction
|
|
@@ -31,5 +34,23 @@ module XSD
|
|
|
31
34
|
def linked?
|
|
32
35
|
!name.nil?
|
|
33
36
|
end
|
|
37
|
+
|
|
38
|
+
# Get base data type
|
|
39
|
+
# @return String, nil
|
|
40
|
+
def data_type
|
|
41
|
+
if restriction
|
|
42
|
+
if restriction.base
|
|
43
|
+
restriction.base_simple_type&.data_type || strip_prefix(restriction.base)
|
|
44
|
+
else
|
|
45
|
+
restriction.simple_type&.data_type
|
|
46
|
+
end
|
|
47
|
+
elsif union
|
|
48
|
+
types = union.types.map { |type| type.is_a?(String) ? strip_prefix(type) : type.data_type }.uniq
|
|
49
|
+
types.size == 1 ? types.first : types
|
|
50
|
+
else
|
|
51
|
+
# list is always a sting
|
|
52
|
+
'string'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
34
55
|
end
|
|
35
56
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module XSD
|
|
4
|
+
module Named
|
|
5
|
+
# Get definition namespace
|
|
6
|
+
# @return String
|
|
7
|
+
def namespace
|
|
8
|
+
schema.target_namespace
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Get absolute definition name
|
|
12
|
+
# @return String
|
|
13
|
+
def absolute_name
|
|
14
|
+
name ? "{#{namespace}}#{name}" : nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/xsd/version.rb
CHANGED
data/lib/xsd/xml.rb
CHANGED
data/lib/xsd.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'xsd/base_object'
|
|
4
|
+
require 'xsd/shared/named'
|
|
4
5
|
require 'xsd/shared/min_max_occurs'
|
|
5
6
|
require 'xsd/shared/referenced'
|
|
6
7
|
require 'xsd/shared/attribute_container'
|
|
@@ -37,6 +38,5 @@ require 'xsd/objects/appinfo'
|
|
|
37
38
|
require 'xsd/objects/any_attribute'
|
|
38
39
|
require 'xsd/objects/key'
|
|
39
40
|
require 'xsd/objects/keyref'
|
|
40
|
-
require 'xsd/generator'
|
|
41
41
|
require 'xsd/exceptions'
|
|
42
42
|
require 'xsd/xml'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xsd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- d.arkhipov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-04-
|
|
11
|
+
date: 2024-04-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: builder
|
|
@@ -72,7 +72,6 @@ files:
|
|
|
72
72
|
- lib/xsd.rb
|
|
73
73
|
- lib/xsd/base_object.rb
|
|
74
74
|
- lib/xsd/exceptions.rb
|
|
75
|
-
- lib/xsd/generator.rb
|
|
76
75
|
- lib/xsd/objects/all.rb
|
|
77
76
|
- lib/xsd/objects/annotation.rb
|
|
78
77
|
- lib/xsd/objects/any.rb
|
|
@@ -107,6 +106,7 @@ files:
|
|
|
107
106
|
- lib/xsd/shared/complex_typed.rb
|
|
108
107
|
- lib/xsd/shared/element_container.rb
|
|
109
108
|
- lib/xsd/shared/min_max_occurs.rb
|
|
109
|
+
- lib/xsd/shared/named.rb
|
|
110
110
|
- lib/xsd/shared/referenced.rb
|
|
111
111
|
- lib/xsd/shared/simple_typed.rb
|
|
112
112
|
- lib/xsd/version.rb
|
data/lib/xsd/generator.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
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.collect_attributes
|
|
63
|
-
if element.complex?
|
|
64
|
-
all_elements = element.collect_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.nil?
|
|
81
|
-
attributes[attribute.name] = value
|
|
82
|
-
elsif attribute.required?
|
|
83
|
-
raise Error, "Attribute #{attribute.name} is required, but no data in provided for it" if attribute.fixed.nil?
|
|
84
|
-
|
|
85
|
-
attributes[attribute.name] = attribute.fixed
|
|
86
|
-
else
|
|
87
|
-
attributes.delete(attribute.name)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# generate element
|
|
92
|
-
if element.complex?
|
|
93
|
-
# generate tag recursively
|
|
94
|
-
xml.tag!("#{prefix}:#{element.name}", attributes) do
|
|
95
|
-
all_elements.each do |elem|
|
|
96
|
-
build_element(xml, elem, item, namespaces.dup)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
else
|
|
100
|
-
has_text = item.is_a?(Hash)
|
|
101
|
-
if has_text && element.complex_type&.nodes(:any, true)&.any?
|
|
102
|
-
xml.tag!("#{prefix}:#{element.name}", attributes) { |res| res << item['#text'].to_s }
|
|
103
|
-
else
|
|
104
|
-
value = has_text ? item['#text'] : item
|
|
105
|
-
xml.tag!("#{prefix}:#{element.name}", attributes, (value == '' ? nil : value))
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Get namespace prefix for element
|
|
112
|
-
# @param [Element] element
|
|
113
|
-
# @param [Hash] attributes
|
|
114
|
-
# @param [Hash] namespaces
|
|
115
|
-
# @return String
|
|
116
|
-
def get_namespace_prefix(element, attributes, namespaces)
|
|
117
|
-
namespace = (element.referenced? ? element.reference : element).target_namespace
|
|
118
|
-
prefix = namespaces.key(namespace)
|
|
119
|
-
unless prefix
|
|
120
|
-
prefix = "n#{@namespace_index += 1}"
|
|
121
|
-
namespaces[prefix] = attributes["xmlns:#{prefix}"] = namespace
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
prefix
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# Find root element with provided lookup
|
|
128
|
-
# @param [String, Array<String>, nil] lookup
|
|
129
|
-
def find_root_element(lookup)
|
|
130
|
-
if lookup
|
|
131
|
-
element = self[*lookup]
|
|
132
|
-
raise Error, "Cant find start element #{lookup}" unless element.is_a?(Element)
|
|
133
|
-
|
|
134
|
-
element
|
|
135
|
-
else
|
|
136
|
-
raise Error, 'XSD contains more that one root element. Please, specify starting element' if elements.size > 1
|
|
137
|
-
|
|
138
|
-
elements.first
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def default_builder
|
|
143
|
-
Builder::XmlMarkup.new
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|