wasabi-ng-1.6 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +90 -0
- data/Gemfile +6 -0
- data/LICENSE +20 -0
- data/README.md +60 -0
- data/Rakefile +7 -0
- data/lib/wasabi.rb +12 -0
- data/lib/wasabi/core_ext/string.rb +21 -0
- data/lib/wasabi/document.rb +166 -0
- data/lib/wasabi/parser.rb +304 -0
- data/lib/wasabi/resolver.rb +54 -0
- data/lib/wasabi/version.rb +5 -0
- data/spec/fixtures/authentication.wsdl +63 -0
- data/spec/fixtures/economic.wsdl +65660 -0
- data/spec/fixtures/encoded_endpoint.wsdl +52 -0
- data/spec/fixtures/geotrust.wsdl +156 -0
- data/spec/fixtures/import_port_types.wsdl +86 -0
- data/spec/fixtures/inherited.wsdl +46 -0
- data/spec/fixtures/juniper.wsdl +215 -0
- data/spec/fixtures/lower_camel.wsdl +52 -0
- data/spec/fixtures/multiple_namespaces.wsdl +61 -0
- data/spec/fixtures/multiple_types.wsdl +60 -0
- data/spec/fixtures/namespaced_actions.wsdl +307 -0
- data/spec/fixtures/no_message_parts.wsdl +59 -0
- data/spec/fixtures/no_namespace.wsdl +115 -0
- data/spec/fixtures/savon295.wsdl +52 -0
- data/spec/fixtures/soap12.wsdl +11 -0
- data/spec/fixtures/symbolic_endpoint.wsdl +190 -0
- data/spec/fixtures/two_bindings.wsdl +24 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/fixture.rb +40 -0
- data/spec/support/profiling.rb +18 -0
- data/spec/wasabi/core_ext/string_spec.rb +37 -0
- data/spec/wasabi/document/authentication_spec.rb +23 -0
- data/spec/wasabi/document/economic_spec.rb +13 -0
- data/spec/wasabi/document/encoded_endpoint_spec.rb +11 -0
- data/spec/wasabi/document/geotrust_spec.rb +24 -0
- data/spec/wasabi/document/inherited_spec.rb +38 -0
- data/spec/wasabi/document/multiple_namespaces_spec.rb +35 -0
- data/spec/wasabi/document/namespaced_actions_spec.rb +25 -0
- data/spec/wasabi/document/no_namespace_spec.rb +25 -0
- data/spec/wasabi/document/savon295_spec.rb +15 -0
- data/spec/wasabi/document/soap12_spec.rb +11 -0
- data/spec/wasabi/document/two_bindings_spec.rb +21 -0
- data/spec/wasabi/document_spec.rb +58 -0
- data/spec/wasabi/parser/get_servicename_spec.rb +19 -0
- data/spec/wasabi/parser/import_port_types_spec.rb +22 -0
- data/spec/wasabi/parser/juniper_spec.rb +23 -0
- data/spec/wasabi/parser/multiple_namespaces_spec.rb +40 -0
- data/spec/wasabi/parser/no_message_parts_spec.rb +26 -0
- data/spec/wasabi/parser/no_namespace_spec.rb +26 -0
- data/spec/wasabi/parser/no_target_namespace_spec.rb +36 -0
- data/spec/wasabi/parser/symbolic_endpoint_spec.rb +24 -0
- data/spec/wasabi/resolver_spec.rb +40 -0
- data/spec/wasabi/wasabi_spec.rb +12 -0
- data/wasabi.gemspec +27 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4f5657201ca8ca58c80f372f9d46f164dc548af6
|
4
|
+
data.tar.gz: 1b07dede1bee0dc7ece80c96160becabb7dfcd81
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bcd9c7b4e64663c9f01731eb21339111480865422e1b2df97811fd97a69b53fe0a4c77758c80eb60f2d994a973ebe37cd901d0318e7dfb1cbcf9e4b372db00ca
|
7
|
+
data.tar.gz: 5fa9f8b47ffcac82f092c81afce91c18c1d258c2b504443075c3230ac51809b2a3337768915acc1562f1bc364e797d67adc242f4b447399ce84830f9deae9a97
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
## 3.2.0 (2013-07-26)
|
2
|
+
|
3
|
+
* Feature: [#20](https://github.com/savonrb/wasabi/issues/20) Limited support for listing an
|
4
|
+
operation's parameters. Please note that if your WSDL defines imports, this method might
|
5
|
+
not return all types.
|
6
|
+
|
7
|
+
* Improvement: [#7](https://github.com/savonrb/wasabi/issues/7) Major speed improvements.
|
8
|
+
|
9
|
+
* Improvement: [#16](https://github.com/savonrb/wasabi/issues/16) Various improvements regarding
|
10
|
+
element order and type information.
|
11
|
+
|
12
|
+
* Fix: [#25](https://github.com/savonrb/wasabi/issues/25) Fixes a problem where Wasabi escaped
|
13
|
+
an already escaped endpoint URL.
|
14
|
+
|
15
|
+
* Fix: [#15](https://github.com/savonrb/wasabi/issues/15) Fixes a bug where the operation tag
|
16
|
+
name was not correctly extracted from the WSDL document.
|
17
|
+
|
18
|
+
## 3.1.0 (2013-04-21)
|
19
|
+
|
20
|
+
* Feature: [#22](https://github.com/savonrb/wasabi/issues/22) added `Wasabi::Document#service_name`
|
21
|
+
to return the name of the SOAP service. Original issue: [savonrb/savon#408](https://github.com/savonrb/savon/pull/408).
|
22
|
+
|
23
|
+
* Fix: [#21](https://github.com/savonrb/wasabi/issues/21) when the Resolver gets an
|
24
|
+
erroneous response (such as a 404), we now raise a more useful HTTPError.
|
25
|
+
|
26
|
+
* Fix: [#23](https://github.com/savonrb/wasabi/issues/23) ignore extension base elements
|
27
|
+
defined in imports.
|
28
|
+
|
29
|
+
## 3.0.0 (2012-12-17)
|
30
|
+
|
31
|
+
* Updated to HTTPI 2.0 to play nicely with Savon 2.0.
|
32
|
+
|
33
|
+
## 2.5.1 (2012-08-22)
|
34
|
+
|
35
|
+
* Fix: [#14](https://github.com/savonrb/wasabi/issues/14) fixes an issue where
|
36
|
+
finding the correct SOAP input tag and namespace identifier fails when portTypes
|
37
|
+
are imported, since imports are currently not supported.
|
38
|
+
|
39
|
+
The bug was introduced in v2.2.0 by [583cf6](https://github.com/savonrb/wasabi/commit/583cf658f1953411a7a7a4c22923fa0a046c8d6d)
|
40
|
+
|
41
|
+
* Refactoring: Removed `Object#blank?` core extension.
|
42
|
+
|
43
|
+
## 2.5.0 (2012-06-28)
|
44
|
+
|
45
|
+
* Fix: [#10](https://github.com/savonrb/wasabi/issues/10) fixes an issue where
|
46
|
+
Wasabi used the wrong operation name.
|
47
|
+
|
48
|
+
## 2.4.1 (2012-06-18)
|
49
|
+
|
50
|
+
* Fix: [savonrb/savon#296](https://github.com/savonrb/savon/issues/296) fixes an issue where
|
51
|
+
the WSDL message element doesn't have part element.
|
52
|
+
|
53
|
+
## 2.4.0 (2012-06-08)
|
54
|
+
|
55
|
+
* Feature: `Wasabi::Document` now accepts either a URL of a remote document,
|
56
|
+
a path to a local file or raw XML. The code for this was moved from Savon over
|
57
|
+
here as a first step towards supporting WSDL imports.
|
58
|
+
|
59
|
+
## 2.3.0 (2012-06-07)
|
60
|
+
|
61
|
+
* Improvement: [#3](https://github.com/savonrb/wasabi/pull/3) adds object inheritance.
|
62
|
+
|
63
|
+
## 2.2.0 (2012-06-06)
|
64
|
+
|
65
|
+
* Improvement: [#5](https://github.com/savonrb/wasabi/pull/5) - Get input from message
|
66
|
+
element or portType input. See [savonrb/savon#277](https://github.com/savonrb/savon/pull/277)
|
67
|
+
to get the full picture on how this all works together, and enables you to pass a single
|
68
|
+
symbol into the `Savon::Client#request` method and get automatic namespace mapping, as well
|
69
|
+
as the proper operation name -> input message mapping.
|
70
|
+
|
71
|
+
## 2.1.1 (2012-05-18)
|
72
|
+
|
73
|
+
* Fix: [issue 7](https://github.com/savonrb/wasabi/issues/7) - Performance regression.
|
74
|
+
|
75
|
+
## 2.1.0 (2012-02-17)
|
76
|
+
|
77
|
+
* Improvement: The value of elementFormDefault can now be manually specified/overwritten.
|
78
|
+
|
79
|
+
* Improvement: [issue 2](https://github.com/savonrb/wasabi/issues/2) - Allow symbolic endpoints
|
80
|
+
like "http://server:port".
|
81
|
+
|
82
|
+
## 2.0.0 (2011-07-07)
|
83
|
+
|
84
|
+
* Feature: Wasabi can now parse type definitions and namespaces.
|
85
|
+
Thanks to [jkingdon](https://github.com/jkingdon) for implementing this.
|
86
|
+
|
87
|
+
## 1.0.0 (2011-07-03)
|
88
|
+
|
89
|
+
* Initial version extracted from the [Savon](http://rubygems.org/gems/savon) library.
|
90
|
+
Use it to build your own SOAP client and help to improve it!
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Daniel Harrington
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Wasabi
|
2
|
+
|
3
|
+
A simple WSDL parser.
|
4
|
+
|
5
|
+
[](http://travis-ci.org/savonrb/wasabi)
|
6
|
+
[](http://badge.fury.io/rb/wasabi)
|
7
|
+
[](https://codeclimate.com/github/savonrb/wasabi)
|
8
|
+
[](https://coveralls.io/r/savonrb/wasabi)
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Wasabi is available through [Rubygems](http://rubygems.org/gems/wasabi) and can be installed via:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ gem install wasabi
|
17
|
+
```
|
18
|
+
|
19
|
+
|
20
|
+
## Getting started
|
21
|
+
|
22
|
+
``` ruby
|
23
|
+
document = Wasabi.document File.read("some.wsdl")
|
24
|
+
```
|
25
|
+
|
26
|
+
Get the SOAP endpoint:
|
27
|
+
|
28
|
+
``` ruby
|
29
|
+
document.endpoint
|
30
|
+
# => "http://soap.example.com"
|
31
|
+
```
|
32
|
+
|
33
|
+
Get the target namespace:
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
document.namespace
|
37
|
+
# => "http://v1.example.com"
|
38
|
+
```
|
39
|
+
|
40
|
+
Check whether elementFormDefault is set to `:qualified` or `:unqualified`:
|
41
|
+
|
42
|
+
``` ruby
|
43
|
+
document.element_form_default
|
44
|
+
# => :qualified
|
45
|
+
```
|
46
|
+
|
47
|
+
Get a list of available SOAP actions (snakecase for convenience):
|
48
|
+
|
49
|
+
``` ruby
|
50
|
+
document.soap_actions
|
51
|
+
# => [:create_user, :find_user]
|
52
|
+
```
|
53
|
+
|
54
|
+
Get a map of SOAP action Symbols, their input tag and original SOAP action name:
|
55
|
+
|
56
|
+
``` ruby
|
57
|
+
document.operations
|
58
|
+
# => { :create_user => { :input => "createUser", :action => "createUser" },
|
59
|
+
# => :find_user => { :input => "findUser", :action => "findUser" } }
|
60
|
+
```
|
data/Rakefile
ADDED
data/lib/wasabi.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Wasabi
|
2
|
+
module CoreExt
|
3
|
+
module String
|
4
|
+
|
5
|
+
# Returns the String in snakecase.
|
6
|
+
def snakecase
|
7
|
+
str = dup
|
8
|
+
str.gsub! /::/, '/'
|
9
|
+
str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
|
10
|
+
str.gsub! /([a-z\d])([A-Z])/, '\1_\2'
|
11
|
+
str.tr! ".", "_"
|
12
|
+
str.tr! "-", "_"
|
13
|
+
str.downcase!
|
14
|
+
str
|
15
|
+
end unless method_defined?(:snakecase)
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
String.send :include, Wasabi::CoreExt::String
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "wasabi/resolver"
|
3
|
+
require "wasabi/parser"
|
4
|
+
|
5
|
+
module Wasabi
|
6
|
+
|
7
|
+
# = Wasabi::Document
|
8
|
+
#
|
9
|
+
# Represents a WSDL document.
|
10
|
+
class Document
|
11
|
+
|
12
|
+
ELEMENT_FORM_DEFAULTS = [:unqualified, :qualified]
|
13
|
+
|
14
|
+
# Validates if a given +value+ is a valid elementFormDefault value.
|
15
|
+
# Raises an +ArgumentError+ if the value is not valid.
|
16
|
+
def self.validate_element_form_default!(value)
|
17
|
+
return if ELEMENT_FORM_DEFAULTS.include?(value)
|
18
|
+
|
19
|
+
raise ArgumentError, "Invalid value for elementFormDefault: #{value}\n" +
|
20
|
+
"Must be one of: #{ELEMENT_FORM_DEFAULTS.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Accepts a WSDL +document+ to parse.
|
24
|
+
def initialize(document = nil)
|
25
|
+
self.document = document
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :document, :request, :xml
|
29
|
+
|
30
|
+
alias_method :document?, :document
|
31
|
+
|
32
|
+
# Returns the SOAP endpoint.
|
33
|
+
def endpoint
|
34
|
+
@endpoint ||= parser.endpoint
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets the SOAP endpoint.
|
38
|
+
attr_writer :endpoint
|
39
|
+
|
40
|
+
# Returns the target namespace.
|
41
|
+
def namespace
|
42
|
+
@namespace ||= parser.namespace
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the target namespace.
|
46
|
+
attr_writer :namespace
|
47
|
+
|
48
|
+
# Returns the value of elementFormDefault.
|
49
|
+
def element_form_default
|
50
|
+
@element_form_default ||= document ? parser.element_form_default : :unqualified
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the elementFormDefault value.
|
54
|
+
def element_form_default=(value)
|
55
|
+
self.class.validate_element_form_default!(value)
|
56
|
+
@element_form_default = value
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns a list of available SOAP actions.
|
60
|
+
def soap_actions
|
61
|
+
@soap_actions ||= parser.operations.keys
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the SOAP action for a given +key+.
|
65
|
+
def soap_action(key)
|
66
|
+
operations[key][:action] if operations[key]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the SOAP input for a given +key+.
|
70
|
+
def soap_input(key)
|
71
|
+
operations[key][:input] if operations[key]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns a map of SOAP operations.
|
75
|
+
def operations
|
76
|
+
@operations ||= parser.operations
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the service name.
|
80
|
+
def service_name
|
81
|
+
@service_name ||= parser.service_name
|
82
|
+
end
|
83
|
+
|
84
|
+
attr_writer :service_name
|
85
|
+
|
86
|
+
# Returns a list of parameter names for a given +key+
|
87
|
+
def soap_action_parameters(key)
|
88
|
+
params = operation_input_parameters(key)
|
89
|
+
params.keys if params
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns a list of input parameters for a given +key+.
|
93
|
+
def operation_input_parameters(key)
|
94
|
+
parser.operations[key][:parameters] if operations[key]
|
95
|
+
end
|
96
|
+
|
97
|
+
def type_namespaces
|
98
|
+
@type_namespaces ||= begin
|
99
|
+
namespaces = []
|
100
|
+
|
101
|
+
parser.types.each do |type, info|
|
102
|
+
namespaces << [[type], info[:namespace]]
|
103
|
+
|
104
|
+
element_keys(info).each do |field|
|
105
|
+
namespaces << [[type, field], info[:namespace]]
|
106
|
+
end
|
107
|
+
end if document
|
108
|
+
|
109
|
+
namespaces
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def type_definitions
|
114
|
+
@type_definitions ||= begin
|
115
|
+
result = []
|
116
|
+
|
117
|
+
parser.types.each do |type, info|
|
118
|
+
element_keys(info).each do |field|
|
119
|
+
field_type = info[field][:type]
|
120
|
+
tag, namespace = field_type.split(":").reverse
|
121
|
+
|
122
|
+
result << [[type, field], tag] if user_defined(namespace)
|
123
|
+
end
|
124
|
+
end if document
|
125
|
+
|
126
|
+
result
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns whether the given +namespace+ was defined manually.
|
131
|
+
def user_defined(namespace)
|
132
|
+
uri = parser.namespaces[namespace]
|
133
|
+
!(uri =~ %r{^http://schemas.xmlsoap.org} || uri =~ %r{^http://www.w3.org})
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the raw WSDL document.
|
137
|
+
# Can be used as a hook to extend the library.
|
138
|
+
def xml
|
139
|
+
@xml ||= Resolver.new(document, request).resolve
|
140
|
+
end
|
141
|
+
|
142
|
+
# Parses the WSDL document and returns the <tt>Wasabi::Parser</tt>.
|
143
|
+
def parser
|
144
|
+
@parser ||= guard_parse && parse
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
# Raises an error if the WSDL document is missing.
|
150
|
+
def guard_parse
|
151
|
+
return true if document
|
152
|
+
raise ArgumentError, "Wasabi needs a WSDL document"
|
153
|
+
end
|
154
|
+
|
155
|
+
# Parses the WSDL document and returns <tt>Wasabi::Parser</tt>.
|
156
|
+
def parse
|
157
|
+
parser = Parser.new Nokogiri::XML(xml)
|
158
|
+
parser.parse
|
159
|
+
parser
|
160
|
+
end
|
161
|
+
|
162
|
+
def element_keys(info)
|
163
|
+
info.keys - [:namespace, :order!, :base_type]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "wasabi/core_ext/string"
|
3
|
+
|
4
|
+
module Wasabi
|
5
|
+
|
6
|
+
# = Wasabi::Parser
|
7
|
+
#
|
8
|
+
# Parses WSDL documents and remembers their important parts.
|
9
|
+
class Parser
|
10
|
+
|
11
|
+
XSD = "http://www.w3.org/2001/XMLSchema"
|
12
|
+
WSDL = "http://schemas.xmlsoap.org/wsdl/"
|
13
|
+
SOAP_1_1 = "http://schemas.xmlsoap.org/wsdl/soap/"
|
14
|
+
SOAP_1_2 = "http://schemas.xmlsoap.org/wsdl/soap12/"
|
15
|
+
|
16
|
+
def initialize(document)
|
17
|
+
self.document = document
|
18
|
+
self.operations = {}
|
19
|
+
self.namespaces = {}
|
20
|
+
self.service_name = ''
|
21
|
+
self.types = {}
|
22
|
+
self.deferred_types = []
|
23
|
+
self.element_form_default = :unqualified
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the Nokogiri document.
|
27
|
+
attr_accessor :document
|
28
|
+
|
29
|
+
# Returns the target namespace.
|
30
|
+
attr_accessor :namespace
|
31
|
+
|
32
|
+
# Returns a map from namespace identifier to namespace URI.
|
33
|
+
attr_accessor :namespaces
|
34
|
+
|
35
|
+
# Returns the SOAP operations.
|
36
|
+
attr_accessor :operations
|
37
|
+
|
38
|
+
# Returns a map from a type name to a Hash with type information.
|
39
|
+
attr_accessor :types
|
40
|
+
|
41
|
+
# Returns a map of deferred type Proc objects.
|
42
|
+
attr_accessor :deferred_types
|
43
|
+
|
44
|
+
# Returns the SOAP endpoint.
|
45
|
+
attr_accessor :endpoint
|
46
|
+
|
47
|
+
# Returns the SOAP Service Name
|
48
|
+
attr_accessor :service_name
|
49
|
+
|
50
|
+
# Returns the elementFormDefault value.
|
51
|
+
attr_accessor :element_form_default
|
52
|
+
|
53
|
+
def parse
|
54
|
+
parse_namespaces
|
55
|
+
parse_endpoint
|
56
|
+
parse_service_name
|
57
|
+
parse_messages
|
58
|
+
parse_port_types
|
59
|
+
parse_port_type_operations
|
60
|
+
parse_operations
|
61
|
+
parse_operations_parameters
|
62
|
+
parse_types
|
63
|
+
parse_deferred_types
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_namespaces
|
67
|
+
element_form_default = schemas.first && schemas.first['elementFormDefault']
|
68
|
+
@element_form_default = element_form_default.to_s.to_sym if element_form_default
|
69
|
+
|
70
|
+
namespace = document.root['targetNamespace']
|
71
|
+
@namespace = namespace.to_s if namespace
|
72
|
+
|
73
|
+
@namespaces = @document.namespaces.inject({}) do |memo, (key, value)|
|
74
|
+
memo[key.sub("xmlns:", "")] = value
|
75
|
+
memo
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_endpoint
|
80
|
+
if service_node = service
|
81
|
+
endpoint = service_node.at_xpath(".//soap11:address/@location", 'soap11' => SOAP_1_1)
|
82
|
+
endpoint ||= service_node.at_xpath(service_node, ".//soap12:address/@location", 'soap12' => SOAP_1_2)
|
83
|
+
end
|
84
|
+
|
85
|
+
@endpoint = parse_url(endpoint) if endpoint
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_url(url)
|
89
|
+
unescaped_url = URI.unescape(url.to_s)
|
90
|
+
escaped_url = URI.escape(unescaped_url)
|
91
|
+
URI.parse(escaped_url)
|
92
|
+
rescue URI::InvalidURIError
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_service_name
|
96
|
+
service_name = document.root['name']
|
97
|
+
@service_name = service_name.to_s if service_name
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_messages
|
101
|
+
messages = document.root.element_children.select { |node| node.name == 'message' }
|
102
|
+
@messages = Hash[messages.map { |node| [node['name'], node] }]
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_port_types
|
106
|
+
port_types = document.root.element_children.select { |node| node.name == 'portType' }
|
107
|
+
@port_types = Hash[port_types.map { |node| [node['name'], node] }]
|
108
|
+
end
|
109
|
+
|
110
|
+
def parse_port_type_operations
|
111
|
+
@port_type_operations = {}
|
112
|
+
|
113
|
+
@port_types.each do |port_type_name, port_type|
|
114
|
+
operations = port_type.element_children.select { |node| node.name == 'operation' }
|
115
|
+
@port_type_operations[port_type_name] = Hash[operations.map { |node| [node['name'], node] }]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_operations_parameters
|
120
|
+
root_elements = document.xpath("wsdl:definitions/wsdl:types/*[local-name()='schema']/*[local-name()='element']", 'wsdl' => WSDL).each do |element|
|
121
|
+
name = element.attribute("name").to_s.snakecase.to_sym
|
122
|
+
|
123
|
+
if operation = @operations[name]
|
124
|
+
element.xpath("*[local-name() ='complexType']/*[local-name() ='sequence']/*[local-name() ='element']").each do |child_element|
|
125
|
+
attr_name = child_element.attribute("name").to_s
|
126
|
+
attr_type = (attr_type = child_element.attribute("type").to_s.split(":")).size > 1 ? attr_type[1] : attr_type[0]
|
127
|
+
|
128
|
+
operation[:parameters] ||= {}
|
129
|
+
operation[:parameters][attr_name.to_sym] = { :name => attr_name, :type => attr_type }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_operations
|
136
|
+
operations = document.xpath("wsdl:definitions/wsdl:binding/wsdl:operation", 'wsdl' => WSDL)
|
137
|
+
operations.each do |operation|
|
138
|
+
name = operation.attribute("name").to_s
|
139
|
+
|
140
|
+
# TODO: check for soap namespace?
|
141
|
+
soap_operation = operation.element_children.find { |node| node.name == 'operation' }
|
142
|
+
soap_action = soap_operation['soapAction'] if soap_operation
|
143
|
+
|
144
|
+
if soap_action
|
145
|
+
soap_action = soap_action.to_s
|
146
|
+
action = soap_action && !soap_action.empty? ? soap_action : name
|
147
|
+
|
148
|
+
# There should be a matching portType for each binding, so we will lookup the input from there.
|
149
|
+
namespace_id, output = output_for(operation)
|
150
|
+
namespace_id, input = input_for(operation)
|
151
|
+
|
152
|
+
# Store namespace identifier so this operation can be mapped to the proper namespace.
|
153
|
+
@operations[name.snakecase.to_sym] = { :action => action, :input => input, :output => output, :namespace_identifier => namespace_id}
|
154
|
+
elsif !@operations[name.snakecase.to_sym]
|
155
|
+
@operations[name.snakecase.to_sym] = { :action => name, :input => name }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def parse_types
|
161
|
+
schemas.each do |schema|
|
162
|
+
schema_namespace = schema['targetNamespace']
|
163
|
+
|
164
|
+
schema.element_children.each do |node|
|
165
|
+
namespace = schema_namespace || @namespace
|
166
|
+
|
167
|
+
case node.name
|
168
|
+
when 'element'
|
169
|
+
complex_type = node.at_xpath('./xs:complexType', 'xs' => XSD)
|
170
|
+
process_type namespace, complex_type, node['name'].to_s if complex_type
|
171
|
+
when 'complexType'
|
172
|
+
process_type namespace, node, node['name'].to_s
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def process_type(namespace, type, name)
|
179
|
+
@types[name] ||= { :namespace => namespace }
|
180
|
+
@types[name][:order!] = []
|
181
|
+
|
182
|
+
type.xpath("./xs:sequence/xs:element", 'xs' => XSD).each do |inner|
|
183
|
+
element_name = inner.attribute("name").to_s
|
184
|
+
@types[name][element_name] = { :type => inner.attribute("type").to_s }
|
185
|
+
|
186
|
+
[ :nillable, :minOccurs, :maxOccurs ].each do |attr|
|
187
|
+
if v = inner.attribute(attr.to_s)
|
188
|
+
@types[name][element_name][attr] = v.to_s
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
@types[name][:order!] << element_name
|
193
|
+
end
|
194
|
+
|
195
|
+
type.xpath("./xs:complexContent/xs:extension/xs:sequence/xs:element", 'xs' => XSD).each do |inner_element|
|
196
|
+
element_name = inner_element.attribute('name').to_s
|
197
|
+
@types[name][element_name] = { :type => inner_element.attribute('type').to_s }
|
198
|
+
|
199
|
+
@types[name][:order!] << element_name
|
200
|
+
end
|
201
|
+
|
202
|
+
type.xpath('./xs:complexContent/xs:extension[@base]', 'xs' => XSD).each do |inherits|
|
203
|
+
base = inherits.attribute('base').value.match(/\w+$/).to_s
|
204
|
+
|
205
|
+
if @types[base]
|
206
|
+
# Reverse merge because we don't want subclass attributes to be overriden by base class
|
207
|
+
@types[name] = types[base].merge(types[name])
|
208
|
+
@types[name][:order!] = @types[base][:order!] | @types[name][:order!]
|
209
|
+
@types[name][:base_type] = base
|
210
|
+
else
|
211
|
+
p = Proc.new do
|
212
|
+
if @types[base]
|
213
|
+
# Reverse merge because we don't want subclass attributes to be overriden by base class
|
214
|
+
@types[name] = @types[base].merge(@types[name])
|
215
|
+
@types[name][:order!] = @types[base][:order!] | @types[name][:order!]
|
216
|
+
@types[name][:base_type] = base
|
217
|
+
end
|
218
|
+
end
|
219
|
+
deferred_types << p
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def parse_deferred_types
|
225
|
+
deferred_types.each(&:call)
|
226
|
+
end
|
227
|
+
|
228
|
+
def input_for(operation)
|
229
|
+
input_output_for(operation, "input")
|
230
|
+
end
|
231
|
+
|
232
|
+
def output_for(operation)
|
233
|
+
input_output_for(operation, "output")
|
234
|
+
end
|
235
|
+
|
236
|
+
def input_output_for(operation, input_output)
|
237
|
+
operation_name = operation["name"]
|
238
|
+
|
239
|
+
# Look up the input by walking up to portType, then up to the message.
|
240
|
+
|
241
|
+
binding_type = operation.parent['type'].to_s.split(':').last
|
242
|
+
if @port_type_operations[binding_type]
|
243
|
+
port_type_operation = @port_type_operations[binding_type][operation_name]
|
244
|
+
end
|
245
|
+
|
246
|
+
port_type_input_output = port_type_operation &&
|
247
|
+
port_type_operation.element_children.find { |node| node.name == input_output }
|
248
|
+
|
249
|
+
# TODO: Stupid fix for missing support for imports.
|
250
|
+
# Sometimes portTypes are actually included in a separate WSDL.
|
251
|
+
if port_type_input_output
|
252
|
+
port_message_ns_id, port_message_type = port_type_input_output.attribute("message").to_s.split(':')
|
253
|
+
|
254
|
+
message_ns_id, message_type = nil
|
255
|
+
|
256
|
+
# TODO: Support multiple 'part' elements in the message.
|
257
|
+
message = @messages[port_message_type]
|
258
|
+
port_message_part = message.element_children.find { |node| node.name == 'part' }
|
259
|
+
|
260
|
+
if port_message_part
|
261
|
+
if (port_message_part_element = port_message_part.attribute("element"))
|
262
|
+
message_ns_id, message_type = port_message_part_element.to_s.split(':')
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Fall back to the name of the binding operation
|
267
|
+
if message_type
|
268
|
+
[message_ns_id, message_type]
|
269
|
+
else
|
270
|
+
[port_message_ns_id, port_message_type]
|
271
|
+
end
|
272
|
+
else
|
273
|
+
[nil, operation_name]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def schemas
|
278
|
+
types = section('types').first
|
279
|
+
types ? types.element_children : []
|
280
|
+
end
|
281
|
+
|
282
|
+
def service
|
283
|
+
services = section('service')
|
284
|
+
services.first if services # service nodes could be imported?
|
285
|
+
end
|
286
|
+
|
287
|
+
def section(section_name)
|
288
|
+
sections[section_name] || []
|
289
|
+
end
|
290
|
+
|
291
|
+
def sections
|
292
|
+
return @sections if @sections
|
293
|
+
|
294
|
+
sections = {}
|
295
|
+
document.root.element_children.each do |node|
|
296
|
+
(sections[node.name] ||= []) << node
|
297
|
+
end
|
298
|
+
|
299
|
+
@sections = sections
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|