Skip to content

Commit

Permalink
Segment parsed types by namespace to avoid clobbering of types with t…
Browse files Browse the repository at this point in the history
…he same type name but different namespaces
  • Loading branch information
Rick Snyder authored and pcai committed Oct 1, 2024
1 parent 78e4e3f commit 153dbf1
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 39 deletions.
22 changes: 13 additions & 9 deletions lib/wasabi/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
31 changes: 16 additions & 15 deletions lib/wasabi/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
75 changes: 75 additions & 0 deletions spec/fixtures/types_with_same_name_in_separate_namespaces.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:article="http://example.com/article"
xmlns:actions="http://example.com/actions"
targetNamespace="http://example.com/actions">
<types>
<s:schema elementFormDefault="qualified" targetNamespace="http://example.com/actions">
<s:element name="Save">
<s:complexType>
<s:sequence>
<s:element name="article" type="article:Article"/>
<s:element name="actionHeader" type="actions:Header" />
<s:element name="articleHeader" type="article:Header" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="Header">
<s:sequence>
<s:element minOccurs="0" name="ActionHeaderField1" type="s:string"/>
<s:element minOccurs="0" name="Description" type="s:string"/>
</s:sequence>
</s:complexType>
</s:schema>
<s:schema elementFormDefault="qualified" targetNamespace="http://example.com/article">
<s:complexType name="Article">
<s:sequence>
<s:element minOccurs="0" name="Author" type="s:string"/>
<s:element minOccurs="0" name="Title" type="s:string"/>
</s:sequence>
</s:complexType>
<s:complexType name="Header">
<s:sequence>
<s:element minOccurs="0" name="ArticleHeaderField1" type="s:string"/>
<s:element minOccurs="0" name="Description" type="s:string"/>
</s:sequence>
</s:complexType>
</s:schema>
</types>
<message name="SaveSoapIn">
<part name="parameters" element="actions:Save"/>
</message>
<message name="SaveSoapOut">
<part name="parameters" element="actions:SaveResponse"/>
</message>
<portType name="ArticleSoap">
<operation name="Save">
<input message="actions:SaveSoapIn"/>
<output message="actions:SaveSoapOut"/>
</operation>
</portType>
<binding name="ArticleSoap" type="actions:ArticleSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="Save">
<soap:operation soapAction="http://example.com/actions.Save" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="StudyMDL">
<port name="StudyMDLSoap" binding="actions:StudyMDLSoap">
<soap:address location="http://example.com:1234/soap"/>
</port>
</service>
</definitions>
8 changes: 4 additions & 4 deletions spec/wasabi/document/inherited_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
19 changes: 12 additions & 7 deletions spec/wasabi/parser/multiple_namespaces_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions spec/wasabi/parser/no_namespace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion spec/wasabi/parser/no_target_namespace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion spec/wasabi/parser/symbolic_endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 153dbf1

Please sign in to comment.