xsd 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee4b9e2059eeb7c7109e687ca866c3617514e167f2d93de816d452fdf01be85b
4
- data.tar.gz: ee5451af6e745dbdfffc55fa26329fd2c68b3257699a6e65fd923da3278769ea
3
+ metadata.gz: d3b12830c536c37e72b109727f470d45de29b6c852e62476cd3aa5578dd3b9c7
4
+ data.tar.gz: 248b65a3794a6c83a6aca695b0d565d55b971991272fd5f7f0a8a841fb8847ec
5
5
  SHA512:
6
- metadata.gz: c937c9501cac27b7d1a003d34feec5fc927663656793c0e2a4abb62112f7b36ee7001532eccc1f1557913c23355feddab616a9df493fe2c7556fb3eaa74d50ce
7
- data.tar.gz: 588d4649a016ed883a401447435a3a01512a610d1bc5b46b8abae0d6b0367ffe2369073f4f0f8bdb834643321f2a22eda196d89315d6e84f3b0222f4eee0c622
6
+ metadata.gz: ac15d2c2c163bd70f007fd76b5c007fbc786ed09d5609a2d6dba5aa8836144917a5159a32c1b7f47aa250bd18034d8339f445180fc4cd330745138ec60283e32
7
+ data.tar.gz: 7db0b9ac2ba0c97aab16d84db5145b4a8a18c901f3c24c8fd13a73b96a1998083a41cff38c3b0f7098dc53457b693e0ee5d3d941ceb1712f38a54924d32ce544
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.1.0] - 2023-07-10
4
+
5
+ - Add support for <xs:include> element
6
+ - Changed method "schema_for_namespace(namespace) -> XSD::Schema" signature to "schemas_for_namespace(namespace) -> Array<XSD::Schema>"
7
+
3
8
  ## [2.0.0] - 2023-07-07
4
9
 
5
10
  - Change XSD::XML.new(file, **options) -> XSD::XML.open(file, **options)
data/README.md CHANGED
@@ -28,20 +28,29 @@ require 'xsd'
28
28
  # Load ruby-xsd
29
29
  reader = XSD::XML.open('some.xsd')
30
30
 
31
+ # Get elements and their child elements
32
+ element = reader['NewReleaseMessage']
33
+ element.collect_elements.map(&:name) # => ['MessageHeader', 'UpdateIndicator', 'IsBackfill', 'CatalogTransfer', 'WorkList', 'CueSheetList', 'ResourceList', 'CollectionList', 'ReleaseList', 'DealList']
34
+
31
35
  # Get attributes
32
36
  attribute = reader['NewReleaseMessage']['@MessageSchemaVersionId']
33
37
 
34
- # Get atrribute information
38
+ # Get attribute information
35
39
  attribute.name # => 'MessageSchemaVersionId'
36
40
  attribute.type # => 'xs:string'
37
41
  attribute.required? # => true
42
+ attribute.optional? # => false
43
+ attribute.prohibited? # => true
38
44
 
39
45
  # Get element information
40
- element = reader['NewReleaseMessage']['ResourceList']['SoundRecording']
46
+ element = reader['NewReleaseMessage']['ResourceList']['SoundRecording'] # => XSD::Element
41
47
  element.min_occurs # => 0
42
48
  element.max_occurs # => :unbounded
43
49
  element.type # => 'ern:SoundRecording'
44
50
  element.complex_type # => XSD::ComplexType
