wasabi 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +26 -9
- data/Gemfile +5 -1
- data/README.md +8 -6
- data/Rakefile +0 -2
- data/lib/wasabi/document.rb +24 -2
- data/lib/wasabi/parser.rb +162 -49
- data/lib/wasabi/version.rb +1 -1
- data/spec/fixtures/economic.wsdl +65660 -0
- data/spec/fixtures/encoded_endpoint.wsdl +52 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/fixture.rb +2 -4
- data/spec/support/profiling.rb +18 -0
- data/spec/wasabi/document/authentication_spec.rb +1 -1
- 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 +2 -2
- data/spec/wasabi/document/inherited_spec.rb +20 -0
- data/spec/wasabi/document/multiple_namespaces_spec.rb +1 -1
- data/spec/wasabi/document/namespaced_actions_spec.rb +3 -3
- data/spec/wasabi/document/no_namespace_spec.rb +3 -3
- data/spec/wasabi/document/savon295_spec.rb +1 -1
- data/spec/wasabi/parser/multiple_namespaces_spec.rb +6 -2
- data/spec/wasabi/parser/no_message_parts_spec.rb +5 -1
- data/spec/wasabi/parser/no_namespace_spec.rb +5 -2
- data/spec/wasabi/parser/symbolic_endpoint_spec.rb +5 -0
- data/wasabi.gemspec +3 -2
- metadata +28 -28
- data/lib/wasabi/xpath_helper.rb +0 -30
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ad4024db6f2cc825dec1eb8223812bd8da45c884
|
4
|
+
data.tar.gz: af57d52095cb5daf9b530f9974b65b9d747cda11
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b61533673c5f483625c6bd884236c7592a03cfa0c6c8f5a47b18600cbc2e903ff5f83864fd85d53a42c3430de7f5a53907222c2bf0b19fc53338eb47fe625be6
|
7
|
+
data.tar.gz: 59212805b9b770b20a37e175e950f9df1a4ff973ce52d0ca4b8b88f41b94678025684591480251900a930d4236ade904120a4eb14cbf5965e1d1cd9376f1db16
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
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
|
+
|
1
18
|
## 3.1.0 (2013-04-21)
|
2
19
|
|
3
20
|
* Feature: [#22](https://github.com/savonrb/wasabi/issues/22) added `Wasabi::Document#service_name`
|
@@ -15,22 +32,22 @@
|
|
15
32
|
|
16
33
|
## 2.5.1 (2012-08-22)
|
17
34
|
|
18
|
-
* Fix: [#14](https://github.com/
|
35
|
+
* Fix: [#14](https://github.com/savonrb/wasabi/issues/14) fixes an issue where
|
19
36
|
finding the correct SOAP input tag and namespace identifier fails when portTypes
|
20
37
|
are imported, since imports are currently not supported.
|
21
38
|
|
22
|
-
The bug was introduced in v2.2.0 by [583cf6](https://github.com/
|
39
|
+
The bug was introduced in v2.2.0 by [583cf6](https://github.com/savonrb/wasabi/commit/583cf658f1953411a7a7a4c22923fa0a046c8d6d)
|
23
40
|
|
24
41
|
* Refactoring: Removed `Object#blank?` core extension.
|
25
42
|
|
26
43
|
## 2.5.0 (2012-06-28)
|
27
44
|
|
28
|
-
* Fix: [#10](https://github.com/
|
45
|
+
* Fix: [#10](https://github.com/savonrb/wasabi/issues/10) fixes an issue where
|
29
46
|
Wasabi used the wrong operation name.
|
30
47
|
|
31
48
|
## 2.4.1 (2012-06-18)
|
32
49
|
|
33
|
-
* Fix: [
|
50
|
+
* Fix: [savonrb/savon#296](https://github.com/savonrb/savon/issues/296) fixes an issue where
|
34
51
|
the WSDL message element doesn't have part element.
|
35
52
|
|
36
53
|
## 2.4.0 (2012-06-08)
|
@@ -41,25 +58,25 @@
|
|
41
58
|
|
42
59
|
## 2.3.0 (2012-06-07)
|
43
60
|
|
44
|
-
* Improvement: [#3](https://github.com/
|
61
|
+
* Improvement: [#3](https://github.com/savonrb/wasabi/pull/3) adds object inheritance.
|
45
62
|
|
46
63
|
## 2.2.0 (2012-06-06)
|
47
64
|
|
48
|
-
* Improvement: [#5](https://github.com/
|
49
|
-
element or portType input. See [
|
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)
|
50
67
|
to get the full picture on how this all works together, and enables you to pass a single
|
51
68
|
symbol into the `Savon::Client#request` method and get automatic namespace mapping, as well
|
52
69
|
as the proper operation name -> input message mapping.
|
53
70
|
|
54
71
|
## 2.1.1 (2012-05-18)
|
55
72
|
|
56
|
-
* Fix: [issue 7](https://github.com/
|
73
|
+
* Fix: [issue 7](https://github.com/savonrb/wasabi/issues/7) - Performance regression.
|
57
74
|
|
58
75
|
## 2.1.0 (2012-02-17)
|
59
76
|
|
60
77
|
* Improvement: The value of elementFormDefault can now be manually specified/overwritten.
|
61
78
|
|
62
|
-
* Improvement: [issue 2](https://github.com/
|
79
|
+
* Improvement: [issue 2](https://github.com/savonrb/wasabi/issues/2) - Allow symbolic endpoints
|
63
80
|
like "http://server:port".
|
64
81
|
|
65
82
|
## 2.0.0 (2011-07-07)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
Wasabi
|
2
|
-
=====
|
1
|
+
# Wasabi
|
3
2
|
|
4
3
|
A simple WSDL parser.
|
5
4
|
|
5
|
+
[![Build Status](https://secure.travis-ci.org/savonrb/wasabi.png)](http://travis-ci.org/savonrb/wasabi)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/wasabi.png)](http://badge.fury.io/rb/wasabi)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/savonrb/wasabi.png)](https://codeclimate.com/github/savonrb/wasabi)
|
8
|
+
[![Coverage Status](https://coveralls.io/repos/savonrb/wasabi/badge.png?branch=master)](https://coveralls.io/r/savonrb/wasabi)
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
|
11
|
+
## Installation
|
9
12
|
|
10
13
|
Wasabi is available through [Rubygems](http://rubygems.org/gems/wasabi) and can be installed via:
|
11
14
|
|
@@ -14,8 +17,7 @@ $ gem install wasabi
|
|
14
17
|
```
|
15
18
|
|
16
19
|
|
17
|
-
Getting started
|
18
|
-
---------------
|
20
|
+
## Getting started
|
19
21
|
|
20
22
|
``` ruby
|
21
23
|
document = Wasabi.document File.read("some.wsdl")
|
data/Rakefile
CHANGED
data/lib/wasabi/document.rb
CHANGED
@@ -83,13 +83,29 @@ module Wasabi
|
|
83
83
|
|
84
84
|
attr_writer :service_name
|
85
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
|
+
|
86
97
|
def type_namespaces
|
87
98
|
@type_namespaces ||= begin
|
88
99
|
namespaces = []
|
100
|
+
|
89
101
|
parser.types.each do |type, info|
|
90
102
|
namespaces << [[type], info[:namespace]]
|
91
|
-
|
103
|
+
|
104
|
+
element_keys(info).each do |field|
|
105
|
+
namespaces << [[type, field], info[:namespace]]
|
106
|
+
end
|
92
107
|
end if document
|
108
|
+
|
93
109
|
namespaces
|
94
110
|
end
|
95
111
|
end
|
@@ -97,13 +113,16 @@ module Wasabi
|
|
97
113
|
def type_definitions
|
98
114
|
@type_definitions ||= begin
|
99
115
|
result = []
|
116
|
+
|
100
117
|
parser.types.each do |type, info|
|
101
|
-
(info
|
118
|
+
element_keys(info).each do |field|
|
102
119
|
field_type = info[field][:type]
|
103
120
|
tag, namespace = field_type.split(":").reverse
|
121
|
+
|
104
122
|
result << [[type, field], tag] if user_defined(namespace)
|
105
123
|
end
|
106
124
|
end if document
|
125
|
+
|
107
126
|
result
|
108
127
|
end
|
109
128
|
end
|
@@ -140,5 +159,8 @@ module Wasabi
|
|
140
159
|
parser
|
141
160
|
end
|
142
161
|
|
162
|
+
def element_keys(info)
|
163
|
+
info.keys - [:namespace, :order!, :base_type]
|
164
|
+
end
|
143
165
|
end
|
144
166
|
end
|
data/lib/wasabi/parser.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "uri"
|
2
|
-
require "wasabi/xpath_helper"
|
3
2
|
require "wasabi/core_ext/string"
|
4
3
|
|
5
4
|
module Wasabi
|
@@ -8,7 +7,11 @@ module Wasabi
|
|
8
7
|
#
|
9
8
|
# Parses WSDL documents and remembers their important parts.
|
10
9
|
class Parser
|
11
|
-
|
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/"
|
12
15
|
|
13
16
|
def initialize(document)
|
14
17
|
self.document = document
|
@@ -51,16 +54,20 @@ module Wasabi
|
|
51
54
|
parse_namespaces
|
52
55
|
parse_endpoint
|
53
56
|
parse_service_name
|
57
|
+
parse_messages
|
58
|
+
parse_port_types
|
59
|
+
parse_port_type_operations
|
54
60
|
parse_operations
|
61
|
+
parse_operations_parameters
|
55
62
|
parse_types
|
56
63
|
parse_deferred_types
|
57
64
|
end
|
58
65
|
|
59
66
|
def parse_namespaces
|
60
|
-
element_form_default =
|
67
|
+
element_form_default = schemas.first && schemas.first['elementFormDefault']
|
61
68
|
@element_form_default = element_form_default.to_s.to_sym if element_form_default
|
62
69
|
|
63
|
-
namespace =
|
70
|
+
namespace = document.root['targetNamespace']
|
64
71
|
@namespace = namespace.to_s if namespace
|
65
72
|
|
66
73
|
@namespaces = @document.namespaces.inject({}) do |memo, (key, value)|
|
@@ -70,38 +77,80 @@ module Wasabi
|
|
70
77
|
end
|
71
78
|
|
72
79
|
def parse_endpoint
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
begin
|
77
|
-
@endpoint = URI(URI.escape(endpoint.to_s)) if endpoint
|
78
|
-
rescue URI::InvalidURIError
|
79
|
-
@endpoint = nil
|
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)
|
80
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
|
81
93
|
end
|
82
94
|
|
83
95
|
def parse_service_name
|
84
|
-
service_name =
|
96
|
+
service_name = document.root['name']
|
85
97
|
@service_name = service_name.to_s if service_name
|
86
98
|
end
|
87
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
|
+
|
88
135
|
def parse_operations
|
89
|
-
operations = xpath("wsdl:definitions/wsdl:binding/wsdl:operation")
|
136
|
+
operations = document.xpath("wsdl:definitions/wsdl:binding/wsdl:operation", 'wsdl' => WSDL)
|
90
137
|
operations.each do |operation|
|
91
138
|
name = operation.attribute("name").to_s
|
92
139
|
|
93
|
-
|
94
|
-
|
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
|
95
143
|
|
96
144
|
if soap_action
|
97
145
|
soap_action = soap_action.to_s
|
98
146
|
action = soap_action && !soap_action.empty? ? soap_action : name
|
99
147
|
|
100
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)
|
101
150
|
namespace_id, input = input_for(operation)
|
102
151
|
|
103
152
|
# Store namespace identifier so this operation can be mapped to the proper namespace.
|
104
|
-
@operations[name.snakecase.to_sym] = { :action => action, :input => input, :namespace_identifier => namespace_id
|
153
|
+
@operations[name.snakecase.to_sym] = { :action => action, :input => input, :output => output, :namespace_identifier => namespace_id}
|
105
154
|
elsif !@operations[name.snakecase.to_sym]
|
106
155
|
@operations[name.snakecase.to_sym] = { :action => name, :input => name }
|
107
156
|
end
|
@@ -109,38 +158,65 @@ module Wasabi
|
|
109
158
|
end
|
110
159
|
|
111
160
|
def parse_types
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
117
176
|
end
|
118
177
|
|
119
|
-
def process_type(type, name)
|
120
|
-
|
121
|
-
@types[name]
|
178
|
+
def process_type(namespace, type, name)
|
179
|
+
@types[name] ||= { :namespace => namespace }
|
180
|
+
@types[name][:order!] = []
|
122
181
|
|
123
|
-
xpath(
|
124
|
-
|
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 }
|
125
185
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
132
200
|
end
|
133
201
|
|
134
|
-
type.xpath('./xs:complexContent/xs:extension[@base]',
|
135
|
-
"xs" => "http://www.w3.org/2001/XMLSchema"
|
136
|
-
).each do |inherits|
|
202
|
+
type.xpath('./xs:complexContent/xs:extension[@base]', 'xs' => XSD).each do |inherits|
|
137
203
|
base = inherits.attribute('base').value.match(/\w+$/).to_s
|
204
|
+
|
138
205
|
if @types[base]
|
139
|
-
|
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
|
140
210
|
else
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
144
220
|
end
|
145
221
|
end
|
146
222
|
end
|
@@ -149,28 +225,39 @@ module Wasabi
|
|
149
225
|
deferred_types.each(&:call)
|
150
226
|
end
|
151
227
|
|
152
|
-
def
|
153
|
-
|
154
|
-
schema_namespace ? schema_namespace.to_s : @namespace
|
228
|
+
def input_for(operation)
|
229
|
+
input_output_for(operation, "input")
|
155
230
|
end
|
156
231
|
|
157
|
-
def
|
232
|
+
def output_for(operation)
|
233
|
+
input_output_for(operation, "output")
|
234
|
+
end
|
235
|
+
|
236
|
+
def input_output_for(operation, input_output)
|
158
237
|
operation_name = operation["name"]
|
159
238
|
|
160
239
|
# Look up the input by walking up to portType, then up to the message.
|
161
240
|
|
162
|
-
binding_type =
|
163
|
-
|
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 }
|
164
248
|
|
165
249
|
# TODO: Stupid fix for missing support for imports.
|
166
250
|
# Sometimes portTypes are actually included in a separate WSDL.
|
167
|
-
if
|
168
|
-
port_message_ns_id, port_message_type =
|
251
|
+
if port_type_input_output
|
252
|
+
port_message_ns_id, port_message_type = port_type_input_output.attribute("message").to_s.split(':')
|
169
253
|
|
170
254
|
message_ns_id, message_type = nil
|
171
255
|
|
172
256
|
# TODO: Support multiple 'part' elements in the message.
|
173
|
-
|
257
|
+
message = @messages[port_message_type]
|
258
|
+
port_message_part = message.element_children.find { |node| node.name == 'part' }
|
259
|
+
|
260
|
+
if port_message_part
|
174
261
|
if (port_message_part_element = port_message_part.attribute("element"))
|
175
262
|
message_ns_id, message_type = port_message_part_element.to_s.split(':')
|
176
263
|
end
|
@@ -180,12 +267,38 @@ module Wasabi
|
|
180
267
|
if message_type
|
181
268
|
[message_ns_id, message_type]
|
182
269
|
else
|
183
|
-
[port_message_ns_id,
|
270
|
+
[port_message_ns_id, port_message_type]
|
184
271
|
end
|
185
272
|
else
|
186
273
|
[nil, operation_name]
|
187
274
|
end
|
188
275
|
end
|
189
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
|
+
|
190
302
|
end
|
303
|
+
|
191
304
|
end
|