From 153dbf16448502a845097e2a06453ab4b081239b Mon Sep 17 00:00:00 2001 From: Rick Snyder Date: Thu, 16 Apr 2015 12:20:08 -0400 Subject: [PATCH] Segment parsed types by namespace to avoid clobbering of types with the same type name but different namespaces --- lib/wasabi/document.rb | 22 +++--- lib/wasabi/parser.rb | 31 ++++---- ...with_same_name_in_separate_namespaces.wsdl | 75 +++++++++++++++++++ spec/wasabi/document/inherited_spec.rb | 8 +- .../wasabi/parser/multiple_namespaces_spec.rb | 19 +++-- spec/wasabi/parser/no_namespace_spec.rb | 4 +- .../wasabi/parser/no_target_namespace_spec.rb | 2 +- spec/wasabi/parser/symbolic_endpoint_spec.rb | 2 +- ...h_same_name_in_separate_namespaces_spec.rb | 27 +++++++ 9 files changed, 151 insertions(+), 39 deletions(-) create mode 100644 spec/fixtures/types_with_same_name_in_separate_namespaces.wsdl create mode 100644 spec/wasabi/parser/types_with_same_name_in_separate_namespaces_spec.rb diff --git a/lib/wasabi/document.rb b/lib/wasabi/document.rb index 0baddf5..2f10169 100644 --- a/lib/wasabi/document.rb +++ b/lib/wasabi/document.rb @@ -103,11 +103,13 @@ def type_namespaces @type_namespaces ||= begin namespaces = [] - parser.types.each do |type, info| - namespaces << [[type], info[:namespace]] + parser.types.each do |ns, types| + types.each do |type, info| + namespaces << [[type], info[:namespace]] - element_keys(info).each do |field| - namespaces << [[type, field], info[:namespace]] + element_keys(info).each do |field| + namespaces << [[type, field], info[:namespace]] + end end end if document @@ -119,12 +121,14 @@ def type_definitions @type_definitions ||= begin result = [] - parser.types.each do |type, info| - element_keys(info).each do |field| - field_type = info[field][:type] - tag, namespace = field_type.split(":").reverse + parser.types.each do |ns, types| + types.each do |type, info| + element_keys(info).each do |field| + field_type = info[field][:type] + tag, namespace = field_type.split(":").reverse - result << [[type, field], tag] if user_defined(namespace) + result << [[type, field], tag] if user_defined(namespace) + end end end if document diff --git a/lib/wasabi/parser.rb b/lib/wasabi/parser.rb index c6f1b69..5381d86 100644 --- a/lib/wasabi/parser.rb +++ b/lib/wasabi/parser.rb @@ -181,44 +181,45 @@ def parse_types end def process_type(namespace, type, name) - @types[name] ||= { :namespace => namespace } - @types[name][:order!] = [] + @types[namespace] ||= {} + @types[namespace][name] ||= { :namespace => namespace } + @types[namespace][name][:order!] = [] type.xpath('./xs:sequence/xs:element', 'xs' => XSD).each do |inner| element_name = inner.attribute('name').to_s - @types[name][element_name] = { :type => inner.attribute('type').to_s } + @types[namespace][name][element_name] = { :type => inner.attribute('type').to_s } [ :nillable, :minOccurs, :maxOccurs ].each do |attr| if v = inner.attribute(attr.to_s) - @types[name][element_name][attr] = v.to_s + @types[namespace][name][element_name][attr] = v.to_s end end - @types[name][:order!] << element_name + @types[namespace][name][:order!] << element_name end type.xpath('./xs:complexContent/xs:extension/xs:sequence/xs:element', 'xs' => XSD).each do |inner_element| element_name = inner_element.attribute('name').to_s - @types[name][element_name] = { :type => inner_element.attribute('type').to_s } + @types[namespace][name][element_name] = { :type => inner_element.attribute('type').to_s } - @types[name][:order!] << element_name + @types[namespace][name][:order!] << element_name end type.xpath('./xs:complexContent/xs:extension[@base]', 'xs' => XSD).each do |inherits| base = inherits.attribute('base').value.match(/\w+$/).to_s - if @types[base] + if @types[namespace][base] # Reverse merge because we don't want subclass attributes to be overriden by base class - @types[name] = types[base].merge(types[name]) - @types[name][:order!] = @types[base][:order!] | @types[name][:order!] - @types[name][:base_type] = base + @types[namespace][name] = types[namespace][base].merge(types[namespace][name]) + @types[namespace][name][:order!] = @types[namespace][base][:order!] | @types[namespace][name][:order!] + @types[namespace][name][:base_type] = base else p = Proc.new do - if @types[base] + if @types[namespace][base] # Reverse merge because we don't want subclass attributes to be overriden by base class - @types[name] = @types[base].merge(@types[name]) - @types[name][:order!] = @types[base][:order!] | @types[name][:order!] - @types[name][:base_type] = base + @types[namespace][name] = @types[namespace][base].merge(@types[namespace][name]) + @types[namespace][name][:order!] = @types[namespace][base][:order!] | @types[namespace][name][:order!] + @types[namespace][name][:base_type] = base end end deferred_types << p diff --git a/spec/fixtures/types_with_same_name_in_separate_namespaces.wsdl b/spec/fixtures/types_with_same_name_in_separate_namespaces.wsdl new file mode 100644 index 0000000..86d3c6e --- /dev/null +++ b/spec/fixtures/types_with_same_name_in_separate_namespaces.wsdl @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/wasabi/document/inherited_spec.rb b/spec/wasabi/document/inherited_spec.rb index fac55b8..7762594 100644 --- a/spec/wasabi/document/inherited_spec.rb +++ b/spec/wasabi/document/inherited_spec.rb @@ -19,20 +19,20 @@ end it "should position base class attributes before subclass attributes in :order! array" do - account = subject.parser.types["Account"] + account = subject.parser.types['http://object.api.example.com/']["Account"] expect(account[:order!]).to eq(["fieldsToNull", "Id", "Description", "ProcessId", "CreatedDate"]) end it "should have each type's hash remember it's base type in :base_type element" do - account = subject.parser.types["Account"] + account = subject.parser.types['http://object.api.example.com/']["Account"] expect(account[:base_type]).to eq("baseObject") - base_object = subject.parser.types["baseObject"] + base_object = subject.parser.types['http://object.api.example.com/']["baseObject"] expect(base_object).not_to have_key(:base_type) end it "should have element's hash contain all these attributes (:nillable, :minOccurs, :maxOccurs) in addition to :type" do - base_object = subject.parser.types["baseObject"] + base_object = subject.parser.types['http://object.api.example.com/']["baseObject"] fields_to_null = base_object["fieldsToNull"] expect(fields_to_null[:nillable]).to eq("true") expect(fields_to_null[:minOccurs]).to eq("0") diff --git a/spec/wasabi/parser/multiple_namespaces_spec.rb b/spec/wasabi/parser/multiple_namespaces_spec.rb index 033e4f3..0b6a890 100644 --- a/spec/wasabi/parser/multiple_namespaces_spec.rb +++ b/spec/wasabi/parser/multiple_namespaces_spec.rb @@ -13,29 +13,34 @@ let(:xml) { fixture(:multiple_namespaces).read } - it "lists the types" do - expect(subject.types.keys.sort).to eq(["Article", "Save"]) + it "lists the namespaces" do + expect(subject.types.keys.sort).to eq(["http://example.com/actions", "http://example.com/article"]) + end + + it "lists the types for each namespace" do + expect(subject.types['http://example.com/actions'].keys.sort).to eq(["Save"]) + expect(subject.types['http://example.com/article'].keys.sort).to eq(["Article"]) end it "records the namespace for each type" do - expect(subject.types["Save"][:namespace]).to eq("http://example.com/actions") + expect(subject.types["http://example.com/actions"]["Save"][:namespace]).to eq("http://example.com/actions") end it "records the fields under a type" do - expect(subject.types["Save"].keys).to match_array(["article", :namespace, :order!]) + expect(subject.types['http://example.com/actions']["Save"].keys).to match_array(["article", :namespace, :order!]) end it "records multiple fields when there are more than one" do - expect(subject.types["Article"].keys).to match_array(["Title", "Author", :namespace, :order!]) + expect(subject.types['http://example.com/article']["Article"].keys).to match_array(["Title", "Author", :namespace, :order!]) end it "records the type of a field" do - expect(subject.types["Save"]["article"][:type]).to eq("article:Article") + expect(subject.types['http://example.com/actions']["Save"]["article"][:type]).to eq("article:Article") expect(subject.namespaces["article"]).to eq("http://example.com/article") end it "lists the order of the type elements" do - expect(subject.types["Article"][:order!]).to eq(["Author", "Title"]) + expect(subject.types['http://example.com/article']["Article"][:order!]).to eq(["Author", "Title"]) end end diff --git a/spec/wasabi/parser/no_namespace_spec.rb b/spec/wasabi/parser/no_namespace_spec.rb index d3ce8ab..032a3db 100644 --- a/spec/wasabi/parser/no_namespace_spec.rb +++ b/spec/wasabi/parser/no_namespace_spec.rb @@ -14,11 +14,11 @@ let(:xml) { fixture(:no_namespace).read } it "lists the types" do - expect(subject.types.keys.sort).to eq(["McContact", "McContactArray", "MpUser", "MpUserArray"]) + expect(subject.types['urn:ActionWebService'].keys.sort).to eq(["McContact", "McContactArray", "MpUser", "MpUserArray"]) end it "ignores xsd:all" do - keys = subject.types["MpUser"].keys + keys = subject.types['urn:ActionWebService']["MpUser"].keys expect(keys.size).to eq(2) expect(keys).to include(:namespace) diff --git a/spec/wasabi/parser/no_target_namespace_spec.rb b/spec/wasabi/parser/no_target_namespace_spec.rb index 6b5b603..9d960a1 100644 --- a/spec/wasabi/parser/no_target_namespace_spec.rb +++ b/spec/wasabi/parser/no_target_namespace_spec.rb @@ -31,7 +31,7 @@ # but I suppose we should do something reasonable if they do. it "defaults to the target namespace from xs:definitions" do - expect(subject.types["Save"][:namespace]).to eq("http://def.example.com") + expect(subject.types["http://def.example.com"]["Save"][:namespace]).to eq("http://def.example.com") end end diff --git a/spec/wasabi/parser/symbolic_endpoint_spec.rb b/spec/wasabi/parser/symbolic_endpoint_spec.rb index 00dec7b..14c1bd6 100644 --- a/spec/wasabi/parser/symbolic_endpoint_spec.rb +++ b/spec/wasabi/parser/symbolic_endpoint_spec.rb @@ -15,7 +15,7 @@ end it "should position base class attributes before subclass attributes in :order! array" do - type = parser.types["ROPtsLiesListe"] + type = subject.types["http://model.webservices.partner.example.de"]["ROPtsLiesListe"] expect(type[:order!]).to eq(["messages", "returncode", "listenteil"]) end diff --git a/spec/wasabi/parser/types_with_same_name_in_separate_namespaces_spec.rb b/spec/wasabi/parser/types_with_same_name_in_separate_namespaces_spec.rb new file mode 100644 index 0000000..71a7a71 --- /dev/null +++ b/spec/wasabi/parser/types_with_same_name_in_separate_namespaces_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Wasabi::Parser do + context 'with: types_with_same_name_in_separate_namespaces.wsdl' do + subject do + parser = Wasabi::Parser.new Nokogiri::XML(xml) + parser.parse + parser + end + + let(:xml) { fixture(:types_with_same_name_in_separate_namespaces).read } + + it 'parses two types in separate namespaces' do + expect(subject.types['http://example.com/article'].keys.sort).to eq(['Article', 'Header']) + expect(subject.types['http://example.com/actions'].keys.sort).to eq(['Header', 'Save']) + end + + it 'assigns the correct type to the appropriate namespace' do + expect(subject.types['http://example.com/article']['Header'][:order!]).to eq(['ArticleHeaderField1', 'Description']) + expect(subject.types['http://example.com/article']['Header'][:namespace]).to eq('http://example.com/article') + + expect(subject.types['http://example.com/actions']['Header'][:order!]).to eq(['ActionHeaderField1', 'Description']) + expect(subject.types['http://example.com/actions']['Header'][:namespace]).to eq('http://example.com/actions') + end + + end +end