51
+ element.complex? # => true
52
+ element.multiple_allowed? # => true
53
+ element.required? # => false
45
54
  ```
46
55
 
47
56
  ## Development
@@ -67,13 +67,13 @@ module XSD
67
67
  end
68
68
 
69
69
  # Get schema by namespace or namespace prefix
70
- # @param [String] namespace
71
- # @return Schema
72
- def schema_for_namespace(namespace)
70
+ # @param [String, nil] namespace
71
+ # @return Array<Schema>
72
+ def schemas_for_namespace(namespace)
73
73
  if schema.targets_namespace?(namespace)
74
- schema
74
+ [schema, *schema.includes.map(&:imported_schema)]
75
75
  elsif (import = schema.import_by_namespace(namespace))
76
- import.imported_schema
76
+ [import.imported_schema]
77
77
  else
78
78
  raise Error, "Schema not found for namespace '#{namespace}' in '#{schema.id || schema.target_namespace}'"
79
79
  end
@@ -112,12 +112,15 @@ module XSD
112
112
  return nil if schema.namespace_prefix == name_prefix
113
113
 
114
114
  # determine schema for namespace
115
- search_schema = schema_for_namespace(name_prefix)
115
+ search_schemas = schemas_for_namespace(name_prefix)
116
116
 
117
117
  # find element in target schema
118
- result = search_schema.node.xpath("./xs:#{node_name}[@name=\"#{name_local}\"]", { 'xs' => XML_SCHEMA }).first
118
+ search_schemas.each do |s|
119
+ node = s.node.xpath("./xs:#{node_name}[@name=\"#{name_local}\"]", { 'xs' => XML_SCHEMA }).first
120
+ return s.node_to_object(node) if node
121
+ end
119
122
 
120
- result ? search_schema.node_to_object(result) : nil
123
+ nil
121
124
  end
122
125
 
123
126
  # Get reader object for node
@@ -169,9 +172,9 @@ module XSD
169
172
 
170
173
  # Get namespace prefix from node name
171
174
  # @param [String, nil] name Name to strip from
172
- # @return String
175
+ # @return String, nil
173
176
  def get_prefix(name)
174
- name&.include?(':') ? name.split(':').first : ''
177
+ name&.include?(':') ? name.split(':').first : nil
175
178
  end
176
179
 
177
180
  # Return element documentation
@@ -8,7 +8,26 @@ module XSD
8
8
  TYPE_PROPERTY = nil
9
9
 
10
10
  include Based
11
- include SimpleTyped
12
11
  include AttributeContainer
12
+
13
+ # Nested group
14
+ # @!attribute group
15
+ # @return Group
16
+ child :group, :group
17
+
18
+ # Nested all
19
+ # @!attribute all
20
+ # @return All
21
+ child :all, :all
22
+
23
+ # Nested choice
24
+ # @!attribute choice
25
+ # @return Choice
26
+ child :choice, :choice
27
+
28
+ # Nested sequence
29
+ # @!attribute sequence
30
+ # @return Sequence
31
+ child :sequence, :sequence
13
32
  end
14
33
  end
@@ -16,23 +16,23 @@ module XSD
16
16
  property :schemaLocation, :string
17
17
 
18
18
  # Get imported schema
19
- # @return XSD:Schema
19
+ # @return Schema
20
20
  def imported_schema
21
- schema = reader.schema_for_namespace(namespace)
22
- return schema if schema
21
+ known_schemas = reader.schemas_for_namespace(namespace)
22
+ return known_schemas.first if known_schemas.any?
23
23
 
24
24
  unless schema_location
25
25
  raise ImportError, "Schema location not provided for namespace '#{namespace}', use add_schema_xml()/add_schema_node()"
26
26
  end
27
27
 
28
28
  xml = reader.resource_resolver.call(schema_location, namespace)
29
- schema = reader.add_schema_xml(xml)
29
+ new_schema = reader.add_schema_xml(xml)
30
30
 
31
- unless namespace == schema.target_namespace
32
- raise ImportError, 'Import location does not match imported schema targetNamespace'
31
+ unless namespace == new_schema.target_namespace
32
+ raise ImportError, 'Import namespace does not match imported schema targetNamespace'
33
33
  end
34
34
 
35
- schema
35
+ new_schema
36
36
  end
37
37
  end
38
38
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XSD
4
+ # The include element is used to add multiple schemas with the same target namespace to a document.
5
+ # Parent elements: schema
6
+ # https://www.w3schools.com/xml/el_include.asp
7
+ class Include < BaseObject
8
+ # Required. Specifies the URI to the schema to include in the target namespace of the containing schema
9
+ # @!attribute schema_location
10
+ # @return String
11
+ property :schemaLocation, :string
12
+
13
+ # Get imported schema
14
+ # @return Schema
15
+ def imported_schema
16
+ # cache included schema locally as it has no unique namespace to check in global registry
17
+ return @imported_schema if @imported_schema
18
+
19
+ xml = reader.resource_resolver.call(schema_location)
20
+ new_schema = reader.add_schema_xml(xml)
21
+
22
+ unless schema.target_namespace == new_schema.target_namespace
23
+ raise ImportError, 'Schema targetNamespace does not match included schema targetNamespace'
24
+ end
25
+
26
+ @imported_schema = new_schema
27
+ end
28
+ end
29
+ end
@@ -16,6 +16,26 @@ module XSD
16
16
  fractionDigits length minLength maxLength enumeration whiteSpace pattern
17
17
  ].freeze
18
18
 
19
+ # Nested group
20
+ # @!attribute group
21
+ # @return Group
22
+ child :group, :group
23
+
24
+ # Nested all
25
+ # @!attribute all
26
+ # @return All
27
+ child :all, :all
28
+
29
+ # Nested choice
30
+ # @!attribute choice
31
+ # @return Choice
32
+ child :choice, :choice
33
+
34
+ # Nested sequence
35
+ # @!attribute sequence
36
+ # @return Sequence
37
+ child :sequence, :sequence
38
+
19
39
  # Get restriction facets
20
40
  # @return Hash
21
41
  def facets
@@ -85,6 +85,11 @@ module XSD
85
85
  # @return Array<Import>
86
86
  child :imports, [:import]
87
87
 
88
+ # Schema includes
89
+ # @!attribute includes
90
+ # @return Array<Include>
91
+ child :includes, [:include]
92
+
88
93
  # Get current schema object
89
94
  # @return Schema
90
95
  def schema
@@ -116,30 +121,31 @@ module XSD
116
121
  end
117
122
 
118
123
  # Check if namespace is a target namespace
119
- # @param [String] namespace
124
+ # @param [String, nil] namespace
120
125
  # @return Boolean
121
126
  def targets_namespace?(namespace)
122
127
  namespace == target_namespace || namespaces[namespace.empty? ? 'xmlns' : "xmlns:#{namespace}"] == target_namespace
123
128
  end
124
129
 
125
- # Override map_children on schema to get objects from all imported schemas
130
+ # Override map_children on schema to get objects from all loaded schemas
126
131
  # @param [Symbol] name
127
132
  # @return Array<BaseObject>
128
133
  def map_children(name, cache = {})
129
134
  super(name) + import_map_children(name, cache)
130
135
  end
131
136
 
132
- # Get children from all imported schemas
137
+ # Get children from all loaded schemas
133
138
  # @param [Symbol] name
134
139
  # @return Array<BaseObject>
135
140
  def import_map_children(name, cache)
136
- return [] if name.to_sym == :import
141
+ return [] if %i[import include].include?(name.to_sym)
137
142
 
138
- imports.map do |import|
139
- if cache[import.namespace]
143
+ (includes + imports).map do |import|
144
+ key = import.respond_to?(:namespace) && import.namespace ? import.namespace : import.schema_location
145
+ if cache.key?(key)
140
146
  nil
141
147
  else
142
- cache[import.namespace] = true
148
+ cache[key] = true
143
149
  import.imported_schema.map_children(name, cache)
144
150
  end
145
151
  end.compact.flatten
data/lib/xsd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XSD
4
- VERSION = '2.0.0'
4
+ VERSION = '2.1.0'
5
5
  end
data/lib/xsd/xml.rb CHANGED
@@ -31,6 +31,7 @@ module XSD
31
31
  'complexContent' => ComplexContent,
32
32
  'extension' => Extension,
33
33
  'import' => Import,
34
+ 'include' => Include,
34
35
  'simpleType' => SimpleType,
35
36
  'all' => All,
36
37
  'restriction' => Restriction,
@@ -63,6 +64,10 @@ module XSD
63
64
  'pattern' => Facet
64
65
  }.freeze
65
66
 
67
+ # Create reader from a file path
68
+ # @param [String] path
69
+ # @param [Hash] options
70
+ # @return XML
66
71
  def self.open(path, **options)
67
72
  reader = new(**options)
68
73
  reader.add_schema_xml(File.read(path))
@@ -92,8 +97,8 @@ module XSD
92
97
  Nokogiri::XML(xml)
93
98
  end
94
99
 
95
- # Get imported schema
96
- # @return XSD:Schema
100
+ # Add schema xml to reader instance
101
+ # @return Schema
97
102
  def add_schema_xml(xml)
98
103
  doc = read_document(xml)
99
104
  raise Error, 'Schema node not found, xml does not seem to be a valid XSD' unless doc.root&.name == 'schema'
@@ -101,15 +106,14 @@ module XSD
101
106
  add_schema_node(doc.root)
102
107
  end
103
108
 
104
- # Get imported schema
109
+ # Add schema node to reader instance
105
110
  # @return Schema
106
111
  def add_schema_node(node)
107
112
  raise Error, 'Added schema must be of type Nokogiri::XML::Node' unless node.is_a?(Nokogiri::XML::Node)
108
113
 
109
- schema = Schema.new(self.options.merge(node: node, reader: self))
110
- schemas.push(schema)
111
-
112
- schema
114
+ new_schema = Schema.new(options.merge(node: node, reader: self))
115
+ schemas.push(new_schema)
116
+ new_schema
113
117
  end
114
118
 
115
119
  # Add prefixes defined outside of processed schemas, for example in WSDL document
@@ -126,10 +130,11 @@ module XSD
126
130
  end
127
131
 
128
132
  # Get schema by namespace or namespace prefix
129
- # @return Schema, nil
130
- def schema_for_namespace(namespace)
133
+ # @param [String, nil] namespace
134
+ # @return Array<Schema>
135
+ def schemas_for_namespace(namespace)
131
136
  namespace = namespace_prefixes[namespace] if namespace_prefixes.key?(namespace)
132
- schemas.find { |schema| schema.target_namespace == namespace }
137
+ schemas.select { |schema| schema.target_namespace == namespace }
133
138
  end
134
139
 
135
140
  def [](*args)
data/lib/xsd.rb CHANGED
@@ -18,6 +18,7 @@ require 'xsd/objects/simple_content'
18
18
  require 'xsd/objects/complex_content'
19
19
  require 'xsd/objects/extension'
20
20
  require 'xsd/objects/import'
21
+ require 'xsd/objects/include'
21
22
  require 'xsd/objects/restriction'
22
23
  require 'xsd/objects/group'
23
24
  require 'xsd/objects/all'
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.0.0
4
+ version: 2.1.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: 2023-07-07 00:00:00.000000000 Z
11
+ date: 2023-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: builder
@@ -90,6 +90,7 @@ files:
90
90
  - lib/xsd/objects/field.rb
91
91
  - lib/xsd/objects/group.rb
92
92
  - lib/xsd/objects/import.rb
93
+ - lib/xsd/objects/include.rb
93
94
  - lib/xsd/objects/key.rb
94
95
  - lib/xsd/objects/keyref.rb
95
96
  - lib/xsd/objects/list.rb