Skip to content

Commit

Permalink
Initial support for include element
Browse files Browse the repository at this point in the history
  • Loading branch information
ekzobrain committed Jul 8, 2023
1 parent d3baeb5 commit 40413cd
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 20 deletions.
1 change: 1 addition & 0 deletions lib/xsd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
require 'xsd/objects/complex_content'
require 'xsd/objects/extension'
require 'xsd/objects/import'
require 'xsd/objects/include'
require 'xsd/objects/restriction'
require 'xsd/objects/group'
require 'xsd/objects/all'
Expand Down
21 changes: 20 additions & 1 deletion lib/xsd/objects/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,26 @@ class Extension < BaseObject
TYPE_PROPERTY = nil

include Based
include SimpleTyped
include AttributeContainer

# Nested group
# @!attribute group
# @return Group
child :group, :group

# Nested all
# @!attribute all
# @return All
child :all, :all

# Nested choice
# @!attribute choice
# @return Choice
child :choice, :choice

# Nested sequence
# @!attribute sequence
# @return Sequence
child :sequence, :sequence
end
end
15 changes: 8 additions & 7 deletions lib/xsd/objects/import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ class Import < BaseObject
property :schemaLocation, :string

# Get imported schema
# @return XSD:Schema
# @return Schema
def imported_schema
schema = reader.schema_for_namespace(namespace)
return schema if schema
if (known_schema = reader.schema_for_namespace(namespace))
return known_schema
end

unless schema_location
raise ImportError, "Schema location not provided for namespace '#{namespace}', use add_schema_xml()/add_schema_node()"
end

xml = reader.resource_resolver.call(schema_location, namespace)
schema = reader.add_schema_xml(xml)
new_schema = reader.add_schema_xml(xml)

unless namespace == schema.target_namespace
raise ImportError, 'Import location does not match imported schema targetNamespace'
unless namespace == new_schema.target_namespace
raise ImportError, 'Import namespace does not match imported schema targetNamespace'
end

schema
new_schema
end
end
end
29 changes: 29 additions & 0 deletions lib/xsd/objects/include.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module XSD
# The include element is used to add multiple schemas with the same target namespace to a document.
# Parent elements: schema
# https://www.w3schools.com/xml/el_include.asp
class Include < BaseObject
# Required. Specifies the URI to the schema to include in the target namespace of the containing schema
# @!attribute schema_location
# @return String
property :schemaLocation, :string

# Get imported schema
# @return Schema
def imported_schema
# cache included schema locally as it has no unique namespace to check in global registry
return @imported_schema if @imported_schema

xml = reader.resource_resolver.call(schema_location)
new_schema = reader.add_schema_xml(xml)

unless schema.target_namespace == new_schema.target_namespace
raise ImportError, 'Schema targetNamespace does not match included schema targetNamespace'
end

@imported_schema = new_schema
end
end
end
20 changes: 20 additions & 0 deletions lib/xsd/objects/restriction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@ class Restriction < BaseObject
fractionDigits length minLength maxLength enumeration whiteSpace pattern
].freeze

# Nested group
# @!attribute group
# @return Group
child :group, :group

# Nested all
# @!attribute all
# @return All
child :all, :all

# Nested choice
# @!attribute choice
# @return Choice
child :choice, :choice

# Nested sequence
# @!attribute sequence
# @return Sequence
child :sequence, :sequence

# Get restriction facets
# @return Hash
def facets
Expand Down
18 changes: 12 additions & 6 deletions lib/xsd/objects/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ class Schema < BaseObject
# @return Array<Import>
child :imports, [:import]

# Schema includes
# @!attribute includes
# @return Array<Include>
child :includes, [:include]

# Get current schema object
# @return Schema
def schema
Expand Down Expand Up @@ -122,24 +127,25 @@ def targets_namespace?(namespace)
namespace == target_namespace || namespaces[namespace.empty? ? 'xmlns' : "xmlns:#{namespace}"] == target_namespace
end

# Override map_children on schema to get objects from all imported schemas
# Override map_children on schema to get objects from all loaded schemas
# @param [Symbol] name
# @return Array<BaseObject>
def map_children(name, cache = {})
super(name) + import_map_children(name, cache)
end

# Get children from all imported schemas
# Get children from all loaded schemas
# @param [Symbol] name
# @return Array<BaseObject>
def import_map_children(name, cache)
return [] if name.to_sym == :import
return [] if %i[import include].include?(name.to_sym)

imports.map do |import|
if cache[import.namespace]
(imports + includes).map do |import|
key = import.namespace || include.schema_location
if cache.key?(key)
nil
else
cache[import.namespace] = true
cache[key] = true
import.imported_schema.map_children(name, cache)
end
end.compact.flatten
Expand Down
14 changes: 8 additions & 6 deletions lib/xsd/xml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def read_document(xml)
Nokogiri::XML(xml)
end

# Get imported schema
# Add schema xml to reader instance
# @return XSD:Schema
def add_schema_xml(xml)
doc = read_document(xml)
Expand All @@ -101,15 +101,17 @@ def add_schema_xml(xml)
add_schema_node(doc.root)
end

# Get imported schema
# Add schema node to reader instance. Duplicated namespaces are discarded by default
# @return Schema
def add_schema_node(node)
def add_schema_node(node, force = false)
raise Error, 'Added schema must be of type Nokogiri::XML::Node' unless node.is_a?(Nokogiri::XML::Node)

schema = Schema.new(self.options.merge(node: node, reader: self))
schemas.push(schema)
new_schema = Schema.new(options.merge(node: node, reader: self))
found = schemas.find { |s| s.target_namespace == new_schema.target_namespace }
return found if !found.nil? && !force

schema
schemas.push(new_schema)
new_schema
end

# Add prefixes defined outside of processed schemas, for example in WSDL document
Expand Down

0 comments on commit 40413cd

Please sign in to comment.