savon 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +119 -104
- data/README.md +12 -11
- data/Rakefile +0 -6
- data/lib/savon.rb +16 -14
- data/lib/savon/block_interface.rb +26 -0
- data/lib/savon/builder.rb +142 -0
- data/lib/savon/client.rb +36 -135
- data/lib/savon/header.rb +42 -0
- data/lib/savon/http_error.rb +27 -0
- data/lib/savon/log_message.rb +23 -25
- data/lib/savon/message.rb +35 -0
- data/lib/savon/mock.rb +5 -0
- data/lib/savon/mock/expectation.rb +70 -0
- data/lib/savon/mock/spec_helper.rb +62 -0
- data/lib/savon/model.rb +39 -61
- data/lib/savon/operation.rb +62 -0
- data/lib/savon/options.rb +265 -0
- data/lib/savon/qualified_message.rb +49 -0
- data/lib/savon/request.rb +92 -0
- data/lib/savon/response.rb +97 -0
- data/lib/savon/soap_fault.rb +40 -0
- data/lib/savon/version.rb +1 -1
- data/savon.gemspec +10 -8
- data/spec/integration/options_spec.rb +536 -0
- data/spec/integration/request_spec.rb +31 -16
- data/spec/integration/support/application.rb +80 -0
- data/spec/integration/support/server.rb +84 -0
- data/spec/savon/builder_spec.rb +81 -0
- data/spec/savon/client_spec.rb +90 -488
- data/spec/savon/http_error_spec.rb +49 -0
- data/spec/savon/log_message_spec.rb +33 -0
- data/spec/savon/mock_spec.rb +127 -0
- data/spec/savon/model_spec.rb +110 -99
- data/spec/savon/observers_spec.rb +92 -0
- data/spec/savon/operation_spec.rb +49 -0
- data/spec/savon/request_spec.rb +145 -0
- data/spec/savon/{soap/response_spec.rb → response_spec.rb} +22 -59
- data/spec/savon/soap_fault_spec.rb +94 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/support/fixture.rb +5 -1
- metadata +202 -197
- data/lib/savon/config.rb +0 -46
- data/lib/savon/error.rb +0 -6
- data/lib/savon/hooks/group.rb +0 -68
- data/lib/savon/hooks/hook.rb +0 -61
- data/lib/savon/http/error.rb +0 -42
- data/lib/savon/logger.rb +0 -39
- data/lib/savon/null_logger.rb +0 -10
- data/lib/savon/soap.rb +0 -21
- data/lib/savon/soap/fault.rb +0 -59
- data/lib/savon/soap/invalid_response_error.rb +0 -13
- data/lib/savon/soap/request.rb +0 -86
- data/lib/savon/soap/request_builder.rb +0 -205
- data/lib/savon/soap/response.rb +0 -117
- data/lib/savon/soap/xml.rb +0 -257
- data/spec/savon/config_spec.rb +0 -38
- data/spec/savon/hooks/group_spec.rb +0 -71
- data/spec/savon/hooks/hook_spec.rb +0 -16
- data/spec/savon/http/error_spec.rb +0 -52
- data/spec/savon/logger_spec.rb +0 -51
- data/spec/savon/savon_spec.rb +0 -33
- data/spec/savon/soap/fault_spec.rb +0 -89
- data/spec/savon/soap/request_builder_spec.rb +0 -207
- data/spec/savon/soap/request_spec.rb +0 -112
- data/spec/savon/soap/xml_spec.rb +0 -357
- data/spec/savon/soap_spec.rb +0 -16
@@ -1,205 +0,0 @@
|
|
1
|
-
module Savon
|
2
|
-
module SOAP
|
3
|
-
|
4
|
-
# = Savon::SOAP::RequestBuilder
|
5
|
-
#
|
6
|
-
# Savon::SOAP::RequestBuilder builds Savon::SOAP::Request instances.
|
7
|
-
# The RequestBuilder is configured by the client that instantiates it.
|
8
|
-
# It uses the options set by the client to build an appropriate request.
|
9
|
-
class RequestBuilder
|
10
|
-
|
11
|
-
# Initialize a new +RequestBuilder+ with the given SOAP operation.
|
12
|
-
# The operation may be specified using a symbol or a string.
|
13
|
-
def initialize(operation, options = {})
|
14
|
-
@operation = operation
|
15
|
-
assign_options(options)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Writer for the <tt>HTTPI::Request</tt> object.
|
19
|
-
attr_writer :http
|
20
|
-
|
21
|
-
# Writer for the <tt>Savon::SOAP::XML</tt> object.
|
22
|
-
attr_writer :soap
|
23
|
-
|
24
|
-
# Writer for the <tt>Akami::WSSE</tt> object.
|
25
|
-
attr_writer :wsse
|
26
|
-
|
27
|
-
# Writer for the <tt>Wasabi::Document</tt> object.
|
28
|
-
attr_writer :wsdl
|
29
|
-
|
30
|
-
# Writer for the <tt>Savon::Config</tt> object.
|
31
|
-
attr_writer :config
|
32
|
-
|
33
|
-
# Writer for the attributes of the SOAP input tag. Accepts a Hash.
|
34
|
-
attr_writer :attributes
|
35
|
-
|
36
|
-
# Writer for the namespace identifer of the <tt>Savon::SOAP::XML</tt>
|
37
|
-
# object.
|
38
|
-
attr_writer :namespace_identifier
|
39
|
-
|
40
|
-
# Writer for the SOAP action of the <tt>Savon::SOAP::XML</tt> object.
|
41
|
-
attr_writer :soap_action
|
42
|
-
|
43
|
-
# Reader for the operation of the request being built by the request builder.
|
44
|
-
attr_reader :operation
|
45
|
-
|
46
|
-
# Builds and returns a <tt>Savon::SOAP::Request</tt> object. You may optionally
|
47
|
-
# pass a block to the method that will be run after the initial configuration of
|
48
|
-
# the dependencies. +self+ will be yielded to the block if the block accepts an
|
49
|
-
# argument.
|
50
|
-
def request(&post_configuration_block)
|
51
|
-
configure_dependencies
|
52
|
-
|
53
|
-
if post_configuration_block
|
54
|
-
# Only yield self to the block if our block takes an argument
|
55
|
-
args = [] and (args << self if post_configuration_block.arity == 1)
|
56
|
-
post_configuration_block.call(*args)
|
57
|
-
end
|
58
|
-
|
59
|
-
Request.new(config, http, soap)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Returns the identifier for the default namespace. If an operation namespace
|
63
|
-
# identifier is defined for the current operation in the WSDL document, this
|
64
|
-
# namespace identifier is used. Otherwise, the +@namespace_identifier+ instance
|
65
|
-
# variable is used.
|
66
|
-
def namespace_identifier
|
67
|
-
if operation_namespace_defined_in_wsdl?
|
68
|
-
wsdl.operations[operation][:namespace_identifier].to_sym
|
69
|
-
else
|
70
|
-
@namespace_identifier
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns the namespace identifier to be used for the the SOAP input tag.
|
75
|
-
# If +@namespace_identifier+ is not +nil+, it will be returned. Otherwise, the
|
76
|
-
# default namespace identifier as returned by +namespace_identifier+ will be
|
77
|
-
# returned.
|
78
|
-
def input_namespace_identifier
|
79
|
-
@namespace_identifier || namespace_identifier
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns the default namespace to be used for the SOAP request. If a namespace
|
83
|
-
# is defined for the operation in the WSDL document, this namespace will be
|
84
|
-
# returned. Otherwise, the default WSDL document namespace will be returned.
|
85
|
-
def namespace
|
86
|
-
if operation_namespace_defined_in_wsdl?
|
87
|
-
wsdl.parser.namespaces[namespace_identifier.to_s]
|
88
|
-
else
|
89
|
-
wsdl.namespace
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Returns true if the operation's namespace is defined within the WSDL
|
94
|
-
# document.
|
95
|
-
def operation_namespace_defined_in_wsdl?
|
96
|
-
return false unless wsdl.document?
|
97
|
-
(operation = wsdl.operations[self.operation]) && operation[:namespace_identifier]
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns the SOAP action. If +@soap_action+ has been defined, this will
|
101
|
-
# be returned. Otherwise, if there is a WSDL document defined, the SOAP
|
102
|
-
# action corresponding to the operation will be returned. Failing this,
|
103
|
-
# the operation name will be used to form the SOAP action.
|
104
|
-
def soap_action
|
105
|
-
return @soap_action if @soap_action
|
106
|
-
|
107
|
-
if wsdl.document?
|
108
|
-
wsdl.soap_action(operation.to_sym)
|
109
|
-
else
|
110
|
-
Gyoku::XMLKey.create(operation).to_sym
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Returns the SOAP operation input tag. If there is a WSDL document defined,
|
115
|
-
# and the operation's input tag is defined in the document, this will be
|
116
|
-
# returned. Otherwise, the operation name will be used to form the input tag.
|
117
|
-
def soap_input_tag
|
118
|
-
if wsdl.document? && (input = wsdl.soap_input(operation.to_sym))
|
119
|
-
input
|
120
|
-
else
|
121
|
-
Gyoku::XMLKey.create(operation)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# Changes the body of the SOAP request to +body+.
|
126
|
-
def body=(body)
|
127
|
-
soap.body = body
|
128
|
-
end
|
129
|
-
|
130
|
-
# Returns the body of the SOAP request.
|
131
|
-
def body
|
132
|
-
soap.body
|
133
|
-
end
|
134
|
-
|
135
|
-
# Returns the attributes of the SOAP input tag. Defaults to
|
136
|
-
# an empty Hash.
|
137
|
-
def attributes
|
138
|
-
@attributes ||= {}
|
139
|
-
end
|
140
|
-
|
141
|
-
# Returns the <tt>Savon::Config</tt> object for the request. Defaults
|
142
|
-
# to a clone of <tt>Savon.config</tt>.
|
143
|
-
def config
|
144
|
-
@config ||= Savon.config.clone
|
145
|
-
end
|
146
|
-
|
147
|
-
# Returns the <tt>HTTPI::Request</tt> object.
|
148
|
-
def http
|
149
|
-
@http ||= HTTPI::Request.new
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns the <tt>SOAP::XML</tt> object.
|
153
|
-
def soap
|
154
|
-
@soap ||= XML.new(config)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Returns the <tt>Wasabi::Document</tt> object.
|
158
|
-
def wsdl
|
159
|
-
@wsdl ||= Wasabi::Document.new
|
160
|
-
end
|
161
|
-
|
162
|
-
# Returns the <tt>Akami::WSSE</tt> object.
|
163
|
-
def wsse
|
164
|
-
@wsse ||= Akami.wsse
|
165
|
-
end
|
166
|
-
|
167
|
-
private
|
168
|
-
|
169
|
-
def configure_dependencies
|
170
|
-
soap.endpoint = wsdl.endpoint
|
171
|
-
soap.element_form_default = wsdl.element_form_default
|
172
|
-
soap.wsse = wsse
|
173
|
-
|
174
|
-
soap.namespace = namespace
|
175
|
-
soap.namespace_identifier = namespace_identifier
|
176
|
-
|
177
|
-
add_wsdl_namespaces_to_soap
|
178
|
-
add_wsdl_types_to_soap
|
179
|
-
|
180
|
-
soap.input = [input_namespace_identifier, soap_input_tag.to_sym, attributes]
|
181
|
-
|
182
|
-
http.headers["SOAPAction"] = %{"#{soap_action}"}
|
183
|
-
end
|
184
|
-
|
185
|
-
def add_wsdl_namespaces_to_soap
|
186
|
-
wsdl.type_namespaces.each do |path, uri|
|
187
|
-
soap.use_namespace(path, uri)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def add_wsdl_types_to_soap
|
192
|
-
wsdl.type_definitions.each do |path, type|
|
193
|
-
soap.types[path] = type
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def assign_options(options)
|
198
|
-
options.each do |option, value|
|
199
|
-
send(:"#{option}=", value) if value
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
data/lib/savon/soap/response.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require "savon/soap/xml"
|
2
|
-
require "savon/soap/fault"
|
3
|
-
require "savon/soap/invalid_response_error"
|
4
|
-
require "savon/http/error"
|
5
|
-
|
6
|
-
module Savon
|
7
|
-
module SOAP
|
8
|
-
|
9
|
-
# = Savon::SOAP::Response
|
10
|
-
#
|
11
|
-
# Represents the SOAP response and contains the HTTP response.
|
12
|
-
class Response
|
13
|
-
|
14
|
-
# Expects an <tt>HTTPI::Response</tt> and handles errors.
|
15
|
-
def initialize(config, response)
|
16
|
-
self.config = config
|
17
|
-
self.http = response
|
18
|
-
raise_errors if config.raise_errors
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_accessor :http, :config
|
22
|
-
|
23
|
-
# Returns whether the request was successful.
|
24
|
-
def success?
|
25
|
-
!soap_fault? && !http_error?
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns whether there was a SOAP fault.
|
29
|
-
def soap_fault?
|
30
|
-
soap_fault.present?
|
31
|
-
end
|
32
|
-
|
33
|
-
# Returns the <tt>Savon::SOAP::Fault</tt>.
|
34
|
-
def soap_fault
|
35
|
-
@soap_fault ||= Fault.new http
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns whether there was an HTTP error.
|
39
|
-
def http_error?
|
40
|
-
http_error.present?
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns the <tt>Savon::HTTP::Error</tt>.
|
44
|
-
def http_error
|
45
|
-
@http_error ||= HTTP::Error.new http
|
46
|
-
end
|
47
|
-
|
48
|
-
# Shortcut accessor for the SOAP response body Hash.
|
49
|
-
def [](key)
|
50
|
-
body[key]
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns the SOAP response header as a Hash.
|
54
|
-
def header
|
55
|
-
if !hash.has_key? :envelope
|
56
|
-
raise Savon::SOAP::InvalidResponseError, "Unable to parse response body '#{to_xml}'"
|
57
|
-
end
|
58
|
-
hash[:envelope][:header]
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns the SOAP response body as a Hash.
|
62
|
-
def body
|
63
|
-
if !hash.has_key? :envelope
|
64
|
-
raise Savon::SOAP::InvalidResponseError, "Unable to parse response body '#{to_xml}'"
|
65
|
-
end
|
66
|
-
hash[:envelope][:body]
|
67
|
-
end
|
68
|
-
|
69
|
-
alias to_hash body
|
70
|
-
|
71
|
-
# Traverses the SOAP response body Hash for a given +path+ of Hash keys and returns
|
72
|
-
# the value as an Array. Defaults to return an empty Array in case the path does not
|
73
|
-
# exist or returns nil.
|
74
|
-
def to_array(*path)
|
75
|
-
result = path.inject body do |memo, key|
|
76
|
-
return [] unless memo[key]
|
77
|
-
memo[key]
|
78
|
-
end
|
79
|
-
|
80
|
-
result.kind_of?(Array) ? result.compact : [result].compact
|
81
|
-
end
|
82
|
-
|
83
|
-
# Returns the complete SOAP response XML without normalization.
|
84
|
-
def hash
|
85
|
-
@hash ||= Nori.parse(to_xml)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Returns the SOAP response XML.
|
89
|
-
def to_xml
|
90
|
-
http.body
|
91
|
-
end
|
92
|
-
|
93
|
-
# Returns a <tt>Nokogiri::XML::Document</tt> for the SOAP response XML.
|
94
|
-
def doc
|
95
|
-
@doc ||= Nokogiri::XML(to_xml)
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns an Array of <tt>Nokogiri::XML::Node</tt> objects retrieved with the given +path+.
|
99
|
-
# Automatically adds all of the document's namespaces unless a +namespaces+ hash is provided.
|
100
|
-
def xpath(path, namespaces = nil)
|
101
|
-
doc.xpath(path, namespaces || xml_namespaces)
|
102
|
-
end
|
103
|
-
|
104
|
-
private
|
105
|
-
|
106
|
-
def raise_errors
|
107
|
-
raise soap_fault if soap_fault?
|
108
|
-
raise http_error if http_error?
|
109
|
-
end
|
110
|
-
|
111
|
-
def xml_namespaces
|
112
|
-
@xml_namespaces ||= doc.collect_namespaces
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
data/lib/savon/soap/xml.rb
DELETED
@@ -1,257 +0,0 @@
|
|
1
|
-
require "builder"
|
2
|
-
require "gyoku"
|
3
|
-
require "rexml/document"
|
4
|
-
require "nori"
|
5
|
-
|
6
|
-
require "savon/soap"
|
7
|
-
|
8
|
-
Nori.configure do |config|
|
9
|
-
config.strip_namespaces = true
|
10
|
-
config.convert_tags_to { |tag| tag.snakecase.to_sym }
|
11
|
-
end
|
12
|
-
|
13
|
-
module Savon
|
14
|
-
module SOAP
|
15
|
-
|
16
|
-
# = Savon::SOAP::XML
|
17
|
-
#
|
18
|
-
# Represents the SOAP request XML. Contains various global and per request/instance settings
|
19
|
-
# like the SOAP version, header, body and namespaces.
|
20
|
-
class XML
|
21
|
-
|
22
|
-
# XML Schema Type namespaces.
|
23
|
-
SCHEMA_TYPES = {
|
24
|
-
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
|
25
|
-
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"
|
26
|
-
}
|
27
|
-
|
28
|
-
# Expects a +config+ object.
|
29
|
-
def initialize(config)
|
30
|
-
self.config = config
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_accessor :config
|
34
|
-
|
35
|
-
# Accessor for the SOAP +input+ tag.
|
36
|
-
attr_accessor :input
|
37
|
-
|
38
|
-
# Accessor for the SOAP +endpoint+.
|
39
|
-
attr_accessor :endpoint
|
40
|
-
|
41
|
-
# Sets the SOAP +version+.
|
42
|
-
def version=(version)
|
43
|
-
raise ArgumentError, "Invalid SOAP version: #{version}" unless SOAP::VERSIONS.include? version
|
44
|
-
@version = version
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns the SOAP +version+. Defaults to <tt>Savon.config.soap_version</tt>.
|
48
|
-
def version
|
49
|
-
@version ||= config.soap_version
|
50
|
-
end
|
51
|
-
|
52
|
-
# Sets the SOAP +header+ Hash.
|
53
|
-
attr_writer :header
|
54
|
-
|
55
|
-
# Returns the SOAP +header+. Defaults to an empty Hash.
|
56
|
-
def header
|
57
|
-
@header ||= config.soap_header.nil? ? {} : config.soap_header
|
58
|
-
end
|
59
|
-
|
60
|
-
# Sets the SOAP envelope namespace.
|
61
|
-
attr_writer :env_namespace
|
62
|
-
|
63
|
-
# Returns the SOAP envelope namespace. Uses the global namespace if set Defaults to :env.
|
64
|
-
def env_namespace
|
65
|
-
@env_namespace ||= config.env_namespace.nil? ? :env : config.env_namespace
|
66
|
-
end
|
67
|
-
|
68
|
-
# Sets the +namespaces+ Hash.
|
69
|
-
attr_writer :namespaces
|
70
|
-
|
71
|
-
# Returns the +namespaces+. Defaults to a Hash containing the SOAP envelope namespace.
|
72
|
-
def namespaces
|
73
|
-
@namespaces ||= begin
|
74
|
-
key = ["xmlns"]
|
75
|
-
key << env_namespace if env_namespace && env_namespace != ""
|
76
|
-
{ key.join(":") => SOAP::NAMESPACE[version] }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def namespace_by_uri(uri)
|
81
|
-
namespaces.each do |candidate_identifier, candidate_uri|
|
82
|
-
return candidate_identifier.gsub(/^xmlns:/, '') if candidate_uri == uri
|
83
|
-
end
|
84
|
-
nil
|
85
|
-
end
|
86
|
-
|
87
|
-
def used_namespaces
|
88
|
-
@used_namespaces ||= {}
|
89
|
-
end
|
90
|
-
|
91
|
-
def use_namespace(path, uri)
|
92
|
-
@internal_namespace_count ||= 0
|
93
|
-
|
94
|
-
unless identifier = namespace_by_uri(uri)
|
95
|
-
identifier = "ins#{@internal_namespace_count}"
|
96
|
-
namespaces["xmlns:#{identifier}"] = uri
|
97
|
-
@internal_namespace_count += 1
|
98
|
-
end
|
99
|
-
|
100
|
-
used_namespaces[path] = identifier
|
101
|
-
end
|
102
|
-
|
103
|
-
def types
|
104
|
-
@types ||= {}
|
105
|
-
end
|
106
|
-
|
107
|
-
# Sets the default namespace identifier.
|
108
|
-
attr_writer :namespace_identifier
|
109
|
-
|
110
|
-
# Returns the default namespace identifier.
|
111
|
-
def namespace_identifier
|
112
|
-
@namespace_identifier ||= :wsdl
|
113
|
-
end
|
114
|
-
|
115
|
-
# Accessor for whether all local elements should be namespaced.
|
116
|
-
attr_accessor :element_form_default
|
117
|
-
|
118
|
-
# Accessor for the default namespace URI.
|
119
|
-
attr_accessor :namespace
|
120
|
-
|
121
|
-
# Accessor for the <tt>Savon::WSSE</tt> object.
|
122
|
-
attr_accessor :wsse
|
123
|
-
|
124
|
-
def signature?
|
125
|
-
wsse.respond_to?(:signature?) && wsse.signature?
|
126
|
-
end
|
127
|
-
|
128
|
-
# Returns the SOAP request encoding. Defaults to "UTF-8".
|
129
|
-
def encoding
|
130
|
-
@encoding ||= "UTF-8"
|
131
|
-
end
|
132
|
-
|
133
|
-
# Sets the SOAP request encoding.
|
134
|
-
attr_writer :encoding
|
135
|
-
|
136
|
-
# Accepts a +block+ and yields a <tt>Builder::XmlMarkup</tt> object to let you create
|
137
|
-
# custom body XML.
|
138
|
-
def body
|
139
|
-
@body = yield builder(nil) if block_given?
|
140
|
-
@body
|
141
|
-
end
|
142
|
-
|
143
|
-
# Sets the SOAP +body+. Expected to be a Hash that can be translated to XML via `Gyoku.xml`
|
144
|
-
# or any other Object responding to to_s.
|
145
|
-
attr_writer :body
|
146
|
-
|
147
|
-
# Accepts a +block+ and yields a <tt>Builder::XmlMarkup</tt> object to let you create
|
148
|
-
# a completely custom XML.
|
149
|
-
def xml(directive_tag = :xml, attrs = {})
|
150
|
-
@xml = yield builder(directive_tag, attrs) if block_given?
|
151
|
-
end
|
152
|
-
|
153
|
-
# Accepts an XML String and lets you specify a completely custom request body.
|
154
|
-
attr_writer :xml
|
155
|
-
|
156
|
-
# Returns the XML for a SOAP request.
|
157
|
-
def to_xml(clear_cache = false)
|
158
|
-
if clear_cache
|
159
|
-
@xml = nil
|
160
|
-
@header_for_xml = nil
|
161
|
-
end
|
162
|
-
|
163
|
-
@xml ||= tag(builder, :Envelope, complete_namespaces) do |xml|
|
164
|
-
tag(xml, :Header) { xml << header_for_xml } unless header_for_xml.empty?
|
165
|
-
|
166
|
-
# TODO: Maybe there should be some sort of plugin architecture where
|
167
|
-
# classes like WSSE::Signature can hook into this process.
|
168
|
-
body_attributes = (signature? ? wsse.signature.body_attributes : {})
|
169
|
-
|
170
|
-
if input.nil?
|
171
|
-
tag(xml, :Body, body_attributes)
|
172
|
-
else
|
173
|
-
tag(xml, :Body, body_attributes) { xml.tag!(*add_namespace_to_input) { xml << body_to_xml } }
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
private
|
179
|
-
|
180
|
-
# Returns a new <tt>Builder::XmlMarkup</tt> object.
|
181
|
-
def builder(directive_tag = :xml, attrs = { :encoding => encoding })
|
182
|
-
builder = Builder::XmlMarkup.new
|
183
|
-
builder.instruct!(directive_tag, attrs) if directive_tag
|
184
|
-
builder
|
185
|
-
end
|
186
|
-
|
187
|
-
# Expects a builder +xml+ instance, a tag +name+ and accepts optional +namespaces+
|
188
|
-
# and a block to create an XML tag.
|
189
|
-
def tag(xml, name, namespaces = {}, &block)
|
190
|
-
if env_namespace && env_namespace != ""
|
191
|
-
xml.tag! env_namespace, name, namespaces, &block
|
192
|
-
else
|
193
|
-
xml.tag! name, namespaces, &block
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Returns the complete Hash of namespaces.
|
198
|
-
def complete_namespaces
|
199
|
-
defaults = SCHEMA_TYPES.dup
|
200
|
-
defaults["xmlns:#{namespace_identifier}"] = namespace if namespace
|
201
|
-
defaults.merge namespaces
|
202
|
-
end
|
203
|
-
|
204
|
-
# Returns the SOAP header as an XML String.
|
205
|
-
def header_for_xml
|
206
|
-
@header_for_xml ||= (Hash === header ? Gyoku.xml(header) : header) + wsse_header
|
207
|
-
end
|
208
|
-
|
209
|
-
# Returns the WSSE header or an empty String in case WSSE was not set.
|
210
|
-
def wsse_header
|
211
|
-
wsse.respond_to?(:to_xml) ? wsse.to_xml : ""
|
212
|
-
end
|
213
|
-
|
214
|
-
# Returns the SOAP body as an XML String.
|
215
|
-
def body_to_xml
|
216
|
-
return body.to_s unless body.kind_of? Hash
|
217
|
-
body_to_xml = element_form_default == :qualified ? add_namespaces_to_body(body) : body
|
218
|
-
Gyoku.xml body_to_xml, :element_form_default => element_form_default, :namespace => namespace_identifier
|
219
|
-
end
|
220
|
-
|
221
|
-
def add_namespaces_to_body(hash, path = [input[1].to_s])
|
222
|
-
return unless hash
|
223
|
-
return hash.map { |value| add_namespaces_to_body(value, path) } if hash.kind_of?(Array)
|
224
|
-
return hash.to_s unless hash.kind_of? Hash
|
225
|
-
|
226
|
-
hash.inject({}) do |newhash, (key, value)|
|
227
|
-
camelcased_key = Gyoku::XMLKey.create(key)
|
228
|
-
newpath = path + [camelcased_key]
|
229
|
-
|
230
|
-
if used_namespaces[newpath]
|
231
|
-
newhash.merge(
|
232
|
-
"#{used_namespaces[newpath]}:#{camelcased_key}" =>
|
233
|
-
add_namespaces_to_body(value, types[newpath] ? [types[newpath]] : newpath)
|
234
|
-
)
|
235
|
-
else
|
236
|
-
add_namespaces_to_values(value, path) if key == :order!
|
237
|
-
newhash.merge(key => value)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def add_namespace_to_input
|
243
|
-
return input.compact unless used_namespaces[[input[1].to_s]]
|
244
|
-
[used_namespaces[[input[1].to_s]], input[1], input[2]]
|
245
|
-
end
|
246
|
-
|
247
|
-
def add_namespaces_to_values(values, path)
|
248
|
-
values.collect! { |value|
|
249
|
-
camelcased_value = Gyoku::XMLKey.create(value)
|
250
|
-
namespace_path = path + [camelcased_value.to_s]
|
251
|
-
namespace = used_namespaces[namespace_path]
|
252
|
-
"#{namespace.blank? ? '' : namespace + ":"}#{camelcased_value}"
|
253
|
-
}
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|