lib/xsd_reader/shared.rb in xsd-reader-0.0.1 vs lib/xsd_reader/shared.rb in xsd-reader-0.1.0
- old
+ new
@@ -10,37 +10,41 @@
@options = _opts || {}
raise "#{self.class.to_s}.new expects a hash parameter" if !@options.is_a?(Hash)
end
def logger
+ return @logger if @logger
@logger ||= options[:logger] || Logger.new(STDOUT)
+ @logger.level = Logger::WARN
+ return @logger
end
def node
options[:node]
end
def nodes
node.search("./*")
end
- def [](name)
- # got an array of name? recursive search through generations
- if name.is_a?(Array)
- el = self
- name.each{|child_name| el = el.nil? ? nil : el.elements.find{|child| child.name == child_name}}
- return el
- end
+ def [](*args)
+ # now name is always an array
+ names = args.flatten
- # starts with an @-symbol? Then we're looking for an attribute
+ result = self
- if name =~ /^\@/
- attr_name = name.gsub(/^\@/, '')
- return attributes.find{|attr| attr.name == attr_name}
+ names.each do |curname|
+ next if result.nil?
+ if curname.to_s =~ /^\@/
+ attr_name = curname.to_s.gsub(/^\@/, '')
+ result = result.attributes.find{|attr| attr.name == attr_name}
+ else
+ result = result.elements.find{|child| child.name == curname.to_s}
+ end
end
- elements.find{|el| el.name == name}
+ return result
end
#
# attribute properties
#
@@ -58,10 +62,23 @@
def type_namespace
type ? type.split(':').first : nil
end
+ # base stuff belongs to extension type objects only, but let's be flexible
+ def base
+ node.attributes['base'] ? node.attributes['base'].value : nil
+ end
+
+ def base_name
+ base ? base.split(':').last : nil
+ end
+
+ def base_namespace
+ base ? base.split(':').first : nil
+ end
+
#
# Node to class mapping
#
def class_for(n)
class_mapping = {
@@ -70,145 +87,165 @@
'xs:attribute' => Attribute,
'xs:choice' => Choice,
'xs:complexType' => ComplexType,
'xs:sequence' => Sequence,
'xs:simpleContent' => SimpleContent,
- 'xs:extension' => Extension
+ 'xs:complexContent' => ComplexContent,
+ 'xs:extension' => Extension,
+ 'xs:import' => Import,
+ 'xs:simpleType' => SimpleType
}
return class_mapping[n.is_a?(Nokogiri::XML::Node) ? n.name : n]
end
def node_to_object(node)
fullname = [node.namespace ? node.namespace.prefix : nil, node.name].reject{|str| str.nil? || str == ''}.join(':')
klass = class_for(fullname)
# logger.debug "node_to_object, klass: #{klass.to_s}, fullname: #{fullname}"
- klass.nil? ? nil : klass.new(options.merge(:node => node))
+ klass.nil? ? nil : klass.new(options.merge(:node => node, :schema => schema))
end
-
#
# Child objects
#
- def map_children(xml_name, klass = nil)
- klass ||= class_for(xml_name)
- node.search("./#{xml_name}").map{|node| klass.new(options.merge(:node => node))}
+ def mappable_children(xml_name)
+ node.search("./#{xml_name}").to_a
end
+ def map_children(xml_name)
+ # puts "Map Children with #{xml_name} for #{self.class.to_s}"
+ mappable_children(xml_name).map{|current_node| node_to_object(current_node)}
+ end
+
def direct_elements
- map_children("xs:element")
+ @direct_elements ||= map_children("xs:element")
end
def elements
direct_elements
end
- def unordered_elements
- direct_elements + (complex_type ? complex_type.all_elements : []) + sequences.map(&:all_elements).flatten + choices.map(&:all_elements).flatten
- end
-
def ordered_elements
# loop over each interpretable child xml node, and if we can convert a child node
# to an XsdReader object, let it give its compilation of all_elements
nodes.map{|node| node_to_object(node)}.compact.map do |obj|
- obj.is_a?(Element) ? obj : obj.all_elements
+ obj.is_a?(Element) ? obj : obj.ordered_elements
end.flatten
end
def all_elements
- ordered_elements + (linked_complex_type ? linked_complex_type.ordered_elements : [])
+ @all_elements ||= ordered_elements + (linked_complex_type ? linked_complex_type.ordered_elements : [])
end
def child_elements?
elements.length > 0
end
def attributes
- map_children('xs:attribute')
+ @attributes ||= map_children('xs:attribute')
end
def sequences
- map_children("xs:sequence",)
+ @sequences ||= map_children("xs:sequence",)
end
def choices
- map_children("xs:choice")
+ @choices ||= map_children("xs:choice")
end
def complex_types
- map_children("xs:complexType")
+ @complex_types ||= map_children("xs:complexType")
end
def complex_type
- complex_types.first
+ complex_types.first || linked_complex_type
end
def linked_complex_type
- complex_type_by_name(type) || complex_type_by_name(type_name)
+ @linked_complex_type ||= (schema_for_namespace(type_namespace) || schema).complex_types.find{|ct| ct.name == (type_name || type)}
+ #@linked_complex_type ||= object_by_name('xs:complexType', type) || object_by_name('xs:complexType', type_name)
end
def simple_contents
- map_children("xs:simpleContent")
+ @simple_contents ||= map_children("xs:simpleContent")
end
def simple_content
simple_contents.first
end
+ def complex_contents
+ @complex_contents ||= map_children("xs:complexContent")
+ end
+
+ def complex_content
+ complex_contents.first
+ end
+
def extensions
- map_children("xs:extension")
+ @extensions ||= map_children("xs:extension")
end
def extension
extensions.first
end
+ def simple_types
+ @simple_types ||= map_children("xs:simpleType")
+ end
+
+ def linked_simple_type
+ @linked_simple_type ||= object_by_name('xs:simpleType', type) || object_by_name('xs:simpleType', type_name)
+ # @linked_simple_type ||= (type_namespace ? schema_for_namespace(type_namespace) : schema).simple_types.find{|st| st.name == (type_name || type)}
+ end
+
#
# Related objects
#
def parent
if node && node.respond_to?(:parent) && node.parent
+
return node_to_object(node.parent)
end
nil
end
- # def ancestors
- # result = [parent]
-
- # while result.first != nil
- # result.unshift (result.first.respond_to?(:parent) ? result.first.parent : nil)
- # end
-
- # result.compact
- # end
-
def schema
- p = node.parent
+ return options[:schema] if options[:schema]
+ schema_node = node.search('//xs:schema')[0]
+ return schema_node.nil? ? nil : node_to_object(schema_node)
+ end
- while p.name != 'schema' && !p.nil?
- p = p.parent
+ def object_by_name(xml_name, name)
+ # find in local schema, then look in imported schemas
+ nod = node.search("//#{xml_name}[@name=\"#{name}\"]").first
+ return node_to_object(nod) if nod
+
+ # try to find in any of the importers
+ self.schema.imports.each do |import|
+ if obj = import.reader.schema.object_by_name(xml_name, name)
+ return obj
+ end
end
- p.nil? ? nil : node_to_object(p)
- end
- def complex_type_by_name(name)
- ct = node.search("//xs:complexType[@name=\"#{name}\"]").first
- ct.nil? ? nil : ComplexType.new(options.merge(:node => ct))
+ return nil
end
- def elements_by_type(type_name)
- els = schema.node.search("//xs:element[@type=\"#{type_name}\"]")
+ def schema_for_namespace(_namespace)
+ logger.debug "Shared#schema_for_namespace with _namespace: #{_namespace}"
+ return schema if schema.targets_namespace?(_namespace)
- schema.node.search("//xs:element[@type=\"#{type_name}\"]")
-
- while els.length == 0
-
+ if import = schema.import_by_namespace(_namespace)
+ logger.debug "Shared#schema_for_namespace found import schema"
+ return import.reader.schema
end
- end
+ logger.debug "Shared#schema_for_namespace no result"
+ return nil
+ end
end
end # module XsdReader
\ No newline at end of file