Skip to content

Commit

Permalink
added support for elementFormDefault="qualified"
Browse files Browse the repository at this point in the history
fixes #91. the attribute is read from wsdl documents and can also be set
manually via:

    client.request :authenticate do
      soap.element_form_default = :qualified
    end
  • Loading branch information
rubiii committed Jan 26, 2011
1 parent 368db71 commit 5c8ec13
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 30 deletions.
9 changes: 5 additions & 4 deletions lib/savon/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ def wsse
# client.request(:get_user, "xmlns:wsdl" => "http://example.com")
def request(*args, &block)
raise ArgumentError, "Savon::Client#request requires at least one argument" if args.empty?

self.soap = SOAP::XML.new
preconfigure extract_options(args)
process &block if block
soap.wsse = wsse

response = SOAP::Request.new(http, soap).response
set_cookie response.http.headers
response
Expand All @@ -99,7 +99,7 @@ def extract_options(args)
attributes = Hash === args.last ? args.pop : {}
namespace = args.size > 1 ? args.shift.to_sym : nil
input = args.first

[namespace, input, attributes]
end

Expand All @@ -108,8 +108,9 @@ def preconfigure(options)
soap.endpoint = wsdl.endpoint
soap.namespace_identifier = options[0]
soap.namespace = wsdl.namespace
soap.element_form_default = wsdl.element_form_default if wsdl.present?
soap.body = options[2].delete(:body) if options[2][:body]

set_soap_action options[1]
set_soap_input *options
end
Expand Down
12 changes: 11 additions & 1 deletion lib/savon/soap/xml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ def namespace_identifier
@namespace_identifier ||= :wsdl
end

# Returns whether all local elements should be namespaced. Might be set to :qualified,
# but defaults to :unqualified.
def element_form_default
@element_form_default ||= :unqualified
end

# Sets whether all local elements should be namespaced.
attr_writer :element_form_default

# Accessor for the default namespace URI.
attr_accessor :namespace

Expand Down Expand Up @@ -159,7 +168,8 @@ def wsse_header

# Returns the SOAP body as an XML String.
def body_to_xml
body.kind_of?(Hash) ? Gyoku.xml(body) : body.to_s
return body.to_s unless body.kind_of? Hash
Gyoku.xml body, :element_form_default => element_form_default, :namespace => namespace_identifier
end

end
Expand Down
5 changes: 5 additions & 0 deletions lib/savon/wsdl/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ def operations
@operations ||= parser.operations
end

# Returns the elementFormDefault value.
def element_form_default
@element_form_default ||= parser.element_form_default
end

# Sets the location of the WSDL document to use. This can either be a URL
# or a path to a local file.
attr_writer :document
Expand Down
12 changes: 11 additions & 1 deletion lib/savon/wsdl/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ class Parser
Sections = %w(definitions types message portType binding service)

def initialize
@path, @operations, @namespaces = [], {}, {}
@path = []
@operations = {}
@namespaces = {}
@element_form_default = :unqualified
end

# Returns the namespace URI.
Expand All @@ -25,6 +28,9 @@ def initialize
# Returns the SOAP endpoint.
attr_reader :endpoint

# Returns the elementFormDefault value.
attr_reader :element_form_default

# Hook method called when the stream parser encounters a starting tag.
def tag_start(tag, attrs)
# read xml namespaces if root element
Expand All @@ -33,6 +39,10 @@ def tag_start(tag, attrs)
tag, namespace = tag.split(":").reverse
@path << tag

if @section == :types && tag == "schema"
@element_form_default = attrs["elementFormDefault"].to_sym if attrs["elementFormDefault"]
end

if @section == :binding && tag == "binding"
# ensure that we are in an wsdl/soap namespace
@section = nil unless @namespaces[namespace].starts_with? "http://schemas.xmlsoap.org/wsdl/soap"
Expand Down
2 changes: 1 addition & 1 deletion savon.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency "builder", ">= 2.1.2"
s.add_dependency "crack", "~> 0.1.8"
s.add_dependency "httpi", ">= 0.7.8"
s.add_dependency "gyoku", ">= 0.2.0"
s.add_dependency "gyoku", ">= 0.3.0"

