diff --git a/lib/handsoap/parser.rb b/lib/handsoap/parser.rb
new file mode 100644
index 0000000..9cd0663
--- /dev/null
+++ b/lib/handsoap/parser.rb
@@ -0,0 +1,794 @@
+# -*- coding: utf-8 -*-
+require 'open-uri'
+require 'nokogiri'
+
+module Handsoap
+
+ module Parser
+
+ class XsdSpider
+ def initialize(uri)
+ @queue = []
+ @wsdl_uri = uri
+ end
+
+ def results
+ @queue
+ end
+
+ def wsdl
+ @queue.each do |element|
+ return element if element[:href] == @wsdl_uri
+ end
+ end
+
+ def process!
+ add_href @wsdl_uri
+ while process_next do end
+ end
+
+ private
+
+ def add_href(href, namespaces = {})
+ unless @queue.find { |element| element[:href] == href }
+ @queue << { :href => href, :namespaces => namespaces, :state => :new, :document => nil }
+ end
+ end
+
+ def process_next
+ next_element = @queue.find { |element| element[:state] == :new }
+ if next_element
+ next_element.merge! spider_href(next_element[:href], next_element[:namespaces])
+ next_element[:state] = :done
+ return true
+ end
+ return false
+ end
+
+ def spider_href(href, namespaces)
+ raise "'href' must be a String" if href.nil?
+ # puts "getting #{href}"
+ ns_xs = {'xs' => 'http://www.w3.org/2001/XMLSchema'}
+ xsd = Nokogiri.XML(Kernel.open(href).read)
+ namespaces.merge! xsd.namespaces
+ #
+ #
+ xsd.xpath('//xs:include', ns_xs).each do |inc|
+ add_href(inc['schemaLocation'], namespaces)
+ end
+ xsd.xpath('//xs:import', ns_xs).each do |inc|
+ add_href(inc['schemaLocation'], namespaces.merge({ 'xmlns' => inc['namespace'] }))
+ end
+ { :document => xsd, :namespaces => namespaces }
+ end
+ end
+
+ class QName
+ attr_reader :name, :namespace
+ def initialize(str_repr, namespaces)
+ @str_repr = str_repr.to_s
+ matches = /^(.+):(.+)$/.match(str_repr)
+ if matches
+ @name = matches[2]
+ @namespace = namespaces['xmlns:' + matches[1]] || raise("Document doesn't define namespace '#{matches[1]}'")
+ else
+ @name = str_repr
+ @namespace = namespaces['xmlns']
+ end
+ end
+ def full_name
+ "{#{@namespace}}#{@name}"
+ end
+ def to_s
+ # @str_repr
+ full_name
+ end
+ end
+
+ class WSDL
+ def initialize(xsd)
+ @xsd = xsd
+ end
+
+ def messages
+ #
+ #
+ # ---
+ # {
+ # 'KeywordSearchRequest' => {
+ # 'KeywordSearchRequest' => Part(
+ # :name => '..',
+ # :type => QName('typens:KeywordRequest')
+ # )
+ # }
+ # }
+ return @messages if @messages
+ ns_wsdl = {'wsdl' => 'http://schemas.xmlsoap.org/wsdl/'}
+ wsdl = @xsd.wsdl[:document]
+ @messages = {}
+ wsdl.xpath('//wsdl:message', ns_wsdl).each do |xml_message|
+ name = xml_message['name']
+ @messages[name] = {}
+ xml_message.xpath('./wsdl:part', ns_wsdl).each do |xml_part|
+ @messages[name][xml_part['name']] = Part.new(xml_part['name'], QName.new(xml_part['type'] || xml_part['element'], wsdl.namespaces))
+ end
+ end
+ return @messages
+ end
+
+ def port_types
+ #
+ #
+ #
+ #
+ # --
+ # {
+ # 'AmazonSearchPort' => {
+ # 'KeywordSearchRequest' => {
+ # 'input' => MessageType(
+ # :name => 'input',
+ # :message => QName('typens:KeywordSearchRequest')
+ # ),
+ # 'output' => MessageType(
+ # :name => 'output',
+ # :message => QName('typens:KeywordSearchResponse')
+ # )
+ # }
+ # }
+ # }
+ return @port_types if @port_types
+ ns_wsdl = {'wsdl' => 'http://schemas.xmlsoap.org/wsdl/'}
+ wsdl = @xsd.wsdl[:document]
+ @port_types = {}
+ wsdl.xpath('//wsdl:portType', ns_wsdl).each do |xml_port_type|
+ port_type_name = xml_port_type['name']
+ operations = {}
+ xml_port_type.xpath('./wsdl:operation', ns_wsdl).each do |xml_operation|
+ operations[xml_operation['name']] = {}
+ xml_operation.xpath('./wsdl:*[@message]', ns_wsdl).each do |xml_message_type|
+ message_type = MessageType.new(xml_message_type.node_name, QName.new(xml_message_type['message'], wsdl.namespaces))
+ operations[xml_operation['name']][message_type.name] = message_type
+ end
+ end
+ @port_types[port_type_name] = operations
+ end
+ return @port_types
+ end
+
+ def bindings
+ #
+ #
+ #
+ #
+ #
+ #
+ #