s.add_development_dependency "rspec", "~> 2.4.0"
s.add_development_dependency "autotest"
Expand Down
40 changes: 27 additions & 13 deletions spec/savon/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@
it "should set the target namespace with the default identifier" do
namespace = 'xmlns:wsdl="http://v1_0.ws.auth.order.example.com/"'
HTTPI::Request.any_instance.expects(:body=).with { |value| value.include? namespace }

client.request :get_user
end

it "should not set the target namespace if soap.namespace was set to nil" do
namespace = "http://v1_0.ws.auth.order.example.com/"
HTTPI::Request.any_instance.expects(:body=).with { |value| !value.include?(namespace) }

client.request(:get_user) { soap.namespace = nil }
end
end
Expand All @@ -114,14 +114,14 @@
it "should set the target namespace with the given identifier" do
namespace = 'xmlns:v1="http://v1_0.ws.auth.order.example.com/"'
HTTPI::Request.any_instance.expects(:body=).with { |value| value.include? namespace }

client.request :v1, :get_user
end

it "should not set the target namespace if soap.namespace was set to nil" do
namespace = "http://v1_0.ws.auth.order.example.com/"
HTTPI::Request.any_instance.expects(:body=).with { |value| !value.include?(namespace) }

client.request(:v1, :get_user) { soap.namespace = nil }
end
end
Expand Down Expand Up @@ -190,7 +190,7 @@
client.http.headers.expects(:[]=).with("Cookie", anything).never
client.http.headers.stubs(:[]=).with("SOAPAction", '"authenticate"')
client.http.headers.stubs(:[]=).with("Content-Type", "text/xml;charset=UTF-8")

client.request :authenticate
end
end
Expand All @@ -205,7 +205,7 @@
client.http.headers.expects(:[]=).with("Cookie", "some-cookie")
client.http.headers.stubs(:[]=).with("SOAPAction", '"authenticate"')
client.http.headers.stubs(:[]=).with("Content-Type", "text/xml;charset=UTF-8")

client.request :authenticate
end
end
Expand All @@ -220,7 +220,7 @@

it "adds a SOAPAction header containing the SOAP action name" do
HTTPI.stubs(:post).returns(new_response)

client.request :authenticate do
http.headers["SOAPAction"].should == %{"authenticate"}
end
Expand All @@ -229,7 +229,7 @@
it "should execute SOAP requests and return the response" do
HTTPI.expects(:post).returns(new_response)
response = client.request(:authenticate)

response.should be_a(Savon::SOAP::Response)
response.to_xml.should == Fixture.response(:authentication)
end
Expand All @@ -246,16 +246,23 @@

it "adds a SOAPAction header containing the SOAP action name" do
HTTPI.stubs(:post).returns(new_response)

client.request :authenticate do
http.headers["SOAPAction"].should == %{"authenticate"}
end
end

it "should get #element_form_default from the WSDL" do
HTTPI.stubs(:post).returns(new_response)
Savon::WSDL::Document.any_instance.expects(:element_form_default).returns(:qualified)

client.request :authenticate
end

it "should execute SOAP requests and return the response" do
HTTPI.expects(:post).returns(new_response)
response = client.request(:authenticate)

response.should be_a(Savon::SOAP::Response)
response.to_xml.should == Fixture.response(:authentication)
end
Expand All @@ -277,16 +284,23 @@

it "adds a SOAPAction header containing the SOAP action name" do
HTTPI.stubs(:post).returns(new_response)

client.request :authenticate do
http.headers["SOAPAction"].should == %{"authenticate"}
end
end

it "should not get #element_form_default from the WSDL" do
HTTPI.stubs(:post).returns(new_response)
Savon::WSDL::Document.any_instance.expects(:element_form_default).never

client.request :authenticate
end

it "should execute SOAP requests and return the response" do
HTTPI.expects(:post).returns(new_response)
response = client.request(:authenticate)

response.should be_a(Savon::SOAP::Response)
response.to_xml.should == Fixture.response(:authentication)
end
Expand Down Expand Up @@ -325,7 +339,7 @@
def new_response(options = {})
defaults = { :code => 200, :headers => {}, :body => Fixture.response(:authentication) }
response = defaults.merge options

HTTPI::Response.new response[:code], response[:headers], response[:body]
end

Expand Down
17 changes: 17 additions & 0 deletions spec/savon/soap/xml_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,23 @@
end
end

context "with :element_form_default set to :qualified and a :namespace" do
let :xml do
Savon::SOAP::XML.new Endpoint.soap, :authenticate, :user => { :id => 1, ":noNamespace" => true }
end

it "should namespace the default elements" do
xml.element_form_default = :qualified
xml.namespace_identifier = :wsdl

xml.to_xml.should include(
"<wsdl:user>",
"<wsdl:id>1</wsdl:id>",
"<noNamespace>true</noNamespace>"
)
end
end

context "with WSSE authentication" do
it "should containg a SOAP header with WSSE authentication details" do
xml.wsse = Savon::WSSE.new
Expand Down
23 changes: 22 additions & 1 deletion spec/savon/wsdl/document_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,17 @@
let(:wsdl) { Savon::WSDL::Document.new HTTPI::Request.new, Endpoint.wsdl }

before do
response = HTTPI::Response.new(200, {}, Fixture.wsdl(:authentication))
response = HTTPI::Response.new 200, {}, Fixture.wsdl(:authentication)
HTTPI.stubs(:get).returns(response)
end

it_should_behave_like "a WSDL document"

describe "#element_form_default" do
it "should return :unqualified" do
wsdl.element_form_default.should == :unqualified
end
end
end

context "with a local document" do
Expand Down Expand Up @@ -108,4 +114,19 @@
end
end

context "with a WSDL document containing elementFormDefault='qualified'" do
let(:wsdl) { Savon::WSDL::Document.new HTTPI::Request.new, Endpoint.wsdl }

before do
response = HTTPI::Response.new 200, {}, Fixture.wsdl(:geotrust)
HTTPI.stubs(:get).returns(response)
end

describe "#element_form_default" do
it "should return :qualified" do
wsdl.element_form_default.should == :qualified
end
end
end

end
30 changes: 21 additions & 9 deletions spec/savon/wsdl/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,72 @@
context "with namespaced_actions.xml" do
let(:parser) { new_parser :namespaced_actions }

it "should know the target namespace" do
it "should return the target namespace" do
parser.namespace.should == "http://api.example.com/api/"
end

it "should know the SOAP endpoint" do
it "should return the SOAP endpoint" do
parser.endpoint.should == URI("https://api.example.com/api/api.asmx")
end

it "should know the available SOAP operations" do
it "should return the available SOAP operations" do
parser.operations.should match_operations(
:get_api_key => { :input => "GetApiKey", :action => "http://api.example.com/api/User.GetApiKey" },
:delete_client => { :input => "DeleteClient", :action => "http://api.example.com/api/Client.Delete" },
:get_clients => { :input => "GetClients", :action => "http://api.example.com/api/User.GetClients" }
)
end

it "should return that :element_form_default is set to :qualified" do
parser.element_form_default.should == :qualified
end
end

context "with no_namespace.xml" do
let(:parser) { new_parser :no_namespace }

it "should know the target namespace" do
it "should return the target namespace" do
parser.namespace.should == "urn:ActionWebService"
end

it "should know the SOAP endpoint" do
it "should return the SOAP endpoint" do
parser.endpoint.should == URI("http://example.com/api/api")
end

it "should know the available SOAP operations" do
it "should return the available SOAP operations" do
parser.operations.should match_operations(
:search_user => { :input => "SearchUser", :action => "/api/api/SearchUser" },
:get_user_login_by_id => { :input => "GetUserLoginById", :action => "/api/api/GetUserLoginById" },
:get_all_contacts => { :input => "GetAllContacts", :action => "/api/api/GetAllContacts" }
)
end

it "should return that :element_form_default is set to :unqualified" do
parser.element_form_default.should == :unqualified
end
end

context "with geotrust.xml" do
let(:parser) { new_parser :geotrust }

it "should know the target namespace" do
it "should return the target namespace" do
parser.namespace.should == "http://api.geotrust.com/webtrust/query"
end

it "should know the SOAP endpoint" do
it "should return the SOAP endpoint" do
parser.endpoint.should == URI("https://test-api.geotrust.com/webtrust/query.jws")
end

it "should know the available SOAP operations" do
it "should return the available SOAP operations" do
parser.operations.should match_operations(
:get_quick_approver_list => { :input => "GetQuickApproverList", :action => "GetQuickApproverList" },
:hello => { :input => "hello", :action => "hello" }
)
end

it "should return that :element_form_default is set to :qualified" do
parser.element_form_default.should == :qualified
end
end

context "with two_bindings.xml" do
Expand Down

0 comments on commit 5c8ec13

Please sign in to comment.