summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--lib/soap/baseData.rb782
-rw-r--r--lib/soap/element.rb232
-rw-r--r--lib/soap/encodingstyle/aspDotNetHandler.rb232
-rw-r--r--lib/soap/encodingstyle/handler.rb111
-rw-r--r--lib/soap/encodingstyle/literalHandler.rb218
-rw-r--r--lib/soap/encodingstyle/soapHandler.rb548
-rw-r--r--lib/soap/generator.rb206
-rw-r--r--lib/soap/mapping.rb21
-rw-r--r--lib/soap/mapping/factory.rb310
-rw-r--r--lib/soap/mapping/mapping.rb218
-rw-r--r--lib/soap/mapping/registry.rb408
-rw-r--r--lib/soap/mapping/rubytypeFactory.rb437
-rw-r--r--lib/soap/mapping/typeMap.rb52
-rw-r--r--lib/soap/mapping/wsdlRegistry.rb146
-rw-r--r--lib/soap/marshal.rb71
-rw-r--r--lib/soap/netHttpClient.rb101
-rw-r--r--lib/soap/parser.rb252
-rw-r--r--lib/soap/processor.rb79
-rw-r--r--lib/soap/rpc/cgistub.rb214
-rw-r--r--lib/soap/rpc/driver.rb189
-rw-r--r--lib/soap/rpc/element.rb278
-rw-r--r--lib/soap/rpc/proxy.rb147
-rw-r--r--lib/soap/rpc/router.rb176
-rw-r--r--lib/soap/rpc/rpc.rb36
-rw-r--r--lib/soap/rpc/soaplet.rb167
-rw-r--r--lib/soap/rpc/standaloneServer.rb116
-rw-r--r--lib/soap/soap.rb112
-rw-r--r--lib/soap/streamHandler.rb188
-rw-r--r--lib/soap/wsdlDriver.rb490
-rw-r--r--lib/wsdl/binding.rb76
-rw-r--r--lib/wsdl/data.rb73
-rw-r--r--lib/wsdl/definitions.rb233
-rw-r--r--lib/wsdl/documentation.rb43
-rw-r--r--lib/wsdl/import.rb81
-rw-r--r--lib/wsdl/importer.rb75
-rw-r--r--lib/wsdl/info.rb44
-rw-r--r--lib/wsdl/message.rb65
-rw-r--r--lib/wsdl/operation.rb144
-rw-r--r--lib/wsdl/operationBinding.rb91
-rw-r--r--lib/wsdl/param.rb85
-rw-r--r--lib/wsdl/parser.rb170
-rw-r--r--lib/wsdl/part.rb63
-rw-r--r--lib/wsdl/port.rb95
-rw-r--r--lib/wsdl/portType.rb83
-rw-r--r--lib/wsdl/service.rb72
-rw-r--r--lib/wsdl/soap/address.rb51
-rw-r--r--lib/wsdl/soap/binding.rb59
-rw-r--r--lib/wsdl/soap/body.rb63
-rw-r--r--lib/wsdl/soap/complexType.rb96
-rw-r--r--lib/wsdl/soap/data.rb52
-rw-r--r--lib/wsdl/soap/definitions.rb130
-rw-r--r--lib/wsdl/soap/fault.rb63
-rw-r--r--lib/wsdl/soap/header.rb90
-rw-r--r--lib/wsdl/soap/headerfault.rb67
-rw-r--r--lib/wsdl/soap/operation.rb131
-rw-r--r--lib/wsdl/types.rb54
-rw-r--r--lib/wsdl/wsdl.rb34
-rw-r--r--lib/wsdl/xmlSchema/all.rb76
-rw-r--r--lib/wsdl/xmlSchema/any.rb67
-rw-r--r--lib/wsdl/xmlSchema/attribute.rb85
-rw-r--r--lib/wsdl/xmlSchema/choice.rb76
-rw-r--r--lib/wsdl/xmlSchema/complexContent.rb90
-rw-r--r--lib/wsdl/xmlSchema/complexType.rb130
-rw-r--r--lib/wsdl/xmlSchema/content.rb107
-rw-r--r--lib/wsdl/xmlSchema/data.rb75
-rw-r--r--lib/wsdl/xmlSchema/element.rb115
-rw-r--r--lib/wsdl/xmlSchema/import.rb55
-rw-r--r--lib/wsdl/xmlSchema/parser.rb172
-rw-r--r--lib/wsdl/xmlSchema/schema.rb105
-rw-r--r--lib/wsdl/xmlSchema/sequence.rb76
-rw-r--r--lib/wsdl/xmlSchema/unique.rb45
-rw-r--r--lib/xsd/charset.rb175
-rw-r--r--lib/xsd/datatypes.rb1094
-rw-r--r--lib/xsd/datatypes1999.rb31
-rw-r--r--lib/xsd/iconvcharset.rb44
-rw-r--r--lib/xsd/namedelements.rb86
-rw-r--r--lib/xsd/ns.rb141
-rw-r--r--lib/xsd/qname.rb77
-rw-r--r--lib/xsd/xmlparser.rb72
-rw-r--r--lib/xsd/xmlparser/parser.rb107
-rw-r--r--lib/xsd/xmlparser/rexmlparser.rb65
-rw-r--r--lib/xsd/xmlparser/xmlparser.rb61
-rw-r--r--lib/xsd/xmlparser/xmlscanner.rb158
-rw-r--r--sample/soap/babelfish.rb16
-rw-r--r--sample/soap/calc/calc.rb17
-rw-r--r--sample/soap/calc/calc2.rb29
-rw-r--r--sample/soap/calc/client.rb26
-rw-r--r--sample/soap/calc/client2.rb29
-rw-r--r--sample/soap/calc/httpd.rb15
-rw-r--r--sample/soap/calc/server.cgi15
-rw-r--r--sample/soap/calc/server.rb17
-rw-r--r--sample/soap/calc/server2.rb20
-rw-r--r--sample/soap/digraph.rb43
-rw-r--r--sample/soap/exchange/client.rb19
-rw-r--r--sample/soap/exchange/exchange.rb17
-rw-r--r--sample/soap/exchange/httpd.rb15
-rw-r--r--sample/soap/exchange/server.cgi14
-rw-r--r--sample/soap/exchange/server.rb16
-rw-r--r--sample/soap/helloworld/hw_c.rb6
-rw-r--r--sample/soap/helloworld/hw_s.rb17
-rw-r--r--sample/soap/icd/IICD.rb17
-rw-r--r--sample/soap/icd/icd.rb46
-rw-r--r--sample/soap/raa/iRAA.rb154
-rw-r--r--sample/soap/raa/soap4r.rb30
-rw-r--r--sample/soap/sampleStruct/client.rb16
-rw-r--r--sample/soap/sampleStruct/httpd.rb15
-rw-r--r--sample/soap/sampleStruct/iSampleStruct.rb22
-rw-r--r--sample/soap/sampleStruct/sampleStruct.rb13
-rw-r--r--sample/soap/sampleStruct/server.cgi14
-rw-r--r--sample/soap/sampleStruct/server.rb16
-rw-r--r--sample/wsdl/amazon/AmazonSearch.rb3701
-rw-r--r--sample/wsdl/amazon/AmazonSearchDriver.rb445
-rw-r--r--sample/wsdl/amazon/sampleClient.rb37
-rw-r--r--sample/wsdl/amazon/wsdlDriver.rb48
-rw-r--r--sample/wsdl/googleSearch/GoogleSearch.rb258
-rw-r--r--sample/wsdl/googleSearch/GoogleSearchDriver.rb101
-rw-r--r--sample/wsdl/googleSearch/README6
-rw-r--r--sample/wsdl/googleSearch/httpd.rb15
-rw-r--r--sample/wsdl/googleSearch/sampleClient.rb56
-rw-r--r--sample/wsdl/googleSearch/sjissearch.sh3
-rw-r--r--sample/wsdl/googleSearch/wsdlDriver.rb23
-rw-r--r--sample/wsdl/raa/raa.wsdl264
-rw-r--r--sample/wsdl/raa/soap4r.rb31
-rw-r--r--test/soap/calc/calc.rb17
-rw-r--r--test/soap/calc/calc2.rb29
-rw-r--r--test/soap/calc/server.cgi15
-rw-r--r--test/soap/calc/server.rb17
-rw-r--r--test/soap/calc/server2.rb20
-rw-r--r--test/soap/calc/test_calc.rb41
-rw-r--r--test/soap/calc/test_calc2.rb43
-rw-r--r--test/soap/calc/test_calc_cgi.rb42
-rw-r--r--test/soap/helloworld/hw_s.rb17
-rw-r--r--test/soap/helloworld/test_helloworld.rb31
-rw-r--r--test/soap/marshal/cmarshal.rb142
-rw-r--r--test/soap/marshal/test_digraph.rb45
-rw-r--r--test/soap/marshal/test_marshal.rb301
-rw-r--r--test/soap/marshal/test_struct.rb38
-rw-r--r--test/soap/test_basetype.rb951
-rw-r--r--test/soap/test_soapelement.rb114
-rw-r--r--test/wsdl/emptycomplextype.wsdl78
-rw-r--r--test/wsdl/test_emptycomplextype.rb14
-rw-r--r--test/xsd/test_xmlschemaparser.rb14
-rw-r--r--test/xsd/test_xsd.rb976
-rw-r--r--test/xsd/xmlschema.xml8
145 files changed, 20938 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 3538f1125f..7b60e14f6f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Mon Sep 25 00:13:15 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/soap/* (29 files): SOAP4R added.
+
+ * lib/wsdl/* (42 files): WSDL4R added.
+
+ * lib/xsd/* (12 files): XSD4R added.
+
+ * test/soap/* (16 files): added.
+
+ * test/wsdl/* (2 files): added.
+
+ * test/xsd/* (3 files): added.
+
+ * sample/soap/* (27 files): added.
+
+ * sample/wsdl/* (13 files): added.
+
Wed Sep 24 02:08:11 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/cgihandler.rb: conform to mswin32.
diff --git a/lib/soap/baseData.rb b/lib/soap/baseData.rb
new file mode 100644
index 0000000000..30f3bce767
--- /dev/null
+++ b/lib/soap/baseData.rb
@@ -0,0 +1,782 @@
+=begin
+SOAP4R - Base type library
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/datatypes'
+require 'soap/soap'
+
+
+module SOAP
+
+
+###
+## Mix-in module for SOAP base type classes.
+#
+module SOAPModuleUtils
+ include SOAP
+
+public
+
+ def decode(elename)
+ d = self.new
+ d.elename = elename
+ d
+ end
+end
+
+
+###
+## Mix-in module for SOAP base type instances.
+#
+module SOAPBasetype
+ include SOAP
+
+ attr_accessor :encodingstyle
+
+ attr_accessor :elename
+ attr_accessor :id
+ attr_reader :precedents
+ attr_accessor :root
+ attr_accessor :parent
+ attr_accessor :position
+ attr_reader :extraattr
+
+public
+
+ def initialize(*vars)
+ super(*vars)
+ @encodingstyle = nil
+ @elename = XSD::QName.new
+ @id = nil
+ @precedents = []
+ @parent = nil
+ @position = nil
+ @extraattr = {}
+ end
+end
+
+
+###
+## Mix-in module for SOAP compound type instances.
+#
+module SOAPCompoundtype
+ include SOAP
+
+ attr_accessor :encodingstyle
+
+ attr_accessor :elename
+ attr_accessor :id
+ attr_reader :precedents
+ attr_accessor :root
+ attr_accessor :parent
+ attr_accessor :position
+ attr_reader :extraattr
+
+ attr_accessor :definedtype
+
+public
+
+ def initialize(type)
+ super()
+ @type = type
+ @encodingstyle = nil
+ @elename = XSD::QName.new
+ @id = nil
+ @precedents = []
+ @root = false
+ @parent = nil
+ @position = nil
+ @definedtype = nil
+ @extraattr = {}
+ end
+end
+
+
+###
+## Convenience datatypes.
+#
+class SOAPReference < XSD::NSDBase
+ include SOAPBasetype
+ extend SOAPModuleUtils
+
+public
+
+ attr_accessor :refid
+ attr_accessor :elename
+
+ # Override the definition in SOAPBasetype.
+ def initialize(refid = nil)
+ super()
+ @type = XSD::QName.new
+ @encodingstyle = nil
+ @elename = XSD::QName.new
+ @id = nil
+ @precedents = []
+ @root = false
+ @parent = nil
+ @refid = refid
+ @obj = nil
+ end
+
+ def __getobj__
+ @obj
+ end
+
+ def __setobj__(obj)
+ @obj = obj
+ @refid = SOAPReference.create_refid(@obj)
+ @obj.id = @refid unless @obj.id
+ @obj.precedents << self
+ # Copies NSDBase information
+ @obj.type = @type unless @obj.type
+ end
+
+ # Why don't I use delegate.rb?
+ # -> delegate requires target object type at initialize time.
+ # Why don't I use forwardable.rb?
+ # -> forwardable requires a list of forwarding methods.
+ #
+ # ToDo: Maybe I should use forwardable.rb and give it a methods list like
+ # delegate.rb...
+ #
+ def method_missing(msg_id, *params)
+ if @obj
+ @obj.send(msg_id, *params)
+ else
+ nil
+ end
+ end
+
+ def self.decode(elename, refid)
+ d = super(elename)
+ d.refid = refid
+ d
+ end
+
+ def SOAPReference.create_refid(obj)
+ 'id' << obj.__id__.to_s
+ end
+end
+
+class SOAPNil < XSD::XSDNil
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+# SOAPRawString is for sending raw string. In contrast to SOAPString,
+# SOAP4R does not do XML encoding and does not convert its CES. The string it
+# holds is embedded to XML instance directly as a 'xsd:string'.
+class SOAPRawString < XSD::XSDString
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+
+###
+## Basic datatypes.
+#
+class SOAPAnySimpleType < XSD::XSDAnySimpleType
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPString < XSD::XSDString
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPBoolean < XSD::XSDBoolean
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPDecimal < XSD::XSDDecimal
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPFloat < XSD::XSDFloat
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPDouble < XSD::XSDDouble
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPDuration < XSD::XSDDuration
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPDateTime < XSD::XSDDateTime
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPTime < XSD::XSDTime
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPDate < XSD::XSDDate
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPGYearMonth < XSD::XSDGYearMonth
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPGYear < XSD::XSDGYear
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPGMonthDay < XSD::XSDGMonthDay
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPGDay < XSD::XSDGDay
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPGMonth < XSD::XSDGMonth
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPHexBinary < XSD::XSDHexBinary
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPBase64 < XSD::XSDBase64Binary
+ include SOAPBasetype
+ extend SOAPModuleUtils
+ Type = QName.new(EncodingNamespace, Base64Literal)
+
+public
+ # Override the definition in SOAPBasetype.
+ def initialize(value = nil)
+ super(value)
+ @type = Type
+ end
+
+ def as_xsd
+ @type = XSD::XSDBase64Binary::Type
+ end
+end
+
+class SOAPAnyURI < XSD::XSDAnyURI
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPQName < XSD::XSDQName
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+
+class SOAPInteger < XSD::XSDInteger
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPLong < XSD::XSDLong
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPInt < XSD::XSDInt
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+class SOAPShort < XSD::XSDShort
+ include SOAPBasetype
+ extend SOAPModuleUtils
+end
+
+
+###
+## Compound datatypes.
+#
+class SOAPStruct < XSD::NSDBase
+ include SOAPCompoundtype
+ include Enumerable
+
+public
+
+ def initialize(type = nil)
+ super(type || XSD::QName.new)
+ @array = []
+ @data = []
+ end
+
+ def to_s()
+ str = ''
+ self.each do |key, data|
+ str << "#{ key }: #{ data }\n"
+ end
+ str
+ end
+
+ def add(name, value)
+ add_member(name, value)
+ end
+
+ def [](idx)
+ if idx.is_a?(Range)
+ @data[idx]
+ elsif idx.is_a?(Integer)
+ if (idx > @array.size)
+ raise ArrayIndexOutOfBoundsError.new('In ' << @type.name)
+ end
+ @data[idx]
+ else
+ if @array.include?(idx)
+ @data[@array.index(idx)]
+ else
+ nil
+ end
+ end
+ end
+
+ def []=(idx, data)
+ if @array.include?(idx)
+ @data[@array.index(idx)] = data
+ else
+ add(idx, data)
+ end
+ end
+
+ def key?(name)
+ @array.include?(name)
+ end
+
+ def members
+ @array
+ end
+
+ def each
+ for i in 0..(@array.length - 1)
+ yield(@array[i], @data[i])
+ end
+ end
+
+ def replace
+ members.each do |member|
+ self[member] = yield(self[member])
+ end
+ end
+
+ def self.decode(elename, type)
+ s = SOAPStruct.new(type)
+ s.elename = elename
+ s
+ end
+
+private
+
+ def add_member(name, value = nil)
+ value = SOAPNil.new() unless value
+ @array.push(name)
+ value.elename = value.elename.dup_name(name)
+ @data.push(value)
+ end
+end
+
+
+# SOAPElement is not typed so it does not derive NSDBase.
+class SOAPElement
+ include Enumerable
+
+ attr_accessor :encodingstyle
+ attr_accessor :extraattr
+ attr_reader :precedents
+
+ attr_accessor :qualified
+ attr_accessor :elename
+
+ def initialize(elename, text = nil)
+ if !elename.is_a?(XSD::QName)
+ elename = XSD::QName.new(nil, elename)
+ end
+ @encodingstyle = LiteralNamespace
+ @extraattr = {}
+ @precedents = []
+
+ @qualified = false
+ @elename = elename
+
+ @array = []
+ @data = []
+ @text = text
+ end
+
+ # Text interface.
+ attr_accessor :text
+
+ # Element interfaces.
+ def add(value)
+ add_member(value.elename.name, value)
+ end
+
+ def [](idx)
+ if @array.include?(idx)
+ @data[@array.index(idx)]
+ else
+ nil
+ end
+ end
+
+ def []=(idx, data)
+ if @array.include?(idx)
+ @data[@array.index(idx)] = data
+ else
+ add(data)
+ end
+ end
+
+ def key?(name)
+ @array.include?(name)
+ end
+
+ def members
+ @array
+ end
+
+ def to_obj
+ if members.empty?
+ @text
+ else
+ hash = {}
+ each do |k, v|
+ hash[k] = v.to_obj
+ end
+ hash
+ end
+ end
+
+ def each
+ for i in 0..(@array.length - 1)
+ yield(@array[i], @data[i])
+ end
+ end
+
+ def self.decode(elename)
+ o = SOAPElement.new
+ o.elename = elename
+ o
+ end
+
+ def self.from_obj(hash_or_string)
+ o = SOAPElement.new(nil)
+ if hash_or_string.is_a?(Hash)
+ hash_or_string.each do |k, v|
+ child = self.from_obj(v)
+ child.elename = XSD::QName.new(nil, k)
+ o.add(child)
+ end
+ else
+ o.text = hash_or_string
+ end
+ o
+ end
+
+private
+
+ def add_member(name, value)
+ add_accessor(name)
+ @array.push(name)
+ @data.push(value)
+ end
+
+ def add_accessor(name)
+ methodname = name
+ if self.respond_to?(methodname)
+ methodname = safe_accessor_name(methodname)
+ end
+ begin
+ instance_eval <<-EOS
+ def #{ methodname }()
+ @data[@array.index('#{ name }')]
+ end
+
+ def #{ methodname }=(value)
+ @data[@array.index('#{ name }')] = value
+ end
+ EOS
+ rescue SyntaxError
+ methodname = safe_accessor_name(methodname)
+ retry
+ end
+ end
+
+ def safe_accessor_name(name)
+ "var_" << name.gsub(/[^a-zA-Z0-9_]/, '')
+ end
+end
+
+
+class SOAPArray < XSD::NSDBase
+ include SOAPCompoundtype
+ include Enumerable
+
+public
+
+ attr_accessor :sparse
+
+ attr_reader :offset, :rank
+ attr_accessor :size, :size_fixed
+ attr_reader :arytype
+
+ def initialize(type = nil, rank = 1, arytype = nil)
+ super(type || XSD::QName.new)
+ @rank = rank
+ @data = Array.new
+ @sparse = false
+ @offset = Array.new(rank, 0)
+ @size = Array.new(rank, 0)
+ @size_fixed = false
+ @position = nil
+ @arytype = arytype
+ end
+
+ def offset=(var)
+ @offset = var
+ @sparse = true
+ end
+
+ def add(value)
+ self[*(@offset)] = value
+ end
+
+ def [](*idxary)
+ if idxary.size != @rank
+ raise ArgumentError.new("Given #{ idxary.size } params does not match rank: #{ @rank }")
+ end
+
+ retrieve(idxary)
+ end
+
+ def []=(*idxary)
+ value = idxary.slice!(-1)
+
+ if idxary.size != @rank
+ raise ArgumentError.new("Given #{ idxary.size } params(#{ idxary }) does not match rank: #{ @rank }")
+ end
+
+ for i in 0..(idxary.size - 1)
+ if idxary[i] + 1 > @size[i]
+ @size[i] = idxary[i] + 1
+ end
+ end
+
+ data = retrieve(idxary[0, idxary.size - 1])
+ data[idxary.last] = value
+
+ if value.is_a?(SOAPBasetype) || value.is_a?(SOAPCompoundtype)
+ value.elename = value.elename.dup_name('item')
+
+ # Sync type
+ unless @type.name
+ @type = XSD::QName.new(value.type.namespace,
+ SOAPArray.create_arytype(value.type.name, @rank))
+ end
+
+ unless value.type
+ value.type = @type
+ end
+ end
+
+ @offset = idxary
+ offsetnext
+ end
+
+ def each
+ @data.each do |data|
+ yield(data)
+ end
+ end
+
+ def to_a
+ @data.dup
+ end
+
+ def replace
+ @data = deep_map(@data) do |ele|
+ yield(ele)
+ end
+ end
+
+ def deep_map(ary, &block)
+ ary.collect do |ele|
+ if ele.is_a?(Array)
+ deep_map(ele, &block)
+ else
+ new_obj = block.call(ele)
+ new_obj.elename = new_obj.elename.dup_name('item')
+ new_obj
+ end
+ end
+ end
+
+ def include?(var)
+ traverse_data(@data) do |v, *rank|
+ if v.is_a?(SOAPBasetype) && v.data == var
+ return true
+ end
+ end
+ false
+ end
+
+ def traverse
+ traverse_data(@data) do |v, *rank|
+ unless @sparse
+ yield(v)
+ else
+ yield(v, *rank) if v && !v.is_a?(SOAPNil)
+ end
+ end
+ end
+
+ def soap2array(ary)
+ traverse_data(@data) do |v, *position|
+ iteary = ary
+ for rank in 1..(position.size - 1)
+ idx = position[rank - 1]
+ if iteary[idx].nil?
+ iteary = iteary[idx] = Array.new
+ else
+ iteary = iteary[idx]
+ end
+ end
+ if block_given?
+ iteary[position.last] = yield(v)
+ else
+ iteary[position.last] = v
+ end
+ end
+ end
+
+ def position
+ @position
+ end
+
+private
+
+ def retrieve(idxary)
+ data = @data
+ for rank in 1..(idxary.size)
+ idx = idxary[rank - 1]
+ if data[idx].nil?
+ data = data[idx] = Array.new
+ else
+ data = data[idx]
+ end
+ end
+ data
+ end
+
+ def traverse_data(data, rank = 1)
+ for idx in 0..(ranksize(rank) - 1)
+ if rank < @rank
+ traverse_data(data[idx], rank + 1) do |*v|
+ v[1, 0] = idx
+ yield(*v)
+ end
+ else
+ yield(data[idx], idx)
+ end
+ end
+ end
+
+ def ranksize(rank)
+ @size[rank - 1]
+ end
+
+ def offsetnext
+ move = false
+ idx = @offset.size - 1
+ while !move && idx >= 0
+ @offset[idx] += 1
+ if @size_fixed
+ if @offset[idx] < @size[idx]
+ move = true
+ else
+ @offset[idx] = 0
+ idx -= 1
+ end
+ else
+ move = true
+ end
+ end
+ end
+
+ # Module function
+
+public
+
+ def self.decode(elename, type, arytype)
+ typestr, nofary = parse_type(arytype.name)
+ rank = nofary.count(',') + 1
+ plain_arytype = XSD::QName.new(arytype.namespace, typestr)
+ o = SOAPArray.new(type, rank, plain_arytype)
+ size = []
+ nofary.split(',').each do |s|
+ if s.empty?
+ size.clear
+ break
+ else
+ size << s.to_i
+ end
+ end
+ unless size.empty?
+ o.size = size
+ o.size_fixed = true
+ end
+ o.elename = elename
+ o
+ end
+
+private
+
+ def self.create_arytype(typename, rank)
+ "#{ typename }[" << ',' * (rank - 1) << ']'
+ end
+
+ TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$')
+
+ def self.parse_type(string)
+ TypeParseRegexp =~ string
+ return $1, $2
+ end
+end
+
+
+require 'soap/mapping/typeMap'
+
+
+end
diff --git a/lib/soap/element.rb b/lib/soap/element.rb
new file mode 100644
index 0000000000..640eafb0e4
--- /dev/null
+++ b/lib/soap/element.rb
@@ -0,0 +1,232 @@
+=begin
+SOAP4R - SOAP elements library
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'soap/baseData'
+
+
+module SOAP
+
+
+###
+## SOAP elements
+#
+module SOAPEnvelopeElement; end
+
+class SOAPFault < SOAPStruct
+ include SOAPEnvelopeElement
+ include SOAPCompoundtype
+
+public
+
+ def faultcode
+ self['faultcode']
+ end
+
+ def faultstring
+ self['faultstring']
+ end
+
+ def faultactor
+ self['faultactor']
+ end
+
+ def detail
+ self['detail']
+ end
+
+ def faultcode=(rhs)
+ self['faultcode'] = rhs
+ end
+
+ def faultstring=(rhs)
+ self['faultstring'] = rhs
+ end
+
+ def faultactor=(rhs)
+ self['faultactor'] = rhs
+ end
+
+ def detail=(rhs)
+ self['detail'] = rhs
+ end
+
+ def initialize(faultcode = nil, faultstring = nil, faultactor = nil, detail = nil)
+ super(EleFaultName)
+ @elename = EleFaultName
+ @encodingstyle = EncodingNamespace
+
+ if faultcode
+ self.faultcode = faultcode
+ self.faultstring = faultstring
+ self.faultactor = faultactor
+ self.detail = detail
+ self.faultcode.elename = EleFaultCodeName if self.faultcode
+ self.faultstring.elename = EleFaultStringName if self.faultstring
+ self.faultactor.elename = EleFaultActorName if self.faultactor
+ self.detail.elename = EleFaultDetailName if self.detail
+ end
+ end
+
+ def encode(buf, ns, attrs = {}, indent = '')
+ SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
+ SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
+ attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
+ name = ns.name(@elename)
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ yield(self.faultcode, false)
+ yield(self.faultstring, false)
+ yield(self.faultactor, false)
+ yield(self.detail, false) if self.detail
+ SOAPGenerator.encode_tag_end(buf, name, indent, true)
+ end
+end
+
+
+class SOAPBody < SOAPStruct
+ include SOAPEnvelopeElement
+
+public
+
+ def initialize(data = nil, is_fault = false)
+ super(nil)
+ @elename = EleBodyName
+ @encodingstyle = nil
+ add(data.elename.name, data) if data
+ @is_fault = is_fault
+ end
+
+ def encode(buf, ns, attrs = {}, indent = '')
+ name = ns.name(@elename)
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ if @is_fault
+ yield(@data, true)
+ else
+ @data.each do |data|
+ yield(data, true)
+ end
+ end
+ SOAPGenerator.encode_tag_end(buf, name, indent, true)
+ end
+
+ def root_node
+ @data.each do |node|
+ if node.root == 1
+ return node
+ end
+ end
+ # No specified root...
+ @data.each do |node|
+ if node.root != 0
+ return node
+ end
+ end
+
+ raise SOAPParser::FormatDecodeError.new('No root element.')
+ end
+end
+
+
+class SOAPHeaderItem < XSD::NSDBase
+ include SOAPEnvelopeElement
+ include SOAPCompoundtype
+
+public
+
+ attr_accessor :content
+ attr_accessor :mustunderstand
+ attr_accessor :encodingstyle
+
+ def initialize(content, mustunderstand = true, encodingstyle = nil)
+ super(nil)
+ @content = content
+ @mustunderstand = mustunderstand
+ @encodingstyle = encodingstyle || LiteralNamespace
+ end
+
+ def encode(buf, ns, attrs = {}, indent = '')
+ attrs.each do |key, value|
+ @content.attr[key] = value
+ end
+ @content.attr[ns.name(EnvelopeNamespace, AttrMustUnderstand)] =
+ (@mustunderstand ? '1' : '0')
+ if @encodingstyle
+ @content.attr[ns.name(EnvelopeNamespace, AttrEncodingStyle)] =
+ @encodingstyle
+ end
+ @content.encodingstyle = @encodingstyle if !@content.encodingstyle
+ yield(@content, true)
+ end
+end
+
+
+class SOAPHeader < SOAPArray
+ include SOAPEnvelopeElement
+
+ def initialize()
+ super(nil, 1) # rank == 1
+ @elename = EleHeaderName
+ @encodingstyle = nil
+ end
+
+ def encode(buf, ns, attrs = {}, indent = '')
+ name = ns.name(@elename)
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ @data.each do |data|
+ yield(data, true)
+ end
+ SOAPGenerator.encode_tag_end(buf, name, indent, true)
+ end
+
+ def length
+ @data.length
+ end
+end
+
+
+class SOAPEnvelope < XSD::NSDBase
+ include SOAPEnvelopeElement
+ include SOAPCompoundtype
+
+ attr_accessor :header
+ attr_accessor :body
+
+ def initialize(header = nil, body = nil)
+ super(nil)
+ @elename = EleEnvelopeName
+ @encodingstyle = nil
+ @header = header
+ @body = body
+ end
+
+ def encode(buf, ns, attrs = {}, indent = '')
+ SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace,
+ SOAPNamespaceTag)
+ name = ns.name(@elename)
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+
+ yield(@header, true) if @header and @header.length > 0
+ yield(@body, true)
+
+ SOAPGenerator.encode_tag_end(buf, name, indent, true)
+ end
+end
+
+
+end
diff --git a/lib/soap/encodingstyle/aspDotNetHandler.rb b/lib/soap/encodingstyle/aspDotNetHandler.rb
new file mode 100644
index 0000000000..fdce42a48a
--- /dev/null
+++ b/lib/soap/encodingstyle/aspDotNetHandler.rb
@@ -0,0 +1,232 @@
+=begin
+SOAP4R - ASP.NET EncodingStyle handler library
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/encodingstyle/handler'
+
+
+module SOAP
+module EncodingStyle
+
+
+class ASPDotNetHandler < Handler
+ Namespace = 'http://tempuri.org/ASP.NET'
+ add_handler
+
+ def initialize(charset = nil)
+ super(charset)
+ @textbuf = ''
+ @decode_typemap = nil
+ end
+
+
+ ###
+ ## encode interface.
+ #
+ def encode_data(buf, ns, qualified, data, parent, indent = '')
+ attrs = {}
+ name = if qualified and data.elename.namespace
+ SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
+ ns.name(data.elename)
+ else
+ data.elename.name
+ end
+
+ case data
+ when SOAPRawString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << data.to_s
+ when XSD::XSDString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(@charset ?
+ XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
+ when XSD::XSDAnySimpleType
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(data.to_s)
+ when SOAPStruct
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.each do |key, value|
+ if !value.elename.namespace
+ value.elename.namespace = data.elename.namespace
+ end
+ yield(value, true)
+ end
+ when SOAPArray
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.traverse do |child, *rank|
+ data.position = nil
+ yield(child, true)
+ end
+ else
+ raise EncodingStyleError.new("Unknown object:#{ data } in this encodingSt
+yle.")
+ end
+ end
+
+ def encode_data_end(buf, ns, qualified, data, parent, indent = "")
+ name = if qualified and data.elename.namespace
+ ns.name(data.elename)
+ else
+ data.elename.name
+ end
+ cr = data.is_a?(SOAPCompoundtype)
+ SOAPGenerator.encode_tag_end(buf, name, indent, cr)
+ end
+
+
+ ###
+ ## decode interface.
+ #
+ class SOAPTemporalObject
+ attr_accessor :parent
+
+ def initialize
+ @parent = nil
+ end
+ end
+
+ class SOAPUnknown < SOAPTemporalObject
+ def initialize(handler, elename)
+ super()
+ @handler = handler
+ @elename = elename
+ end
+
+ def as_struct
+ o = SOAPStruct.decode(@elename, XSD::AnyTypeName)
+ o.parent = @parent
+ o.type.name = @name
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_string
+ o = SOAPString.decode(@elename)
+ o.parent = @parent
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_nil
+ o = SOAPNil.decode(@elename)
+ o.parent = @parent
+ @handler.decode_parent(@parent, o)
+ o
+ end
+ end
+
+ def decode_tag(ns, elename, attrs, parent)
+ # ToDo: check if @textbuf is empty...
+ @textbuf = ''
+ o = SOAPUnknown.new(self, elename)
+ o.parent = parent
+ o
+ end
+
+ def decode_tag_end(ns, node)
+ o = node.node
+ if o.is_a?(SOAPUnknown)
+ newnode = o.as_string
+# if /\A\s*\z/ =~ @textbuf
+# o.as_struct
+# else
+# o.as_string
+# end
+ node.replace_node(newnode)
+ o = node.node
+ end
+
+ decode_textbuf(o)
+ @textbuf = ''
+ end
+
+ def decode_text(ns, text)
+ # @textbuf is set at decode_tag_end.
+ @textbuf << text
+ end
+
+ def decode_prologue
+ end
+
+ def decode_epilogue
+ end
+
+ def decode_parent(parent, node)
+ case parent.node
+ when SOAPUnknown
+ newparent = parent.node.as_struct
+ node.parent = newparent
+ parent.replace_node(newparent)
+ decode_parent(parent, node)
+
+ when SOAPStruct
+ data = parent.node[node.elename.name]
+ case data
+ when nil
+ parent.node.add(node.elename.name, node)
+ when SOAPArray
+ name, type_ns = node.elename.name, node.type.namespace
+ data.add(node)
+ node.elename, node.type.namespace = name, type_ns
+ else
+ parent.node[node.elename.name] = SOAPArray.new
+ name, type_ns = data.elename.name, data.type.namespace
+ parent.node[node.elename.name].add(data)
+ data.elename.name, data.type.namespace = name, type_ns
+ name, type_ns = node.elename.name, node.type.namespace
+ parent.node[node.elename.name].add(node)
+ node.elename.name, node.type.namespace = name, type_ns
+ end
+
+ when SOAPArray
+ if node.position
+ parent.node[*(decode_arypos(node.position))] = node
+ parent.node.sparse = true
+ else
+ parent.node.add(node)
+ end
+
+ when SOAPBasetype
+ raise EncodingStyleError.new("SOAP base type must not have a child.")
+
+ else
+ # SOAPUnknown does not have parent.
+ # raise EncodingStyleError.new("Illegal parent: #{ parent }.")
+ end
+ end
+
+private
+
+ def decode_textbuf(node)
+ if node.is_a?(XSD::XSDString)
+ if @charset
+ node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset))
+ else
+ node.set(@textbuf)
+ end
+ else
+ # Nothing to do...
+ end
+ end
+end
+
+ASPDotNetHandler.new
+
+
+end
+end
diff --git a/lib/soap/encodingstyle/handler.rb b/lib/soap/encodingstyle/handler.rb
new file mode 100644
index 0000000000..1ab9d86ec5
--- /dev/null
+++ b/lib/soap/encodingstyle/handler.rb
@@ -0,0 +1,111 @@
+=begin
+SOAP4R - EncodingStyle handler library
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/soap'
+require 'soap/baseData'
+require 'soap/element'
+
+
+module SOAP
+module EncodingStyle
+
+
+class Handler
+ @@handlers = {}
+
+ class EncodingStyleError < Error; end
+
+ class << self
+ def uri
+ self::Namespace
+ end
+
+ def handler(uri)
+ @@handlers[uri]
+ end
+
+ def each
+ @@handlers.each do |key, value|
+ yield(value)
+ end
+ end
+
+ private
+
+ def add_handler
+ @@handlers[self.uri] = self
+ end
+ end
+
+ attr_reader :charset
+ attr_accessor :generate_explicit_type
+ def decode_typemap=(complextypes)
+ @decode_typemap = complextypes
+ end
+
+ def initialize(charset)
+ @charset = charset
+ @generate_explicit_type = true
+ @decode_typemap = nil
+ end
+
+ ###
+ ## encode interface.
+ #
+ # Returns a XML instance as a string.
+ def encode_data(buf, ns, qualified, data, parent, indent)
+ raise NotImplementError.new('Method encode_data must be defined in derived class.')
+ end
+
+ def encode_data_end(buf, ns, qualified, data, parent, indent)
+ raise NotImplementError.new('Method encode_data must be defined in derived class.')
+ end
+
+ def encode_prologue
+ end
+
+ def encode_epilogue
+ end
+
+ ###
+ ## decode interface.
+ #
+ # Returns SOAP/OM data.
+ def decode_tag(ns, name, attrs, parent)
+ raise NotImplementError.new('Method decode_tag must be defined in derived class.')
+ end
+
+ def decode_tag_end(ns, name)
+ raise NotImplementError.new('Method decode_tag_end must be defined in derived class.')
+ end
+
+ def decode_text(ns, text)
+ raise NotImplementError.new('Method decode_text must be defined in derived class.')
+ end
+
+ def decode_prologue
+ end
+
+ def decode_epilogue
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/encodingstyle/literalHandler.rb b/lib/soap/encodingstyle/literalHandler.rb
new file mode 100644
index 0000000000..b5d0d464d7
--- /dev/null
+++ b/lib/soap/encodingstyle/literalHandler.rb
@@ -0,0 +1,218 @@
+=begin
+SOAP4R - XML Literal EncodingStyle handler library
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/encodingstyle/handler'
+
+
+module SOAP
+module EncodingStyle
+
+
+class LiteralHandler < Handler
+ Namespace = SOAP::LiteralNamespace
+ add_handler
+
+ def initialize(charset = nil)
+ super(charset)
+ @textbuf = ''
+ end
+
+
+ ###
+ ## encode interface.
+ #
+ def encode_data(buf, ns, qualified, data, parent, indent = '')
+ attrs = {}
+ name = if qualified and data.elename.namespace
+ SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
+ ns.name(data.elename)
+ else
+ data.elename.name
+ end
+
+ case data
+ when SOAPRawString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << data.to_s
+ when XSD::XSDString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(@charset ?
+ XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
+ when XSD::XSDAnySimpleType
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(data.to_s)
+ when SOAPStruct
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.each do |key, value|
+ value.elename.namespace = data.elename.namespace if !value.elename.namespace
+ yield(value, true)
+ end
+ when SOAPArray
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.traverse do |child, *rank|
+ data.position = nil
+ yield(child, true)
+ end
+ when SOAPElement
+ SOAPGenerator.encode_tag(buf, name, attrs.update(data.extraattr),
+ indent)
+ buf << data.text if data.text
+ data.each do |key, value|
+ value.elename.namespace = data.elename.namespace if !value.elename.namespace
+ #yield(value, data.qualified)
+ yield(value, qualified)
+ end
+ else
+ raise EncodingStyleError.new("Unknown object:#{ data } in this encodingStyle.")
+ end
+ end
+
+ def encode_data_end(buf, ns, qualified, data, parent, indent)
+ name = if qualified and data.elename.namespace
+ ns.name(data.elename)
+ else
+ data.elename.name
+ end
+ SOAPGenerator.encode_tag_end(buf, name, indent)
+ end
+
+
+ ###
+ ## decode interface.
+ #
+ class SOAPTemporalObject
+ attr_accessor :parent
+
+ def initialize
+ @parent = nil
+ end
+ end
+
+ class SOAPUnknown < SOAPTemporalObject
+ def initialize(handler, elename)
+ super()
+ @handler = handler
+ @elename = elename
+ end
+
+ def as_struct
+ o = SOAPStruct.decode(@elename, XSD::AnyTypeName)
+ o.parent = @parent
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_string
+ o = SOAPString.decode(@elename)
+ o.parent = @parent
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_nil
+ o = SOAPNil.decode(@elename)
+ o.parent = @parent
+ @handler.decode_parent(@parent, o)
+ o
+ end
+ end
+
+ def decode_tag(ns, elename, attrs, parent)
+ # ToDo: check if @textbuf is empty...
+ @textbuf = ''
+ o = SOAPUnknown.new(self, elename)
+ o.parent = parent
+ o
+ end
+
+ def decode_tag_end(ns, node)
+ o = node.node
+ if o.is_a?(SOAPUnknown)
+ newnode = if /\A\s*\z/ =~ @textbuf
+ o.as_struct
+ else
+ o.as_string
+ end
+ node.replace_node(newnode)
+ o = node.node
+ end
+
+ decode_textbuf(o)
+ @textbuf = ''
+ end
+
+ def decode_text(ns, text)
+ # @textbuf is set at decode_tag_end.
+ @textbuf << text
+ end
+
+ def decode_prologue
+ end
+
+ def decode_epilogue
+ end
+
+ def decode_parent(parent, node)
+ case parent.node
+ when SOAPUnknown
+ newparent = parent.node.as_struct
+ node.parent = newparent
+ parent.replace_node(newparent)
+ decode_parent(parent, node)
+
+ when SOAPStruct
+ parent.node.add(node.name, node)
+
+ when SOAPArray
+ if node.position
+ parent.node[*(decode_arypos(node.position))] = node
+ parent.node.sparse = true
+ else
+ parent.node.add(node)
+ end
+
+ when SOAPBasetype
+ raise EncodingStyleError.new("SOAP base type must not have a child.")
+
+ else
+ # SOAPUnknown does not have parent.
+ # raise EncodingStyleError.new("Illegal parent: #{ parent }.")
+ end
+ end
+
+private
+
+ def decode_textbuf(node)
+ if node.is_a?(XSD::XSDString)
+ if @charset
+ node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset))
+ else
+ node.set(@textbuf)
+ end
+ else
+ # Nothing to do...
+ end
+ end
+end
+
+LiteralHandler.new
+
+
+end
+end
diff --git a/lib/soap/encodingstyle/soapHandler.rb b/lib/soap/encodingstyle/soapHandler.rb
new file mode 100644
index 0000000000..b1b5072e49
--- /dev/null
+++ b/lib/soap/encodingstyle/soapHandler.rb
@@ -0,0 +1,548 @@
+=begin
+SOAP4R - SOAP EncodingStyle handler library
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/encodingstyle/handler'
+
+
+module SOAP
+module EncodingStyle
+
+
+class SOAPHandler < Handler
+ Namespace = SOAP::EncodingNamespace
+ add_handler
+
+ def initialize(charset = nil)
+ super(charset)
+ @refpool = []
+ @idpool = []
+ @textbuf = ''
+ @is_first_top_ele = true
+ end
+
+
+ ###
+ ## encode interface.
+ #
+ def encode_data(buf, ns, qualified, data, parent, indent = '')
+ attrs = encode_attrs(ns, qualified, data, parent)
+
+ if parent && parent.is_a?(SOAPArray) && parent.position
+ attrs[ns.name(AttrPositionName)] = '[' << parent.position.join(',') << ']'
+ end
+
+ name = nil
+ if qualified and data.elename.namespace
+ SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
+ name = ns.name(data.elename)
+ else
+ name = data.elename.name
+ end
+
+ if data.respond_to?(:encode)
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ return data.encode(buf, ns, attrs, indent)
+ end
+
+ case data
+ when SOAPReference
+ attrs['href'] = '#' << data.refid
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ when SOAPRawString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << data.to_s
+ when XSD::XSDString
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(@charset ?
+ XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
+ when XSD::XSDAnySimpleType
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ buf << SOAPGenerator.encode_str(data.to_s)
+ when SOAPStruct
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.each do |key, value|
+ yield(value, false)
+ end
+ when SOAPArray
+ SOAPGenerator.encode_tag(buf, name, attrs, indent)
+ data.traverse do |child, *rank|
+ data.position = data.sparse ? rank : nil
+ yield(child, false)
+ end
+ else
+ raise EncodingStyleError.new(
+ "Unknown object:#{ data } in this encodingStyle.")
+ end
+ end
+
+ def encode_data_end(buf, ns, qualified, data, parent, indent = '')
+ name = if qualified and data.elename.namespace
+ ns.name(data.elename)
+ else
+ data.elename.name
+ end
+ cr = data.is_a?(SOAPCompoundtype)
+ SOAPGenerator.encode_tag_end(buf, name, indent, cr)
+ end
+
+
+ ###
+ ## decode interface.
+ #
+ class SOAPTemporalObject
+ attr_accessor :parent
+ attr_accessor :position
+ attr_accessor :id
+ attr_accessor :root
+
+ def initialize
+ @parent = nil
+ @position = nil
+ @id = nil
+ @root = nil
+ end
+ end
+
+ class SOAPUnknown < SOAPTemporalObject
+ attr_reader :type
+ attr_accessor :definedtype
+ attr_reader :extraattr
+
+ def initialize(handler, elename, type, extraattr)
+ super()
+ @handler = handler
+ @elename = elename
+ @type = type
+ @extraattr = extraattr
+ @definedtype = nil
+ end
+
+ def as_struct
+ o = SOAPStruct.decode(@elename, @type)
+ o.id = @id
+ o.root = @root
+ o.parent = @parent
+ o.position = @position
+ o.extraattr.update(@extraattr)
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_string
+ o = SOAPString.decode(@elename)
+ o.id = @id
+ o.root = @root
+ o.parent = @parent
+ o.position = @position
+ o.extraattr.update(@extraattr)
+ @handler.decode_parent(@parent, o)
+ o
+ end
+
+ def as_nil
+ o = SOAPNil.decode(@elename)
+ o.id = @id
+ o.root = @root
+ o.parent = @parent
+ o.position = @position
+ o.extraattr.update(@extraattr)
+ @handler.decode_parent(@parent, o)
+ o
+ end
+ end
+
+ def decode_tag(ns, elename, attrs, parent)
+ # ToDo: check if @textbuf is empty...
+ @textbuf = ''
+ is_nil, type, arytype, root, offset, position, href, id, extraattr =
+ decode_attrs(ns, attrs)
+ o = nil
+ if is_nil
+ o = SOAPNil.decode(elename)
+ elsif href
+ o = SOAPReference.decode(elename, href)
+ @refpool << o
+ elsif @decode_typemap &&
+ (parent.node.class != SOAPBody || @is_first_top_ele)
+ # multi-ref element should be parsed by decode_tag_by_type.
+ @is_first_top_ele = false
+ o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, extraattr)
+ else
+ o = decode_tag_by_type(ns, elename, type, parent.node, arytype, extraattr)
+ end
+
+ if o.is_a?(SOAPArray)
+ if offset
+ o.offset = decode_arypos(offset)
+ o.sparse = true
+ else
+ o.sparse = false
+ end
+ end
+
+ o.parent = parent
+ o.id = id
+ o.root = root
+ o.position = position
+
+ unless o.is_a?(SOAPTemporalObject)
+ @idpool << o if o.id
+ decode_parent(parent, o)
+ end
+ o
+ end
+
+ def decode_tag_end(ns, node)
+ o = node.node
+ if o.is_a?(SOAPUnknown)
+ newnode = if /\A\s*\z/ =~ @textbuf
+ o.as_struct
+ else
+ o.as_string
+ end
+ if newnode.id
+ @idpool << newnode
+ end
+ node.replace_node(newnode)
+ o = node.node
+ end
+ if o.is_a?(SOAPCompoundtype)
+ o.definedtype = nil
+ end
+
+ decode_textbuf(o)
+ @textbuf = ''
+ end
+
+ def decode_text(ns, text)
+ # @textbuf is set at decode_tag_end.
+ @textbuf << text
+ end
+
+ def decode_prologue
+ @refpool.clear
+ @idpool.clear
+ @is_first_top_ele = true
+ end
+
+ def decode_epilogue
+ decode_resolve_id
+ end
+
+ def decode_parent(parent, node)
+ case parent.node
+ when SOAPUnknown
+ newparent = parent.node.as_struct
+ node.parent = newparent
+ if newparent.id
+ @idpool << newparent
+ end
+ parent.replace_node(newparent)
+ decode_parent(parent, node)
+
+ when SOAPStruct
+ parent.node.add(node.elename.name, node)
+ node.parent = parent.node
+
+ when SOAPArray
+ if node.position
+ parent.node[*(decode_arypos(node.position))] = node
+ parent.node.sparse = true
+ else
+ parent.node.add(node)
+ end
+ node.parent = parent.node
+
+ when SOAPBasetype
+ raise EncodingStyleError.new("SOAP base type must not have a child.")
+
+ else
+ raise EncodingStyleError.new("Illegal parent: #{ parent.node }.")
+ end
+ end
+
+private
+
+ def content_ranksize(typename)
+ typename.scan(/\[[\d,]*\]$/)[0]
+ end
+
+ def content_typename(typename)
+ typename.sub(/\[,*\]$/, '')
+ end
+
+ def create_arytype(ns, data)
+ XSD::QName.new(data.arytype.namespace,
+ content_typename(data.arytype.name) << '[' << data.size.join(',') << ']')
+ end
+
+ def encode_attrs(ns, qualified, data, parent)
+ return {} if data.is_a?(SOAPReference)
+ attrs = {}
+
+ if !parent || parent.encodingstyle != EncodingNamespace
+ if @generate_explicit_type
+ SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
+ SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
+ attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
+ end
+ data.encodingstyle = EncodingNamespace
+ end
+
+ if data.is_a?(SOAPNil)
+ attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue
+ elsif @generate_explicit_type
+ if data.type.namespace
+ SOAPGenerator.assign_ns(attrs, ns, data.type.namespace)
+ end
+ if data.is_a?(SOAPArray)
+ if data.arytype.namespace
+ SOAPGenerator.assign_ns(attrs, ns, data.arytype.namespace)
+ end
+ attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data))
+ if data.type.name
+ attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
+ end
+ elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type)
+ # No need to add.
+ elsif !data.type.namespace
+ # No need to add.
+ else
+ attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
+ end
+ end
+
+ data.extraattr.each do |key, value|
+ SOAPGenerator.assign_ns(attrs, ns, key.namespace)
+ attrs[ns.name(key)] = value # ns.name(value) ?
+ end
+ if data.id
+ attrs['id'] = data.id
+ end
+ attrs
+ end
+
+ def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr)
+ if parent.class == SOAPBody
+ # Unqualified name is allowed here.
+ type = @decode_typemap[elename] || @decode_typemap.find_name(elename.name)
+ unless type
+ raise EncodingStyleError.new("Unknown operation '#{ elename }'.")
+ end
+ o = SOAPStruct.new(elename)
+ o.definedtype = type
+ return o
+ end
+
+ if parent.type == XSD::AnyTypeName
+ return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
+ extraattr)
+ end
+
+ # parent.definedtype is nil means the parent is SOAPUnknown. SOAPUnknown is
+ # generated by decode_tag_by_type when its type is anyType.
+ parenttype = parent.definedtype || @decode_typemap[parent.type]
+ unless parenttype
+ raise EncodingStyleError.new("Unknown type '#{ parent.type }'.")
+ end
+ typename = parenttype.child_type(elename)
+ if typename
+ if (klass = TypeMap[typename])
+ return klass.decode(elename)
+ elsif typename == XSD::AnyTypeName
+ return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
+ extraattr)
+ end
+ end
+
+ type = if typename
+ @decode_typemap[typename]
+ else
+ parenttype.child_defined_complextype(elename)
+ end
+ unless type
+ raise EncodingStyleError.new("Unknown type '#{ typename }'.")
+ end
+
+ case type.compoundtype
+ when :TYPE_STRUCT
+ o = SOAPStruct.decode(elename, typename)
+ o.definedtype = type
+ return o
+ when :TYPE_ARRAY
+ expected_arytype = type.find_arytype
+ actual_arytype = if arytypestr
+ XSD::QName.new(expected_arytype.namespace,
+ content_typename(expected_arytype.name) <<
+ content_ranksize(arytypestr))
+ else
+ expected_arytype
+ end
+ o = SOAPArray.decode(elename, typename, actual_arytype)
+ o.definedtype = type
+ return o
+ end
+ return nil
+ end
+
+ def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr)
+ if arytypestr
+ type = typestr ? ns.parse(typestr) : ValueArrayName
+ node = SOAPArray.decode(elename, type, ns.parse(arytypestr))
+ node.extraattr.update(extraattr)
+ return node
+ end
+
+ type = nil
+ if typestr
+ type = ns.parse(typestr)
+ elsif parent.is_a?(SOAPArray)
+ type = parent.arytype
+ else
+ # Since it's in dynamic(without any type) encoding process,
+ # assumes entity as its type itself.
+ # <SOAP-ENC:Array ...> => type Array in SOAP-ENC.
+ # <Country xmlns="foo"> => type Country in foo.
+ type = elename
+ end
+
+ if (klass = TypeMap[type])
+ klass.decode(elename)
+ else
+ # Unknown type... Struct or String
+ SOAPUnknown.new(self, elename, type, extraattr)
+ end
+ end
+
+ def decode_textbuf(node)
+ case node
+ when XSD::XSDHexBinary, XSD::XSDBase64Binary
+ node.set_encoded(@textbuf)
+ when XSD::XSDString
+ if @charset
+ node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset))
+ else
+ node.set(@textbuf)
+ end
+ when SOAPNil
+ # Nothing to do.
+ when SOAPBasetype
+ node.set(@textbuf)
+ else
+ # Nothing to do...
+ end
+ end
+
+ NilLiteralMap = {
+ 'true' => true,
+ '1' => true,
+ 'false' => false,
+ '0' => false
+ }
+ RootLiteralMap = {
+ '1' => 1,
+ '0' => 0
+ }
+ def decode_attrs(ns, attrs)
+ is_nil = false
+ type = nil
+ arytype = nil
+ root = nil
+ offset = nil
+ position = nil
+ href = nil
+ id = nil
+ extraattr = {}
+
+ attrs.each do |key, value|
+ qname = ns.parse(key)
+ case qname.namespace
+ when XSD::InstanceNamespace
+ case qname.name
+ when XSD::NilLiteral
+ is_nil = NilLiteralMap[value] or
+ raise EncodingStyleError.new("Cannot accept attribute value: #{ value } as the value of xsi:#{ XSD::NilLiteral } (expected 'true', 'false', '1', or '0').")
+ next
+ when XSD::AttrType
+ type = value
+ next
+ end
+ when EncodingNamespace
+ case qname.name
+ when AttrArrayType
+ arytype = value
+ next
+ when AttrRoot
+ root = RootLiteralMap[value] or
+ raise EncodingStyleError.new(
+ "Illegal root attribute value: #{ value }.")
+ next
+ when AttrOffset
+ offset = value
+ next
+ when AttrPosition
+ position = value
+ next
+ end
+ end
+ if key == 'href'
+ href = value
+ next
+ elsif key == 'id'
+ id = value
+ next
+ end
+ extraattr[qname] = value
+ end
+
+ return is_nil, type, arytype, root, offset, position, href, id, extraattr
+ end
+
+ def decode_arypos(position)
+ /^\[(.+)\]$/ =~ position
+ $1.split(',').collect { |s| s.to_i }
+ end
+
+ def decode_resolve_id
+ count = @refpool.length # To avoid infinite loop
+ while !@refpool.empty? && count > 0
+ @refpool = @refpool.find_all { |ref|
+ o = @idpool.find { |item|
+ ('#' << item.id == ref.refid)
+ }
+ unless o
+ raise EncodingStyleError.new("Unresolved reference: #{ ref.refid }.")
+ end
+ if o.is_a?(SOAPReference)
+ true
+ else
+ ref.__setobj__(o)
+ false
+ end
+ }
+ count -= 1
+ end
+ end
+end
+
+SOAPHandler.new
+
+
+end
+end
diff --git a/lib/soap/generator.rb b/lib/soap/generator.rb
new file mode 100644
index 0000000000..6707aef195
--- /dev/null
+++ b/lib/soap/generator.rb
@@ -0,0 +1,206 @@
+=begin
+SOAP4R - SOAP XML Instance Generator library.
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/ns'
+require 'soap/soap'
+require 'soap/baseData'
+require 'soap/encodingstyle/handler'
+
+
+module SOAP
+
+
+###
+## CAUTION: MT-unsafe
+#
+class SOAPGenerator
+ include SOAP
+
+ class FormatEncodeError < Error; end
+
+public
+
+ attr_accessor :charset
+ attr_accessor :default_encodingstyle
+ attr_accessor :generate_explicit_type
+ attr_accessor :pretty
+
+ def initialize(opt = {})
+ @reftarget = nil
+ @handlers = {}
+ @charset = opt[:charset] || XSD::Charset.encoding_label
+ @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
+ @generate_explicit_type =
+ opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true
+ @pretty = true # opt[:pretty]
+ end
+
+ def generate(obj, io = nil)
+ prologue
+ @handlers.each do |uri, handler|
+ handler.encode_prologue
+ end
+
+ io = '' if io.nil?
+
+ ns = XSD::NS.new
+ io << xmldecl
+ encode_data(io, ns, true, obj, nil, 0)
+
+ @handlers.each do |uri, handler|
+ handler.encode_epilogue
+ end
+ epilogue
+
+ io
+ end
+
+ def encode_data(buf, ns, qualified, obj, parent, indent)
+ if obj.is_a?(SOAPEnvelopeElement)
+ encode_element(buf, ns, qualified, obj, parent, indent)
+ return
+ end
+
+ if @reftarget && !obj.precedents.empty?
+ @reftarget.add(obj.elename.name, obj)
+ ref = SOAPReference.new
+ ref.elename.name = obj.elename.name
+ ref.__setobj__(obj)
+ obj.precedents.clear # Avoid cyclic delay.
+ obj.encodingstyle = parent.encodingstyle
+ # SOAPReference is encoded here.
+ obj = ref
+ end
+
+ encodingstyle = obj.encodingstyle
+ # Children's encodingstyle is derived from its parent.
+ encodingstyle ||= parent.encodingstyle if parent
+ obj.encodingstyle = encodingstyle
+
+ handler = find_handler(encodingstyle || @default_encodingstyle)
+ unless handler
+ raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
+ end
+
+ if !obj.elename.name
+ raise FormatEncodeError.new("Element name not defined: #{ obj }.")
+ end
+
+ indent_str = ' ' * indent
+ child_indent = @pretty ? indent + 2 : indent
+ handler.encode_data(buf, ns, qualified, obj, parent, indent_str) do |child, child_q|
+ encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
+ end
+ handler.encode_data_end(buf, ns, qualified, obj, parent, indent_str)
+ end
+
+ def encode_element(buf, ns, qualified, obj, parent, indent)
+ indent_str = ' ' * indent
+ child_indent = @pretty ? indent + 2 : indent
+ attrs = {}
+ if obj.is_a?(SOAPBody)
+ @reftarget = obj
+ obj.encode(buf, ns, attrs, indent_str) do |child, child_q|
+ encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
+ end
+ @reftarget = nil
+ else
+ if obj.is_a?(SOAPEnvelope)
+ # xsi:nil="true" can appear even if dumping without explicit type.
+ SOAPGenerator.assign_ns(attrs, ns,
+ XSD::InstanceNamespace, XSINamespaceTag)
+ if @generate_explicit_type
+ SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag)
+ end
+ end
+ obj.encode(buf, ns, attrs, indent_str) do |child, child_q|
+ encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
+ end
+ end
+ end
+
+ def self.assign_ns(attrs, ns, namespace, tag = nil)
+ unless ns.assigned?(namespace)
+ tag = ns.assign(namespace, tag)
+ attrs['xmlns:' << tag] = namespace
+ end
+ end
+
+ def self.encode_tag(buf, elename, attrs = nil, indent = '')
+ if attrs
+ buf << "\n#{ indent }<#{ elename }" <<
+ attrs.collect { |key, value|
+ %Q[ #{ key }="#{ value }"]
+ }.join <<
+ '>'
+ else
+ buf << "\n#{ indent }<#{ elename }>"
+ end
+ end
+
+ def self.encode_tag_end(buf, elename, indent = '', cr = nil)
+ if cr
+ buf << "\n#{ indent }</#{ elename }>"
+ else
+ buf << "</#{ elename }>"
+ end
+ end
+
+ EncodeMap = {
+ '&' => '&amp;',
+ '<' => '&lt;',
+ '>' => '&gt;',
+ '"' => '&quot;',
+ '\'' => '&apos;',
+ "\r" => '&#xd;'
+ }
+ EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]")
+ def self.encode_str(str)
+ str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] }
+ end
+
+private
+
+ def prologue
+ end
+
+ def epilogue
+ end
+
+ def find_handler(encodingstyle)
+ unless @handlers.key?(encodingstyle)
+ handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset)
+ handler.generate_explicit_type = @generate_explicit_type
+ handler.encode_prologue
+ @handlers[encodingstyle] = handler
+ end
+ @handlers[encodingstyle]
+ end
+
+ def xmldecl
+ if @charset
+ %Q[<?xml version="1.0" encoding="#{ @charset }" ?>]
+ else
+ %Q[<?xml version="1.0" ?>]
+ end
+ end
+end
+
+
+end
diff --git a/lib/soap/mapping.rb b/lib/soap/mapping.rb
new file mode 100644
index 0000000000..8da1978a4f
--- /dev/null
+++ b/lib/soap/mapping.rb
@@ -0,0 +1,21 @@
+=begin
+SOAP4R - Ruby type mapping utility.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/mapping/mapping'
+require 'soap/mapping/registry'
diff --git a/lib/soap/mapping/factory.rb b/lib/soap/mapping/factory.rb
new file mode 100644
index 0000000000..2e5ddc1f15
--- /dev/null
+++ b/lib/soap/mapping/factory.rb
@@ -0,0 +1,310 @@
+=begin
+SOAP4R - Mapping factory.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+module Mapping
+
+
+class Factory
+ include TraverseSupport
+
+ def obj2soap(soap_class, obj, info, map)
+ raise NotImplementError.new
+ # return soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ raise NotImplementError.new
+ # return convert_succeeded_or_not, obj
+ end
+
+ if Object.respond_to?(:allocate)
+ # ruby/1.7 or later.
+ def create_empty_object(klass)
+ klass.allocate
+ end
+ else
+ def create_empty_object(klass)
+ name = klass.name
+ # Below line is from TANAKA, Akira's amarshal.rb.
+ # See http://cvs.m17n.org/cgi-bin/viewcvs/amarshal/?cvsroot=ruby
+ ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name))
+ end
+ end
+
+ def set_instance_vars(obj, values)
+ values.each do |name, value|
+ setter = name + "="
+ if obj.respond_to?(setter)
+ obj.__send__(setter, value)
+ else
+ obj.instance_eval("@#{ name } = value")
+ end
+ end
+ end
+
+ def setiv2obj(obj, node, map)
+ return if node.nil?
+ vars = {}
+ node.each do |name, value|
+ vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
+ end
+ set_instance_vars(obj, vars)
+ end
+
+ def setiv2soap(node, obj, map)
+ obj.instance_variables.each do |var|
+ name = var.sub(/^@/, '')
+ node.add(Mapping.name2elename(name),
+ Mapping._obj2soap(obj.instance_eval(var), map))
+ end
+ end
+
+ def addiv2soap(node, obj, map)
+ return if obj.instance_variables.empty?
+ ivars = SOAPStruct.new # Undefined type.
+ setiv2soap(ivars, obj, map)
+ node.add('ivars', ivars)
+ end
+
+ # It breaks Thread.current[:SOAPMarshalDataKey].
+ def mark_marshalled_obj(obj, soap_obj)
+ Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
+ end
+
+ # It breaks Thread.current[:SOAPMarshalDataKey].
+ def mark_unmarshalled_obj(node, obj)
+ Thread.current[:SOAPMarshalDataKey][node.id] = obj
+ end
+
+ def name2typename(name)
+ capitalize(name)
+ end
+
+ def capitalize(target)
+ target.gsub(/^([a-z])/) { $1.tr!('[a-z]', '[A-Z]') }
+ end
+end
+
+class StringFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ begin
+ if XSD::Charset.is_ces(obj, $KCODE)
+ encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
+ soap_obj = soap_class.new(encoded)
+ else
+ return nil
+ end
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ mark_marshalled_obj(obj, soap_obj)
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class BasetypeFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = nil
+ begin
+ soap_obj = soap_class.new(obj)
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ # Basetype except String should not be multiref-ed in SOAP/1.1.
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = node.data
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class DateTimeFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = nil
+ begin
+ soap_obj = soap_class.new(obj)
+ rescue XSD::ValueSpaceError
+ return nil
+ end
+ mark_marshalled_obj(obj, soap_obj)
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = nil
+ if obj_class == Time
+ obj = node.to_time
+ if obj.nil?
+ # Is out of range as a Time
+ return false
+ end
+ elsif obj_class == Date
+ obj = node.data
+ else
+ return false
+ end
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class Base64Factory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ soap_obj = soap_class.new(obj)
+ mark_marshalled_obj(obj, soap_obj) if soap_obj
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = node.string
+ mark_unmarshalled_obj(node, obj)
+ return true, obj
+ end
+end
+
+class ArrayFactory_ < Factory
+ # [[1], [2]] is converted to Array of Array, not 2-D Array.
+ # To create M-D Array, you must call Mapping.ary2md.
+ def obj2soap(soap_class, obj, info, map)
+ arytype = Mapping.obj2element(obj)
+ if arytype.name
+ arytype.namespace ||= RubyTypeNamespace
+ else
+ arytype = XSD::AnyTypeName
+ end
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+end
+
+class TypedArrayFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ arytype = info[:type] || info[0]
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ if node.rank > 1
+ return false
+ end
+ arytype = info[:type] || info[0]
+ unless node.arytype == arytype
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+end
+
+class TypedStructFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ type = info[:type] || info[0]
+ param = soap_class.new(type)
+ mark_marshalled_obj(obj, param)
+ if obj.class <= SOAP::Marshallable
+ setiv2soap(param, obj, map)
+ else
+ setiv2soap(param, obj, map)
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ type = info[:type] || info[0]
+ unless node.type == type
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ setiv2obj(obj, node, map)
+ return true, obj
+ end
+end
+
+MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
+class HashFactory_ < Factory
+ def obj2soap(soap_class, obj, info, map)
+ if obj.default or
+ (obj.respond_to?(:default_proc) and obj.default_proc)
+ return nil
+ end
+ param = SOAPStruct.new(MapQName)
+ mark_marshalled_obj(obj, param)
+ obj.each do |key, value|
+ elem = SOAPStruct.new
+ elem.add("key", Mapping._obj2soap(key, map))
+ elem.add("value", Mapping._obj2soap(value, map))
+ # ApacheAxis allows only 'item' here.
+ param.add("item", elem)
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == MapQName
+ return false
+ end
+ if node.key?('default')
+ return false
+ end
+ obj = create_empty_object(obj_class)
+ mark_unmarshalled_obj(node, obj)
+ node.each do |key, value|
+ obj[Mapping._soap2obj(value['key'], map)] =
+ Mapping._soap2obj(value['value'], map)
+ end
+ return true, obj
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/mapping/mapping.rb b/lib/soap/mapping/mapping.rb
new file mode 100644
index 0000000000..19eca5dab0
--- /dev/null
+++ b/lib/soap/mapping/mapping.rb
@@ -0,0 +1,218 @@
+=begin
+SOAP4R - Ruby type mapping utility.
+Copyright (C) 2000, 2001, 2003 NAKAMURA Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+
+
+module Mapping
+ RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6'
+ RubyTypeInstanceNamespace =
+ 'http://www.ruby-lang.org/xmlns/ruby/type-instance'
+ RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom'
+ ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap'
+
+
+ # TraverseSupport breaks Thread.current[:SOAPMarshalDataKey].
+ module TraverseSupport
+ def mark_marshalled_obj(obj, soap_obj)
+ Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
+ end
+
+ def mark_unmarshalled_obj(node, obj)
+ # node.id is not Object#id but SOAPReference#id
+ Thread.current[:SOAPMarshalDataKey][node.id] = obj
+ end
+ end
+
+
+ def self.obj2soap(obj, registry = nil, type = nil)
+ registry ||= Mapping::DefaultRegistry
+ Thread.current[:SOAPMarshalDataKey] = {}
+ soap_obj = _obj2soap(obj, registry, type)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ soap_obj
+ end
+
+ def self.soap2obj(node, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ Thread.current[:SOAPMarshalDataKey] = {}
+ obj = _soap2obj(node, registry)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ obj
+ end
+
+ def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ type = XSD::QName.new(type_ns, typename)
+ soap_ary = SOAPArray.new(ValueArrayName, 1, type)
+ Thread.current[:SOAPMarshalDataKey] = {}
+ ary.each do |ele|
+ soap_ary.add(_obj2soap(ele, registry, type))
+ end
+ Thread.current[:SOAPMarshalDataKey] = nil
+ soap_ary
+ end
+
+ def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ type = XSD::QName.new(type_ns, typename)
+ md_ary = SOAPArray.new(ValueArrayName, rank, type)
+ Thread.current[:SOAPMarshalDataKey] = {}
+ add_md_ary(md_ary, ary, [], registry)
+ Thread.current[:SOAPMarshalDataKey] = nil
+ md_ary
+ end
+
+ def self.fault2exception(e, registry = nil)
+ registry ||= Mapping::DefaultRegistry
+ detail = if e.detail
+ soap2obj(e.detail, registry) || ""
+ else
+ ""
+ end
+ if detail.is_a?(Mapping::SOAPException)
+ begin
+ raise detail.to_e
+ rescue Exception => e2
+ detail.set_backtrace(e2)
+ raise
+ end
+ else
+ e.detail = detail
+ e.set_backtrace(
+ if detail.is_a?(Array)
+ detail
+ else
+ [detail.to_s]
+ end
+ )
+ raise
+ end
+ end
+
+ def self._obj2soap(obj, registry, type = nil)
+ if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__]
+ soap_obj = SOAPReference.new
+ soap_obj.__setobj__(referent)
+ soap_obj
+ else
+ registry.obj2soap(obj.class, obj, type)
+ end
+ end
+
+ def self._soap2obj(node, registry)
+ if node.is_a?(SOAPReference)
+ target = node.__getobj__
+ # target.id is not Object#id but SOAPReference#id
+ if referent = Thread.current[:SOAPMarshalDataKey][target.id]
+ return referent
+ else
+ return _soap2obj(target, registry)
+ end
+ end
+ return registry.soap2obj(node.class, node)
+ end
+
+
+ # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
+ # Caution: '.' is not allowed here.
+ # To follow XML spec., it should be NCName.
+ # (denied chars) => .[0-F][0-F]
+ # ex. a.b => a.2eb
+ #
+ def self.name2elename(name)
+ name.gsub(/([^a-zA-Z0-9:_\-]+)/n) {
+ '.' << $1.unpack('H2' * $1.size).join('.')
+ }.gsub(/::/n, '..')
+ end
+
+ def self.elename2name(name)
+ name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) {
+ [$1.delete('.')].pack('H*')
+ }
+ end
+
+ def self.class_from_name(name)
+ if /^[A-Z]/ !~ name
+ return nil
+ end
+ klass = ::Object
+ name.split('::').each do |klass_str|
+ if klass.const_defined?(klass_str)
+ klass = klass.const_get(klass_str)
+ else
+ return nil
+ end
+ end
+ klass
+ end
+
+ def self.class2qname(klass)
+ name = if klass.class_variables.include?("@@schema_type")
+ klass.class_eval("@@schema_type")
+ else
+ nil
+ end
+ namespace = if klass.class_variables.include?("@@schema_ns")
+ klass.class_eval("@@schema_ns")
+ else
+ nil
+ end
+ XSD::QName.new(namespace, name)
+ end
+
+ def self.class2element(klass)
+ type = Mapping.class2qname(klass)
+ type.name ||= Mapping.name2elename(klass.name)
+ type.namespace ||= RubyCustomTypeNamespace
+ type
+ end
+
+ def self.obj2element(obj)
+ name = namespace = nil
+ ivars = obj.instance_variables
+ if ivars.include?("@schema_type")
+ name = obj.instance_eval("@schema_type")
+ end
+ if ivars.include?("@schema_ns")
+ namespace = obj.instance_eval("@schema_ns")
+ end
+ if !name or !namespace
+ class2qname(obj.class)
+ else
+ XSD::QName.new(namespace, name)
+ end
+ end
+
+ class << Mapping
+ private
+ def add_md_ary(md_ary, ary, indices, registry)
+ for idx in 0..(ary.size - 1)
+ if ary[idx].is_a?(Array)
+ add_md_ary(md_ary, ary[idx], indices + [idx], registry)
+ else
+ md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry)
+ end
+ end
+ end
+ end
+end
+
+
+end
diff --git a/lib/soap/mapping/registry.rb b/lib/soap/mapping/registry.rb
new file mode 100644
index 0000000000..568f34ac3e
--- /dev/null
+++ b/lib/soap/mapping/registry.rb
@@ -0,0 +1,408 @@
+=begin
+SOAP4R - Mapping registry.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/baseData'
+require 'soap/mapping/mapping'
+require 'soap/mapping/typeMap'
+require 'soap/mapping/factory'
+require 'soap/mapping/rubytypeFactory'
+
+
+module SOAP
+
+
+module Marshallable
+ # @@type_ns = Mapping::RubyCustomTypeNamespace
+end
+
+
+module Mapping
+
+
+module MappedException; end
+
+
+RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
+
+
+# Inner class to pass an exception.
+class SOAPException; include Marshallable
+ attr_reader :excn_type_name, :message, :backtrace, :cause
+ def initialize(e)
+ @excn_type_name = Mapping.name2elename(e.class.to_s)
+ @message = e.message
+ @backtrace = e.backtrace
+ @cause = e
+ end
+
+ def to_e
+ if @cause.is_a?(::Exception)
+ @cause.extend(::SOAP::Mapping::MappedException)
+ return @cause
+ end
+ klass = Mapping.class_from_name(
+ Mapping.elename2name(@excn_type_name.to_s))
+ if klass.nil?
+ raise RuntimeError.new(@message)
+ end
+ unless klass <= ::Exception
+ raise NameError.new
+ end
+ obj = klass.new(@message)
+ obj.extend(::SOAP::Mapping::MappedException)
+ obj
+ end
+
+ def set_backtrace(e)
+ e.set_backtrace(
+ if @backtrace.is_a?(Array)
+ @backtrace
+ else
+ [@backtrace.inspect]
+ end
+ )
+ end
+end
+
+
+# For anyType object: SOAP::Mapping::Object not ::Object
+class Object; include Marshallable
+ def set_property(name, value)
+ var_name = name
+ begin
+ instance_eval <<-EOS
+ def #{ var_name }
+ @#{ var_name }
+ end
+
+ def #{ var_name }=(value)
+ @#{ var_name } = value
+ end
+ EOS
+ self.send(var_name + '=', value)
+ rescue SyntaxError
+ var_name = safe_name(var_name)
+ retry
+ end
+
+ var_name
+ end
+
+ def members
+ instance_variables.collect { |str| str[1..-1] }
+ end
+
+ def [](name)
+ if self.respond_to?(name)
+ self.send(name)
+ else
+ self.send(safe_name(name))
+ end
+ end
+
+ def []=(name, value)
+ if self.respond_to?(name)
+ self.send(name + '=', value)
+ else
+ self.send(safe_name(name) + '=', value)
+ end
+ end
+
+private
+
+ def safe_name(name)
+ require 'md5'
+ "var_" << MD5.new(name).hexdigest
+ end
+end
+
+
+class MappingError < Error; end
+
+
+class Registry
+ class Map
+ def initialize(registry)
+ @map = []
+ @registry = registry
+ end
+
+ def obj2soap(klass, obj)
+ @map.each do |obj_class, soap_class, factory, info|
+ if klass == obj_class or
+ (info[:derived_class] and klass <= obj_class)
+ ret = factory.obj2soap(soap_class, obj, info, @registry)
+ return ret if ret
+ end
+ end
+ nil
+ end
+
+ def soap2obj(klass, node)
+ @map.each do |obj_class, soap_class, factory, info|
+ if klass == soap_class or
+ (info[:derived_class] and klass <= soap_class)
+ conv, obj = factory.soap2obj(obj_class, node, info, @registry)
+ return true, obj if conv
+ end
+ end
+ return false
+ end
+
+ # Give priority to former entry.
+ def init(init_map = [])
+ clear
+ init_map.reverse_each do |obj_class, soap_class, factory, info|
+ add(obj_class, soap_class, factory, info)
+ end
+ end
+
+ # Give priority to latter entry.
+ def add(obj_class, soap_class, factory, info)
+ info ||= {}
+ @map.unshift([obj_class, soap_class, factory, info])
+ end
+
+ def clear
+ @map.clear
+ end
+
+ def find_mapped_soap_class(target_obj_class)
+ @map.each do |obj_class, soap_class, factory, info|
+ if obj_class == target_obj_class
+ return soap_class
+ end
+ end
+ nil
+ end
+
+ def find_mapped_obj_class(target_soap_class)
+ @map.each do |obj_class, soap_class, factory, info|
+ if soap_class == target_soap_class
+ return obj_class
+ end
+ end
+ nil
+ end
+ end
+
+ StringFactory = StringFactory_.new
+ BasetypeFactory = BasetypeFactory_.new
+ DateTimeFactory = DateTimeFactory_.new
+ ArrayFactory = ArrayFactory_.new
+ Base64Factory = Base64Factory_.new
+ TypedArrayFactory = TypedArrayFactory_.new
+ TypedStructFactory = TypedStructFactory_.new
+
+ HashFactory = HashFactory_.new
+
+ SOAPBaseMap = [
+ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
+ [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::String, ::SOAP::SOAPString, StringFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDate, BasetypeFactory],
+ [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
+ {:derived_class => true}],
+ [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
+ {:derived_class => true}],
+ [::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
+ {:derived_class => true}],
+ [::String, ::SOAP::SOAPBase64, Base64Factory],
+ [::String, ::SOAP::SOAPHexBinary, Base64Factory],
+ [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
+ [::String, ::SOAP::SOAPDuration, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYear, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPQName, BasetypeFactory],
+
+ [::Array, ::SOAP::SOAPArray, ArrayFactory,
+ {:derived_class => true}],
+
+ [::Hash, ::SOAP::SOAPStruct, HashFactory],
+ [::SOAP::Mapping::SOAPException,
+ ::SOAP::SOAPStruct, TypedStructFactory,
+ {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
+ ]
+
+ RubyOriginalMap = [
+ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
+ [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
+ [::String, ::SOAP::SOAPString, StringFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Date, ::SOAP::SOAPDate, BasetypeFactory],
+ [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
+ [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::Float, ::SOAP::SOAPDouble, BasetypeFactory,
+ {:derived_class => true}],
+ [::Float, ::SOAP::SOAPFloat, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInt, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPLong, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
+ {:derived_class => true}],
+ [::Integer, ::SOAP::SOAPShort, BasetypeFactory,
+ {:derived_class => true}],
+ [::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
+ {:derived_class => true}],
+ [::String, ::SOAP::SOAPBase64, Base64Factory],
+ [::String, ::SOAP::SOAPHexBinary, Base64Factory],
+ [::String, ::SOAP::SOAPDecimal, BasetypeFactory],
+ [::String, ::SOAP::SOAPDuration, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPGYear, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGDay, BasetypeFactory],
+ [::String, ::SOAP::SOAPGMonth, BasetypeFactory],
+ [::String, ::SOAP::SOAPQName, BasetypeFactory],
+
+ # Does not allow Array's subclass here.
+ [::Array, ::SOAP::SOAPArray, ArrayFactory],
+
+ [::Hash, ::SOAP::SOAPStruct, HashFactory],
+ [::SOAP::Mapping::SOAPException,
+ ::SOAP::SOAPStruct, TypedStructFactory,
+ {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
+ ]
+
+ def initialize(config = {})
+ @config = config
+ @map = Map.new(self)
+ if @config[:allow_original_mapping]
+ allow_original_mapping = true
+ @map.init(RubyOriginalMap)
+ else
+ allow_original_mapping = false
+ @map.init(SOAPBaseMap)
+ end
+
+ allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
+ @config[:allow_untyped_struct] : true
+ @rubytype_factory = RubytypeFactory.new(
+ :allow_untyped_struct => allow_untyped_struct,
+ :allow_original_mapping => allow_original_mapping
+ )
+ @default_factory = @rubytype_factory
+ @excn_handler_obj2soap = nil
+ @excn_handler_soap2obj = nil
+ end
+
+ def add(obj_class, soap_class, factory, info = nil)
+ @map.add(obj_class, soap_class, factory, info)
+ end
+ alias :set :add
+
+ # This mapping registry ignores type hint.
+ def obj2soap(klass, obj, type = nil)
+ ret = nil
+ if obj.is_a?(SOAPStruct) || obj.is_a?(SOAPArray)
+ obj.replace do |ele|
+ Mapping._obj2soap(ele, self)
+ end
+ return obj
+ elsif obj.is_a?(SOAPBasetype)
+ return obj
+ end
+ begin
+ ret = @map.obj2soap(klass, obj) ||
+ @default_factory.obj2soap(klass, obj, nil, self)
+ rescue MappingError
+ end
+ return ret if ret
+
+ if @excn_handler_obj2soap
+ ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
+ Mapping._obj2soap(yield_obj, self)
+ }
+ end
+ return ret if ret
+
+ raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
+ end
+
+ def soap2obj(klass, node)
+ if node.extraattr.key?(RubyTypeName)
+ conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
+ return obj if conv
+ else
+ conv, obj = @map.soap2obj(klass, node)
+ return obj if conv
+ conv, obj = @default_factory.soap2obj(klass, node, nil, self)
+ return obj if conv
+ end
+
+ if @excn_handler_soap2obj
+ begin
+ return @excn_handler_soap2obj.call(node) { |yield_node|
+ Mapping._soap2obj(yield_node, self)
+ }
+ rescue Exception
+ end
+ end
+
+ raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
+ end
+
+ def default_factory=(factory)
+ @default_factory = factory
+ end
+
+ def excn_handler_obj2soap=(handler)
+ @excn_handler_obj2soap = handler
+ end
+
+ def excn_handler_soap2obj=(handler)
+ @excn_handler_soap2obj = handler
+ end
+
+ def find_mapped_soap_class(obj_class)
+ @map.find_mapped_soap_class(obj_class)
+ end
+
+ def find_mapped_obj_class(soap_class)
+ @map.find_mapped_obj_class(soap_class)
+ end
+end
+
+
+DefaultRegistry = Registry.new
+RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
+
+
+end
+end
diff --git a/lib/soap/mapping/rubytypeFactory.rb b/lib/soap/mapping/rubytypeFactory.rb
new file mode 100644
index 0000000000..0a3f502dfe
--- /dev/null
+++ b/lib/soap/mapping/rubytypeFactory.rb
@@ -0,0 +1,437 @@
+=begin
+SOAP4R - Ruby type mapping factory.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+module Mapping
+
+
+class RubytypeFactory < Factory
+ TYPE_STRING = 'String'
+ TYPE_ARRAY = 'Array'
+ TYPE_REGEXP = 'Regexp'
+ TYPE_RANGE = 'Range'
+ TYPE_CLASS = 'Class'
+ TYPE_MODULE = 'Module'
+ TYPE_SYMBOL = 'Symbol'
+ TYPE_STRUCT = 'Struct'
+ TYPE_HASH = 'Map'
+
+ def initialize(config = {})
+ @config = config
+ @allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
+ @config[:allow_untyped_struct] : true
+ @allow_original_mapping = @config.key?(:allow_original_mapping) ?
+ @config[:allow_original_mapping] : false
+ end
+
+ def obj2soap(soap_class, obj, info, map)
+ param = nil
+ case obj
+ when String
+ unless @allow_original_mapping
+ return nil
+ end
+ unless XSD::Charset.is_ces(obj, $KCODE)
+ return nil
+ end
+ encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRING))
+ mark_marshalled_obj(obj, param)
+ param.add('string', SOAPString.new(encoded))
+ if obj.class != String
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ addiv2soap(param, obj, map)
+ when Array
+ unless @allow_original_mapping
+ return nil
+ end
+ arytype = Mapping.obj2element(obj)
+ if arytype.name
+ arytype.namespace ||= RubyTypeNamespace
+ else
+ arytype = XSD::AnyTypeName
+ end
+ if obj.instance_variables.empty?
+ param = SOAPArray.new(ValueArrayName, 1, arytype)
+ mark_marshalled_obj(obj, param)
+ obj.each do |var|
+ param.add(Mapping._obj2soap(var, map))
+ end
+ else
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_ARRAY))
+ mark_marshalled_obj(obj, param)
+ ary = SOAPArray.new(ValueArrayName, 1, arytype)
+ obj.each do |var|
+ ary.add(Mapping._obj2soap(var, map))
+ end
+ param.add('array', ary)
+ addiv2soap(param, obj, map)
+ end
+ if obj.class != Array
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ when Regexp
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_REGEXP))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Regexp
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ param.add('source', SOAPBase64.new(obj.source))
+ if obj.respond_to?('options')
+ # Regexp#options is from Ruby/1.7
+ options = obj.options
+ else
+ options = 0
+ obj.inspect.sub(/^.*\//, '').each_byte do |c|
+ options += case c
+ when ?i
+ 1
+ when ?x
+ 2
+ when ?m
+ 4
+ when ?n
+ 16
+ when ?e
+ 32
+ when ?s
+ 48
+ when ?u
+ 64
+ end
+ end
+ end
+ param.add('options', SOAPInt.new(options))
+ addiv2soap(param, obj, map)
+ when Range
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_RANGE))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Range
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ param.add('begin', Mapping._obj2soap(obj.begin, map))
+ param.add('end', Mapping._obj2soap(obj.end, map))
+ param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?))
+ addiv2soap(param, obj, map)
+ when Hash
+ unless @allow_original_mapping
+ return nil
+ end
+ if obj.respond_to?(:default_proc) && obj.default_proc
+ raise TypeError.new("cannot dump hash with default proc")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_HASH))
+ mark_marshalled_obj(obj, param)
+ if obj.class != Hash
+ param.extraattr[RubyTypeName] = obj.class.name
+ end
+ obj.each do |key, value|
+ elem = SOAPStruct.new # Undefined type.
+ elem.add("key", Mapping._obj2soap(key, map))
+ elem.add("value", Mapping._obj2soap(value, map))
+ param.add("item", elem)
+ end
+ param.add('default', Mapping._obj2soap(obj.default, map))
+ addiv2soap(param, obj, map)
+ when Class
+ if obj.name.empty?
+ raise TypeError.new("Can't dump anonymous class #{ obj }.")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_CLASS))
+ mark_marshalled_obj(obj, param)
+ param.add('name', SOAPString.new(obj.name))
+ addiv2soap(param, obj, map)
+ when Module
+ if obj.name.empty?
+ raise TypeError.new("Can't dump anonymous module #{ obj }.")
+ end
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_MODULE))
+ mark_marshalled_obj(obj, param)
+ param.add('name', SOAPString.new(obj.name))
+ addiv2soap(param, obj, map)
+ when Symbol
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_SYMBOL))
+ mark_marshalled_obj(obj, param)
+ param.add('id', SOAPString.new(obj.id2name))
+ addiv2soap(param, obj, map)
+ when Exception
+ typestr = Mapping.name2elename(obj.class.to_s)
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
+ mark_marshalled_obj(obj, param)
+ param.add('message', Mapping._obj2soap(obj.message, map))
+ param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
+ addiv2soap(param, obj, map)
+ when Struct
+ param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRUCT))
+ mark_marshalled_obj(obj, param)
+ param.add('type', ele_type = SOAPString.new(obj.class.to_s))
+ ele_member = SOAPStruct.new
+ obj.members.each do |member|
+ ele_member.add(Mapping.name2elename(member),
+ Mapping._obj2soap(obj[member], map))
+ end
+ param.add('member', ele_member)
+ addiv2soap(param, obj, map)
+ when IO, Binding, Continuation, Data, Dir, File::Stat, MatchData, Method,
+ Proc, Thread, ThreadGroup
+ return nil
+ when ::SOAP::Mapping::Object
+ param = SOAPStruct.new(XSD::AnyTypeName)
+ mark_marshalled_obj(obj, param)
+ setiv2soap(param, obj, map) # addiv2soap?
+ else
+ if obj.class.name.empty?
+ raise TypeError.new("Can't dump anonymous class #{ obj }.")
+ end
+ if check_singleton(obj)
+ raise TypeError.new("singleton can't be dumped #{ obj }")
+ end
+ type = Mapping.class2element(obj.class)
+ param = SOAPStruct.new(type)
+ mark_marshalled_obj(obj, param)
+ if obj.class <= Marshallable
+ setiv2soap(param, obj, map)
+ else
+ setiv2soap(param, obj, map) # Should not be marshalled?
+ end
+ end
+ param
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ rubytype = node.extraattr[RubyTypeName]
+ if rubytype or node.type.namespace == RubyTypeNamespace
+ rubytype2obj(node, map, rubytype)
+ elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
+ anytype2obj(node, map)
+ else
+ unknowntype2obj(node, map)
+ end
+ end
+
+private
+
+ def check_singleton(obj)
+ unless singleton_methods_true(obj).empty?
+ return true
+ end
+ singleton_class = class << obj; self; end
+ if !singleton_class.instance_variables.empty? or
+ !(singleton_class.ancestors - obj.class.ancestors).empty?
+ return true
+ end
+ false
+ end
+
+ if RUBY_VERSION >= '1.8.0'
+ def singleton_methods_true(obj)
+ obj.singleton_methods(true)
+ end
+ else
+ def singleton_methods_true(obj)
+ obj.singleton_methods
+ end
+ end
+
+ def rubytype2obj(node, map, rubytype)
+ obj = nil
+ case node.class
+ when SOAPString
+ obj = string2obj(node, map, rubytype)
+ obj.replace(node.data)
+ return true, obj
+ when SOAPArray
+ obj = array2obj(node, map, rubytype)
+ node.soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ return true, obj
+ end
+
+ case node.type.name
+ when TYPE_STRING
+ obj = string2obj(node, map, rubytype)
+ obj.replace(node['string'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_ARRAY
+ obj = array2obj(node, map, rubytype)
+ node['array'].soap2array(obj) do |elem|
+ elem ? Mapping._soap2obj(elem, map) : nil
+ end
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_REGEXP
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ source = node['source'].string
+ options = node['options'].data || 0
+ obj.instance_eval { initialize(source, options) }
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_RANGE
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Range
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ first = Mapping._soap2obj(node['begin'], map)
+ last = Mapping._soap2obj(node['end'], map)
+ exclude_end = node['exclude_end'].data
+ obj.instance_eval { initialize(first, last, exclude_end) }
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_HASH
+ unless @allow_original_mapping
+ return false
+ end
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ node.each do |key, value|
+ next unless key == 'item'
+ obj[Mapping._soap2obj(value['key'], map)] =
+ Mapping._soap2obj(value['value'], map)
+ end
+ if node.key?('default')
+ obj.default = Mapping._soap2obj(node['default'], map)
+ end
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_CLASS
+ obj = Mapping.class_from_name(node['name'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_MODULE
+ obj = Mapping.class_from_name(node['name'].data)
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_SYMBOL
+ obj = node['id'].data.intern
+ setiv2obj(obj, node['ivars'], map)
+ when TYPE_STRUCT
+ typestr = Mapping.elename2name(node['type'].data)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ klass = Mapping.class_from_name(name2typename(typestr))
+ end
+ if klass.nil?
+ return false
+ end
+ unless klass <= ::Struct
+ return false
+ end
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ node['member'].each do |name, value|
+ obj[Mapping.elename2name(name)] =
+ Mapping._soap2obj(value, map)
+ end
+ setiv2obj(obj, node['ivars'], map)
+ else
+ conv, obj = exception2obj(node, map)
+ unless conv
+ return false
+ end
+ setiv2obj(obj, node['ivars'], map)
+ end
+ return true, obj
+ end
+
+ def exception2obj(node, map)
+ typestr = Mapping.elename2name(node.type.name)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ return false
+ end
+ unless klass <= Exception
+ return false
+ end
+ message = Mapping._soap2obj(node['message'], map)
+ backtrace = Mapping._soap2obj(node['backtrace'], map)
+ obj = create_empty_object(klass)
+ obj = obj.exception(message)
+ mark_unmarshalled_obj(node, obj)
+ obj.set_backtrace(backtrace)
+ setiv2obj(obj, node['ivars'], map)
+ return true, obj
+ end
+
+ def anytype2obj(node, map)
+ case node
+ when SOAPBasetype
+ return true, node.data
+ when SOAPStruct
+ klass = ::SOAP::Mapping::Object
+ obj = klass.new
+ mark_unmarshalled_obj(node, obj)
+ node.each do |name, value|
+ obj.set_property(name, Mapping._soap2obj(value, map))
+ end
+ return true, obj
+ else
+ return false
+ end
+ end
+
+ def unknowntype2obj(node, map)
+ if node.is_a?(SOAPStruct)
+ obj = struct2obj(node, map)
+ return true, obj if obj
+ if !@allow_untyped_struct
+ return false
+ end
+ return anytype2obj(node, map)
+ else
+ # Basetype which is not defined...
+ return false
+ end
+ end
+
+ def struct2obj(node, map)
+ obj = nil
+ typestr = Mapping.elename2name(node.type.name)
+ klass = Mapping.class_from_name(typestr)
+ if klass.nil?
+ klass = Mapping.class_from_name(name2typename(typestr))
+ end
+ if klass.nil?
+ return nil
+ end
+ klass_type = Mapping.class2qname(klass)
+ return nil unless node.type.match(klass_type)
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ setiv2obj(obj, node, map)
+ obj
+ end
+
+ # Only creates empty array. Do String#replace it with real string.
+ def array2obj(node, map, rubytype)
+ klass = rubytype ? Mapping.class_from_name(rubytype) : Array
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ obj
+ end
+
+ # Only creates empty string. Do String#replace it with real string.
+ def string2obj(node, map, rubytype)
+ klass = rubytype ? Mapping.class_from_name(rubytype) : String
+ obj = create_empty_object(klass)
+ mark_unmarshalled_obj(node, obj)
+ obj
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/mapping/typeMap.rb b/lib/soap/mapping/typeMap.rb
new file mode 100644
index 0000000000..c62f1482c1
--- /dev/null
+++ b/lib/soap/mapping/typeMap.rb
@@ -0,0 +1,52 @@
+=begin
+SOAP4R - Base type mapping definition
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+
+
+TypeMap = {
+ XSD::XSDAnySimpleType::Type => SOAPAnySimpleType,
+ XSD::XSDString::Type => SOAPString,
+ XSD::XSDBoolean::Type => SOAPBoolean,
+ XSD::XSDDecimal::Type => SOAPDecimal,
+ XSD::XSDFloat::Type => SOAPFloat,
+ XSD::XSDDouble::Type => SOAPDouble,
+ XSD::XSDDuration::Type => SOAPDuration,
+ XSD::XSDDateTime::Type => SOAPDateTime,
+ XSD::XSDTime::Type => SOAPTime,
+ XSD::XSDDate::Type => SOAPDate,
+ XSD::XSDGYearMonth::Type => SOAPGYearMonth,
+ XSD::XSDGYear::Type => SOAPGYear,
+ XSD::XSDGMonthDay::Type => SOAPGMonthDay,
+ XSD::XSDGDay::Type => SOAPGDay,
+ XSD::XSDGMonth::Type => SOAPGMonth,
+ XSD::XSDHexBinary::Type => SOAPHexBinary,
+ XSD::XSDBase64Binary::Type => SOAPBase64,
+ XSD::XSDAnyURI::Type => SOAPAnyURI,
+ XSD::XSDQName::Type => SOAPQName,
+ XSD::XSDInteger::Type => SOAPInteger,
+ XSD::XSDLong::Type => SOAPLong,
+ XSD::XSDInt::Type => SOAPInt,
+ XSD::XSDShort::Type => SOAPShort,
+
+ SOAP::SOAPBase64::Type => SOAPBase64,
+}
+
+
+end
diff --git a/lib/soap/mapping/wsdlRegistry.rb b/lib/soap/mapping/wsdlRegistry.rb
new file mode 100644
index 0000000000..4b5beabe72
--- /dev/null
+++ b/lib/soap/mapping/wsdlRegistry.rb
@@ -0,0 +1,146 @@
+=begin
+SOAP4R - WSDL mapping registry.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/baseData'
+require 'soap/mapping/mapping'
+require 'soap/mapping/typeMap'
+
+
+module SOAP
+module Mapping
+
+
+class WSDLRegistry
+ include TraverseSupport
+
+ attr_reader :complextypes
+
+ def initialize(complextypes, config = {})
+ @complextypes = complextypes
+ @config = config
+ @excn_handler_obj2soap = nil
+ # For mapping AnyType element.
+ @rubytype_factory = RubytypeFactory.new(
+ :allow_untyped_struct => true,
+ :allow_original_mapping => true
+ )
+ end
+
+ def obj2soap(klass, obj, type_qname)
+ soap_obj = nil
+ if obj.nil?
+ soap_obj = SOAPNil.new
+ elsif obj.is_a?(XSD::NSDBase)
+ soap_obj = soap2soap(obj, type_qname)
+ elsif (type = @complextypes[type_qname])
+ case type.compoundtype
+ when :TYPE_STRUCT
+ soap_obj = struct2soap(obj, type_qname, type)
+ when :TYPE_ARRAY
+ soap_obj = array2soap(obj, type_qname, type)
+ end
+ elsif (type = TypeMap[type_qname])
+ soap_obj = base2soap(obj, type)
+ elsif type_qname == XSD::AnyTypeName
+ soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, nil)
+ end
+ return soap_obj if soap_obj
+
+ if @excn_handler_obj2soap
+ soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
+ Mapping._obj2soap(yield_obj, self)
+ }
+ end
+ return soap_obj if soap_obj
+
+ raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
+ end
+
+ def soap2obj(klass, node)
+ raise RuntimeError.new("#{ self } is for obj2soap only.")
+ end
+
+ def excn_handler_obj2soap=(handler)
+ @excn_handler_obj2soap = handler
+ end
+
+private
+
+ def soap2soap(obj, type_qname)
+ if obj.is_a?(SOAPBasetype)
+ obj
+ elsif obj.is_a?(SOAPStruct) && (type = @complextypes[type_qname])
+ soap_obj = obj
+ mark_marshalled_obj(obj, soap_obj)
+ elements2soap(obj, soap_obj, type.content.elements)
+ soap_obj
+ elsif obj.is_a?(SOAPArray) && (type = @complextypes[type_qname])
+ soap_obj = obj
+ contenttype = type.child_type
+ mark_marshalled_obj(obj, soap_obj)
+ obj.replace do |ele|
+ Mapping._obj2soap(ele, self, contenttype)
+ end
+ soap_obj
+ else
+ nil
+ end
+ end
+
+ def base2soap(obj, type)
+ soap_obj = nil
+ if type <= XSD::XSDString
+ soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ?
+ XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj)
+ mark_marshalled_obj(obj, soap_obj)
+ else
+ soap_obj = type.new(obj)
+ end
+ soap_obj
+ end
+
+ def struct2soap(obj, type_qname, type)
+ soap_obj = SOAPStruct.new(type_qname)
+ mark_marshalled_obj(obj, soap_obj)
+ elements2soap(obj, soap_obj, type.content.elements)
+ soap_obj
+ end
+
+ def array2soap(obj, type_qname, type)
+ contenttype = type.child_type
+ soap_obj = SOAPArray.new(ValueArrayName, 1, contenttype)
+ mark_marshalled_obj(obj, soap_obj)
+ obj.each do |item|
+ soap_obj.add(Mapping._obj2soap(item, self, contenttype))
+ end
+ soap_obj
+ end
+
+ def elements2soap(obj, soap_obj, elements)
+ elements.each do |element|
+ name = element.name.name
+ child_obj = obj.instance_eval("@#{ name }")
+ soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type))
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/marshal.rb b/lib/soap/marshal.rb
new file mode 100644
index 0000000000..1dc4e13558
--- /dev/null
+++ b/lib/soap/marshal.rb
@@ -0,0 +1,71 @@
+=begin
+SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding.
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+# The original version of the marshal.rb to marshal/unmarshal Ruby's object
+# using SOAP Encoding was written by Michael Neumann. His valuable comments
+# and his program inspired me to write this. Thanks.
+
+
+require "soap/mapping"
+require "soap/processor"
+
+
+module SOAP
+
+
+module Marshal
+ # Trying xsd:dateTime data to be recovered as aTime. aDateTime if it fails.
+ MarshalMappingRegistry = Mapping::Registry.new(:allow_original_mapping => true)
+ MarshalMappingRegistry.add(
+ Time,
+ ::SOAP::SOAPDateTime,
+ ::SOAP::Mapping::Registry::DateTimeFactory
+)
+
+ class << self
+ public
+ def dump(obj, io = nil)
+ marshal(obj, MarshalMappingRegistry, io)
+ end
+
+ def load(stream)
+ unmarshal(stream, MarshalMappingRegistry)
+ end
+
+ def marshal(obj, mapping_registry = MarshalMappingRegistry, io = nil)
+ elename = Mapping.name2elename(obj.class.to_s)
+ soap_obj = Mapping.obj2soap(obj, mapping_registry)
+ body = SOAPBody.new
+ body.add(elename, soap_obj)
+ SOAP::Processor.marshal(nil, body, {}, io)
+ end
+
+ def unmarshal(stream, mapping_registry = MarshalMappingRegistry)
+ header, body = SOAP::Processor.unmarshal(stream)
+ Mapping.soap2obj(body.root_node, mapping_registry)
+ end
+ end
+
+end
+
+
+end
+
+
+SOAPMarshal = SOAP::Marshal
diff --git a/lib/soap/netHttpClient.rb b/lib/soap/netHttpClient.rb
new file mode 100644
index 0000000000..14003b34d0
--- /dev/null
+++ b/lib/soap/netHttpClient.rb
@@ -0,0 +1,101 @@
+=begin
+SOAP4R - net/http wrapper
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'net/http'
+
+
+module SOAP
+
+
+class NetHttpClient
+
+ attr_accessor :proxy
+ attr_accessor :debug_dev
+ attr_reader :session_manager
+
+ class SessionManager
+ attr_accessor :connect_timeout
+ attr_accessor :send_timeout
+ attr_accessor :receive_timeout
+ end
+
+ class Response
+ attr_reader :content
+ attr_reader :status
+ attr_reader :reason
+ attr_reader :contenttype
+
+ def initialize(res)
+ @status = res.code.to_i
+ @reason = res.message
+ @contenttype = res['content-type']
+ @content = res.body
+ end
+ end
+
+ def initialize(proxy = nil, agent = nil)
+ @proxy = proxy ? URI.parse(proxy) : nil
+ @agent = agent
+ @debug_dev = nil
+ @session_manager = SessionManager.new
+ end
+
+ def reset(url)
+ # ignored.
+ end
+
+ def post(url, req_body, header = {})
+ url = URI.parse(url)
+ extra = header.dup
+ extra['User-Agent'] = @agent if @agent
+ res = start(url) { |http|
+ http.post(url.instance_eval('path_query'), req_body, extra)
+ }
+ Response.new(res)
+ end
+
+ def get_content(url, header = {})
+ url = URI.parse(url)
+ extra = header.dup
+ extra['User-Agent'] = @agent if @agent
+ res = start(url) { |http|
+ http.get(url.instance_eval('path_query'), extra)
+ }
+ res.body
+ end
+
+private
+
+ def start(url)
+ proxy_host = @proxy ? @proxy.host : nil
+ proxy_port = @proxy ? @proxy.port : nil
+ response = nil
+ Net::HTTP::Proxy(proxy_host, proxy_port).start(url.host, url.port) { |http|
+ if http.respond_to?(:set_debug_output)
+ http.set_debug_output(@debug_dev)
+ end
+ response, = yield(http)
+ http.finish
+ }
+ response
+ end
+end
+
+
+end
diff --git a/lib/soap/parser.rb b/lib/soap/parser.rb
new file mode 100644
index 0000000000..67782566c3
--- /dev/null
+++ b/lib/soap/parser.rb
@@ -0,0 +1,252 @@
+=begin
+SOAP4R - SOAP XML Instance Parser library.
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/ns'
+require 'xsd/xmlparser'
+require 'soap/soap'
+require 'soap/baseData'
+require 'soap/encodingstyle/handler'
+
+
+module SOAP
+
+
+class Parser
+ include SOAP
+
+ class ParseError < Error; end
+ class FormatDecodeError < ParseError; end
+ class UnexpectedElementError < ParseError; end
+
+private
+
+ class ParseFrame
+ attr_reader :node
+ attr_reader :name
+ attr_reader :ns, :encodingstyle
+
+ class NodeContainer
+ def initialize(node)
+ @node = node
+ end
+
+ def node
+ @node
+ end
+
+ def replace_node(node)
+ @node = node
+ end
+ end
+
+ public
+
+ def initialize(ns, name, node, encodingstyle)
+ @ns = ns
+ @name = name
+ self.node = node
+ @encodingstyle = encodingstyle
+ end
+
+ def node=(node)
+ @node = NodeContainer.new(node)
+ end
+ end
+
+public
+
+ attr_accessor :default_encodingstyle
+ attr_accessor :decode_typemap
+ attr_accessor :allow_unqualified_element
+
+ def initialize(opt = {})
+ @parser = XSD::XMLParser.create_parser(self, opt)
+ @parsestack = nil
+ @lastnode = nil
+ @handlers = {}
+ @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
+ @decode_typemap = opt[:decode_typemap] || nil
+ @allow_unqualified_element = opt[:allow_unqualified_element] || false
+ end
+
+ def charset
+ @parser.charset
+ end
+
+ def parse(string_or_readable)
+ @parsestack = []
+ @lastnode = nil
+
+ @handlers.each do |uri, handler|
+ handler.decode_prologue
+ end
+
+ @parser.do_parse(string_or_readable)
+
+ unless @parsestack.empty?
+ raise FormatDecodeError.new("Unbalanced tag in XML.")
+ end
+
+ @handlers.each do |uri, handler|
+ handler.decode_epilogue
+ end
+
+ @lastnode
+ end
+
+ def start_element(name, attrs)
+ lastframe = @parsestack.last
+ ns = parent = parent_encodingstyle = nil
+ if lastframe
+ ns = lastframe.ns.clone_ns
+ parent = lastframe.node
+ parent_encodingstyle = lastframe.encodingstyle
+ else
+ ns = XSD::NS.new
+ parent = ParseFrame::NodeContainer.new(nil)
+ parent_encodingstyle = nil
+ end
+
+ attrs = XSD::XMLParser.filter_ns(ns, attrs)
+ encodingstyle = find_encodingstyle(ns, attrs)
+
+ # Children's encodingstyle is derived from its parent.
+ encodingstyle ||= parent_encodingstyle || @default_encodingstyle
+
+ node = decode_tag(ns, name, attrs, parent, encodingstyle)
+
+ @parsestack << ParseFrame.new(ns, name, node, encodingstyle)
+ end
+
+ def characters(text)
+ lastframe = @parsestack.last
+ if lastframe
+ # Need not to be cloned because character does not have attr.
+ ns = lastframe.ns
+ parent = lastframe.node
+ encodingstyle = lastframe.encodingstyle
+ decode_text(ns, text, encodingstyle)
+ else
+ # Ignore Text outside of SOAP Envelope.
+ p text if $DEBUG
+ end
+ end
+
+ def end_element(name)
+ lastframe = @parsestack.pop
+ unless name == lastframe.name
+ raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.")
+ end
+ decode_tag_end(lastframe.ns, lastframe.node, lastframe.encodingstyle)
+ @lastnode = lastframe.node.node
+ end
+
+private
+
+ def find_encodingstyle(ns, attrs)
+ attrs.each do |key, value|
+ if (ns.compare(EnvelopeNamespace, AttrEncodingStyle, key))
+ return value
+ end
+ end
+ nil
+ end
+
+ def decode_tag(ns, name, attrs, parent, encodingstyle)
+ ele = ns.parse(name)
+
+ # Envelope based parsing.
+ if ((ele.namespace == EnvelopeNamespace) ||
+ (@allow_unqualified_element && ele.namespace.nil?))
+ o = decode_soap_envelope(ns, ele, attrs, parent)
+ return o if o
+ end
+
+ # Encoding based parsing.
+ handler = find_handler(encodingstyle)
+ if handler
+ return handler.decode_tag(ns, ele, attrs, parent)
+ else
+ raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
+ end
+ end
+
+ def decode_tag_end(ns, node, encodingstyle)
+ return unless encodingstyle
+
+ handler = find_handler(encodingstyle)
+ if handler
+ return handler.decode_tag_end(ns, node)
+ else
+ raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
+ end
+ end
+
+ def decode_text(ns, text, encodingstyle)
+ handler = find_handler(encodingstyle)
+
+ if handler
+ handler.decode_text(ns, text)
+ else
+ # How should I do?
+ end
+ end
+
+ def decode_soap_envelope(ns, ele, attrs, parent)
+ o = nil
+ if ele.name == EleEnvelope
+ o = SOAPEnvelope.new
+ elsif ele.name == EleHeader
+ unless parent.node.is_a?(SOAPEnvelope)
+ raise FormatDecodeError.new("Header should be a child of Envelope.")
+ end
+ o = SOAPHeader.new
+ parent.node.header = o
+ elsif ele.name == EleBody
+ unless parent.node.is_a?(SOAPEnvelope)
+ raise FormatDecodeError.new("Body should be a child of Envelope.")
+ end
+ o = SOAPBody.new
+ parent.node.body = o
+ elsif ele.name == EleFault
+ unless parent.node.is_a?(SOAPBody)
+ raise FormatDecodeError.new("Fault should be a child of Body.")
+ end
+ o = SOAPFault.new
+ parent.node.fault = o
+ end
+ o.parent = parent if o
+ o
+ end
+
+ def find_handler(encodingstyle)
+ unless @handlers.key?(encodingstyle)
+ handler_factory = SOAP::EncodingStyle::Handler.handler(encodingstyle) ||
+ SOAP::EncodingStyle::Handler.handler(EncodingNamespace)
+ handler = handler_factory.new(@parser.charset)
+ handler.decode_typemap = @decode_typemap
+ handler.decode_prologue
+ @handlers[encodingstyle] = handler
+ end
+ @handlers[encodingstyle]
+ end
+end
+
+
+end
diff --git a/lib/soap/processor.rb b/lib/soap/processor.rb
new file mode 100644
index 0000000000..47df772a9d
--- /dev/null
+++ b/lib/soap/processor.rb
@@ -0,0 +1,79 @@
+=begin
+SOAP4R - marshal/unmarshal interface.
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/datatypes'
+require 'soap/soap'
+require 'soap/element'
+require 'soap/parser'
+require 'soap/generator'
+require 'soap/encodingstyle/soapHandler'
+require 'soap/encodingstyle/literalHandler'
+require 'soap/encodingstyle/aspDotNetHandler'
+
+
+module SOAP
+
+
+module Processor
+ @@default_parser_option = {}
+
+ class << self
+ public
+
+ def marshal(header, body, opt = {}, io = nil)
+ env = SOAPEnvelope.new(header, body)
+ generator = create_generator(opt)
+ generator.generate(env, io)
+ end
+
+ def unmarshal(stream, opt = {})
+ parser = create_parser(opt)
+ env = parser.parse(stream)
+ if env
+ return env.header, env.body
+ else
+ return nil, nil
+ end
+ end
+
+ def default_parser_option=(rhs)
+ @@default_parser_option = rhs
+ end
+
+ def default_parser_option
+ @@default_parser_option
+ end
+
+ private
+
+ def create_generator(opt)
+ SOAPGenerator.new(opt)
+ end
+
+ def create_parser(opt)
+ if opt.empty?
+ opt = @@default_parser_option
+ end
+ ::SOAP::Parser.new(opt)
+ end
+ end
+end
+
+
+end
diff --git a/lib/soap/rpc/cgistub.rb b/lib/soap/rpc/cgistub.rb
new file mode 100644
index 0000000000..f016e31057
--- /dev/null
+++ b/lib/soap/rpc/cgistub.rb
@@ -0,0 +1,214 @@
+=begin
+SOAP4R - CGI stub library
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/streamHandler'
+require 'webrick/httpresponse'
+require 'webrick/httpstatus'
+require 'logger'
+require 'soap/rpc/router'
+
+
+module SOAP
+module RPC
+
+
+###
+# SYNOPSIS
+# CGIStub.new
+#
+# DESCRIPTION
+# To be written...
+#
+class CGIStub < Logger::Application
+ include SOAP
+
+ # There is a client which does not accept the media-type which is defined in
+ # SOAP spec.
+ attr_accessor :mediatype
+
+ class CGIError < Error; end
+
+ class SOAPRequest
+ ALLOWED_LENGTH = 1024 * 1024
+
+ def initialize(stream = $stdin)
+ @method = ENV['REQUEST_METHOD']
+ @size = ENV['CONTENT_LENGTH'].to_i || 0
+ @contenttype = ENV['CONTENT_TYPE']
+ @charset = nil
+ @soapaction = ENV['HTTP_SOAPAction']
+ @source = stream
+ @body = nil
+ end
+
+ def init
+ validate
+ @charset = StreamHandler.parse_media_type(@contenttype)
+ @body = @source.read(@size)
+ self
+ end
+
+ def dump
+ @body.dup
+ end
+
+ def soapaction
+ @soapaction
+ end
+
+ def charset
+ @charset
+ end
+
+ def to_s
+ "method: #{ @method }, size: #{ @size }"
+ end
+
+ private
+
+ def validate # raise CGIError
+ if @method != 'POST'
+ raise CGIError.new("Method '#{ @method }' not allowed.")
+ end
+
+ if @size > ALLOWED_LENGTH
+ raise CGIError.new("Content-length too long.")
+ end
+ end
+ end
+
+ def initialize(appname, default_namespace)
+ super(appname)
+ set_log(STDERR)
+ self.level = INFO
+ @default_namespace = default_namespace
+ @router = SOAP::RPC::Router.new(appname)
+ @remote_user = ENV['REMOTE_USER'] || 'anonymous'
+ @remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown'
+ @request = nil
+ @response = nil
+ @mediatype = MediaType
+ on_init
+ end
+
+ def add_servant(obj, namespace = @default_namespace, soapaction = nil)
+ RPC.defined_methods(obj).each do |name|
+ qname = XSD::QName.new(namespace, name)
+ param_size = obj.method(name).arity.abs
+ params = (1..param_size).collect { |i| "p#{ i }" }
+ param_def = SOAP::RPC::SOAPMethod.create_param_def(params)
+ @router.add_method(obj, qname, soapaction, name, param_def)
+ end
+ end
+
+ def on_init
+ # Override this method in derived class to call 'add_method' to add methods.
+ end
+
+ def mapping_registry
+ @router.mapping_registry
+ end
+
+ def mapping_registry=(value)
+ @router.mapping_registry = value
+ end
+
+ def add_method(receiver, name, *param)
+ add_method_with_namespace_as(@default_namespace, receiver,
+ name, name, *param)
+ end
+
+ def add_method_as(receiver, name, name_as, *param)
+ add_method_with_namespace_as(@default_namespace, receiver,
+ name, name_as, *param)
+ end
+
+ def add_method_with_namespace(namespace, receiver, name, *param)
+ add_method_with_namespace_as(namespace, receiver, name, name, *param)
+ end
+
+ def add_method_with_namespace_as(namespace, receiver, name, name_as, *param)
+ param_def = if param.size == 1 and param[0].is_a?(Array)
+ param[0]
+ else
+ SOAP::RPC::SOAPMethod.create_param_def(param)
+ end
+ qname = XSD::QName.new(namespace, name_as)
+ @router.add_method(receiver, qname, nil, name, param_def)
+ end
+
+ def route(request_string, charset)
+ @router.route(request_string, charset)
+ end
+
+ def create_fault_response(e)
+ @router.create_fault_response(e)
+ end
+
+private
+
+ def run
+ prologue
+
+ httpversion = WEBrick::HTTPVersion.new('1.0')
+ @response = WEBrick::HTTPResponse.new({:HTTPVersion => httpversion})
+ begin
+ log(INFO) { "Received a request from '#{ @remote_user }@#{ @remote_host }'." }
+ # SOAP request parsing.
+ @request = SOAPRequest.new.init
+ req_charset = @request.charset
+ req_string = @request.dump
+ log(DEBUG) { "XML Request: #{req_string}" }
+ res_string, is_fault = route(req_string, req_charset)
+ log(DEBUG) { "XML Response: #{res_string}" }
+
+ @response['Cache-Control'] = 'private'
+ if req_charset
+ @response['content-type'] = "#{@mediatype}; charset=\"#{req_charset}\""
+ else
+ @response['content-type'] = @mediatype
+ end
+ if is_fault
+ @response.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
+ end
+ @response.body = res_string
+ rescue Exception
+ res_string = create_fault_response($!)
+ @response['Cache-Control'] = 'private'
+ @response['content-type'] = @mediatype
+ @response.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
+ ensure
+ buf = ''
+ @response.send_response(buf)
+ buf.sub!(/^[^\r]+\r\n/, '') # Trim status line.
+ log(DEBUG) { "SOAP CGI Response:\n#{ buf }" }
+ print buf
+ epilogue
+ end
+
+ 0
+ end
+
+ def prologue; end
+ def epilogue; end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/driver.rb b/lib/soap/rpc/driver.rb
new file mode 100644
index 0000000000..76fd14e34b
--- /dev/null
+++ b/lib/soap/rpc/driver.rb
@@ -0,0 +1,189 @@
+=begin
+SOAP4R - SOAP RPC driver
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/soap'
+require 'soap/mapping'
+require 'soap/rpc/rpc'
+require 'soap/rpc/proxy'
+require 'soap/rpc/element'
+require 'soap/streamHandler'
+
+
+module SOAP
+module RPC
+
+
+class Driver
+public
+ class EmptyResponseError < Error; end
+
+ attr_accessor :mapping_registry
+ attr_accessor :soapaction
+ attr_reader :endpoint_url
+ attr_reader :wiredump_dev
+ attr_reader :wiredump_file_base
+ attr_reader :httpproxy
+
+ def initialize(endpoint_url, namespace, soapaction = nil)
+ @endpoint_url = endpoint_url
+ @namespace = namespace
+ @mapping_registry = nil # for unmarshal
+ @soapaction = soapaction
+ @wiredump_dev = nil
+ @wiredump_file_base = nil
+ @httpproxy = ENV['httpproxy'] || ENV['HTTP_PROXY']
+ @handler = HTTPPostStreamHandler.new(@endpoint_url, @httpproxy,
+ XSD::Charset.encoding_label)
+ @proxy = Proxy.new(@handler, @soapaction)
+ @proxy.allow_unqualified_element = true
+ end
+
+ def endpoint_url=(endpoint_url)
+ @endpoint_url = endpoint_url
+ if @handler
+ @handler.endpoint_url = @endpoint_url
+ @handler.reset
+ end
+ end
+
+ def wiredump_dev=(dev)
+ @wiredump_dev = dev
+ if @handler
+ @handler.wiredump_dev = @wiredump_dev
+ @handler.reset
+ end
+ end
+
+ def wiredump_file_base=(base)
+ @wiredump_file_base = base
+ end
+
+ def httpproxy=(httpproxy)
+ @httpproxy = httpproxy
+ if @handler
+ @handler.proxy = @httpproxy
+ @handler.reset
+ end
+ end
+
+ def default_encodingstyle
+ @proxy.default_encodingstyle
+ end
+
+ def default_encodingstyle=(encodingstyle)
+ @proxy.default_encodingstyle = encodingstyle
+ end
+
+
+ ###
+ ## Method definition interfaces.
+ #
+ # params: [[param_def...]] or [paramname, paramname, ...]
+ # param_def: See proxy.rb. Sorry.
+
+ def add_method(name, *params)
+ add_method_with_soapaction_as(name, name, @soapaction, *params)
+ end
+
+ def add_method_as(name, name_as, *params)
+ add_method_with_soapaction_as(name, name_as, @soapaction, *params)
+ end
+
+ def add_method_with_soapaction(name, soapaction, *params)
+ add_method_with_soapaction_as(name, name, soapaction, *params)
+ end
+
+ def add_method_with_soapaction_as(name, name_as, soapaction, *params)
+ param_def = if params.size == 1 and params[0].is_a?(Array)
+ params[0]
+ else
+ SOAPMethod.create_param_def(params)
+ end
+ qname = XSD::QName.new(@namespace, name_as)
+ @proxy.add_method(qname, soapaction, name, param_def)
+ add_rpc_method_interface(name, param_def)
+ end
+
+
+ ###
+ ## Driving interface.
+ #
+ def invoke(headers, body)
+ if @wiredump_file_base
+ @handler.wiredump_file_base =
+ @wiredump_file_base + '_' << body.elename.name
+ end
+ @proxy.invoke(headers, body)
+ end
+
+ def call(name, *params)
+ # Convert parameters: params array => SOAPArray => members array
+ params = Mapping.obj2soap(params, @mapping_registry).to_a
+ if @wiredump_file_base
+ @handler.wiredump_file_base = @wiredump_file_base + '_' << name
+ end
+
+ # Then, call @proxy.call like the following.
+ header, body = @proxy.call(nil, name, *params)
+ unless body
+ raise EmptyResponseError.new("Empty response.")
+ end
+
+ begin
+ @proxy.check_fault(body)
+ rescue SOAP::FaultError => e
+ Mapping.fault2exception(e)
+ end
+
+ ret = body.response ? Mapping.soap2obj(body.response, @mapping_registry) : nil
+ if body.outparams
+ outparams = body.outparams.collect { |outparam| Mapping.soap2obj(outparam) }
+ return [ret].concat(outparams)
+ else
+ return ret
+ end
+ end
+
+ def reset_stream
+ @handler.reset
+ end
+
+private
+
+ def add_rpc_method_interface(name, param_def)
+ param_names = []
+ i = 0
+ @proxy.method[name].each_param_name(RPC::SOAPMethod::IN,
+ RPC::SOAPMethod::INOUT) do |param_name|
+ i += 1
+ param_names << "arg#{ i }"
+ end
+
+ callparam = (param_names.collect { |pname| ", " + pname }).join
+ self.instance_eval <<-EOS
+ def #{ name }(#{ param_names.join(", ") })
+ call("#{ name }"#{ callparam })
+ end
+ EOS
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/element.rb b/lib/soap/rpc/element.rb
new file mode 100644
index 0000000000..d1e1931fa3
--- /dev/null
+++ b/lib/soap/rpc/element.rb
@@ -0,0 +1,278 @@
+=begin
+SOAP4R - RPC element definition.
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/baseData'
+
+
+module SOAP
+
+# Add method definitions for RPC to common definition in element.rb
+class SOAPBody < SOAPStruct
+ public
+
+ def request
+ root_node
+ end
+
+ def response
+ if !@is_fault
+ if void?
+ nil
+ else
+ # Initial element is [retval].
+ root_node[0]
+ end
+ else
+ root_node
+ end
+ end
+
+ def outparams
+ if !@is_fault and !void?
+ op = root_node[1..-1]
+ op = nil if op && op.empty?
+ op
+ else
+ nil
+ end
+ end
+
+ def void?
+ root_node.nil? # || root_node.is_a?(SOAPNil)
+ end
+
+ def fault
+ if @is_fault
+ self['fault']
+ else
+ nil
+ end
+ end
+
+ def fault=(fault)
+ @is_fault = true
+ add_member('fault', fault)
+ end
+end
+
+
+module RPC
+
+
+class RPCError < Error; end
+class MethodDefinitionError < RPCError; end
+class ParameterError < RPCError; end
+
+class SOAPMethod < SOAPStruct
+ RETVAL = 'retval'
+ IN = 'in'
+ OUT = 'out'
+ INOUT = 'inout'
+
+ attr_reader :param_def
+ attr_reader :inparam
+ attr_reader :outparam
+
+ def initialize(qname, param_def = nil)
+ super(nil)
+ @elename = qname
+ @encodingstyle = nil
+
+ @param_def = param_def
+
+ @signature = []
+ @inparam_names = []
+ @inoutparam_names = []
+ @outparam_names = []
+
+ @inparam = {}
+ @outparam = {}
+ @retval_name = nil
+
+ init_param(@param_def) if @param_def
+ end
+
+ def have_outparam?
+ @outparam_names.size > 0
+ end
+
+ def each_param_name(*type)
+ @signature.each do |io_type, name, param_type|
+ if type.include?(io_type)
+ yield(name)
+ end
+ end
+ end
+
+ def set_param(params)
+ params.each do |param, data|
+ @inparam[param] = data
+ data.elename.name = param
+ end
+ end
+
+ def set_outparam(params)
+ params.each do |param, data|
+ @outparam[param] = data
+ data.elename.name = param
+ end
+ end
+
+ def SOAPMethod.create_param_def(param_names)
+ param_def = []
+ param_names.each do |param_name|
+ param_def.push([IN, param_name, nil])
+ end
+ param_def.push([RETVAL, 'return', nil])
+ param_def
+ end
+
+private
+
+ def init_param(param_def)
+ param_def.each do |io_type, name, param_type|
+ case io_type
+ when IN
+ @signature.push([IN, name, param_type])
+ @inparam_names.push(name)
+ when OUT
+ @signature.push([OUT, name, param_type])
+ @outparam_names.push(name)
+ when INOUT
+ @signature.push([INOUT, name, param_type])
+ @inoutparam_names.push(name)
+ when RETVAL
+ if (@retval_name)
+ raise MethodDefinitionError.new('Duplicated retval')
+ end
+ @retval_name = name
+ else
+ raise MethodDefinitionError.new("Unknown type: #{ io_type }")
+ end
+ end
+ end
+end
+
+
+class SOAPMethodRequest < SOAPMethod
+ attr_accessor :soapaction
+
+ def SOAPMethodRequest.create_request(qname, *params)
+ param_def = []
+ param_value = []
+ i = 0
+ params.each do |param|
+ param_name = "p#{ i }"
+ i += 1
+ param_def << [IN, nil, param_name]
+ param_value << [param_name, param]
+ end
+ param_def << [RETVAL, nil, 'return']
+ o = new(qname, param_def)
+ o.set_param(param_value)
+ o
+ end
+
+ def initialize(qname, param_def = nil, soapaction = nil)
+ check_elename(qname)
+ super(qname, param_def)
+ @soapaction = soapaction
+ end
+
+ def each
+ each_param_name(IN, INOUT) do |name|
+ unless @inparam[name]
+ raise ParameterError.new("Parameter: #{ name } was not given.")
+ end
+ yield(name, @inparam[name])
+ end
+ end
+
+ def dup
+ req = self.class.new(@elename.dup, @param_def, @soapaction)
+ req.encodingstyle = @encodingstyle
+ req
+ end
+
+ def create_method_response
+ SOAPMethodResponse.new(
+ XSD::QName.new(@elename.namespace, @elename.name + 'Response'),
+ @param_def)
+ end
+
+private
+
+ def check_elename(qname)
+ # NCName & ruby's method name
+ unless /\A[\w_][\w\d_\-]*\z/ =~ qname.name
+ raise MethodDefinitionError.new("Element name '#{qname.name}' not allowed")
+ end
+ end
+end
+
+
+class SOAPMethodResponse < SOAPMethod
+
+ def initialize(qname, param_def = nil)
+ super(qname, param_def)
+ @retval = nil
+ end
+
+ def retval=(retval)
+ @retval = retval
+ @retval.elename = @retval.elename.dup_name('return')
+ end
+
+ def each
+ if @retval_name and !@retval.is_a?(SOAPVoid)
+ yield(@retval_name, @retval)
+ end
+
+ each_param_name(OUT, INOUT) do |param_name|
+ unless @outparam[param_name]
+ raise ParameterError.new("Parameter: #{ param_name } was not given.")
+ end
+ yield(param_name, @outparam[param_name])
+ end
+ end
+end
+
+
+# To return(?) void explicitly.
+# def foo(input_var)
+# ...
+# return SOAP::RPC::SOAPVoid.new
+# end
+class SOAPVoid < XSD::XSDAnySimpleType
+ include SOAPBasetype
+ extend SOAPModuleUtils
+ Name = XSD::QName.new(Mapping::RubyCustomTypeNamespace, nil)
+
+public
+ def initialize()
+ @elename = Name
+ @id = nil
+ @precedents = []
+ @parent = nil
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/proxy.rb b/lib/soap/rpc/proxy.rb
new file mode 100644
index 0000000000..39a095838c
--- /dev/null
+++ b/lib/soap/rpc/proxy.rb
@@ -0,0 +1,147 @@
+=begin
+SOAP4R - RPC Proxy library.
+Copyright (C) 2000, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/soap'
+require 'soap/processor'
+require 'soap/mapping'
+require 'soap/rpc/rpc'
+require 'soap/rpc/element'
+require 'soap/streamHandler'
+
+
+module SOAP
+module RPC
+
+
+class Proxy
+ include SOAP
+
+public
+
+ attr_accessor :soapaction
+ attr_accessor :allow_unqualified_element, :default_encodingstyle
+ attr_reader :method
+
+ def initialize(stream_handler, soapaction = nil)
+ @handler = stream_handler
+ @soapaction = soapaction
+ @method = {}
+ @allow_unqualified_element = false
+ @default_encodingstyle = nil
+ end
+
+ class Request
+ include RPC
+
+ public
+
+ attr_reader :method
+ attr_reader :namespace
+ attr_reader :name
+
+ def initialize(model, values)
+ @method = model.dup
+ @namespace = @method.elename.namespace
+ @name = @method.elename.name
+
+ params = {}
+
+ if ((values.size == 1) and (values[0].is_a?(Hash)))
+ params = values[0]
+ else
+ i = 0
+ @method.each_param_name(SOAPMethod::IN, SOAPMethod::INOUT) do |name|
+ params[name] = values[i] || SOAPNil.new
+ i += 1
+ end
+ end
+ @method.set_param(params)
+ end
+ end
+
+ def add_method(qname, soapaction, name, param_def)
+ @method[name] = SOAPMethodRequest.new(qname, param_def, soapaction)
+ end
+
+ def create_request(name, *values)
+ if (@method.key?(name))
+ method = @method[name]
+ method.encodingstyle = @default_encodingstyle if @default_encodingstyle
+ else
+ raise SOAP::RPC::MethodDefinitionError.new(
+ "Method: #{ name } not defined.")
+ end
+
+ Request.new(method, values)
+ end
+
+ def invoke(req_header, req_body, soapaction = nil)
+ if req_header and !req_header.is_a?(SOAPHeader)
+ req_header = create_header(req_header)
+ end
+ if !req_body.is_a?(SOAPBody)
+ req_body = SOAPBody.new(req_body)
+ end
+ opt = create_options
+ send_string = Processor.marshal(req_header, req_body, opt)
+ data = @handler.send(send_string, soapaction)
+ if data.receive_string.empty?
+ return nil, nil
+ end
+ res_charset = StreamHandler.parse_media_type(data.receive_contenttype)
+ opt = create_options
+ opt[:charset] = res_charset
+ res_header, res_body = Processor.unmarshal(data.receive_string, opt)
+ return res_header, res_body
+ end
+
+ def call(headers, name, *values)
+ req = create_request(name, *values)
+ return invoke(headers, req.method, req.method.soapaction || @soapaction)
+ end
+
+ def check_fault(body)
+ if body.fault
+ raise SOAP::FaultError.new(body.fault)
+ end
+ end
+
+private
+
+ def create_header(headers)
+ header = SOAPHeader.new()
+ headers.each do |content, mustunderstand, encodingstyle|
+ header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle))
+ end
+ header
+ end
+
+ def create_options
+ opt = {}
+ opt[:default_encodingstyle] = @default_encodingstyle
+ if @allow_unqualified_element
+ opt[:allow_unqualified_element] = true
+ end
+ opt
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/router.rb b/lib/soap/rpc/router.rb
new file mode 100644
index 0000000000..20396a4a7d
--- /dev/null
+++ b/lib/soap/rpc/router.rb
@@ -0,0 +1,176 @@
+=begin
+SOAP4R - RPC Routing library
+Copyright (C) 2001, 2002 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/soap'
+require 'soap/processor'
+require 'soap/mapping'
+require 'soap/rpc/rpc'
+require 'soap/rpc/element'
+
+
+module SOAP
+module RPC
+
+
+class Router
+ include SOAP
+
+ attr_reader :actor
+ attr_accessor :allow_unqualified_element
+ attr_accessor :default_encodingstyle
+ attr_accessor :mapping_registry
+
+ def initialize(actor)
+ @actor = actor
+ @receiver = {}
+ @method_name = {}
+ @method = {}
+ @allow_unqualified_element = false
+ @default_encodingstyle = nil
+ @mapping_registry = nil
+ end
+
+ def add_method(receiver, qname, soapaction, name, param_def)
+ fqname = fqname(qname)
+ @receiver[fqname] = receiver
+ @method_name[fqname] = name
+ @method[fqname] = RPC::SOAPMethodRequest.new(qname, param_def, soapaction)
+ end
+
+ def add_header_handler
+ raise NotImplementedError.new
+ end
+
+ # Routing...
+ def route(soap_string, charset = nil)
+ opt = options
+ opt[:charset] = charset
+ is_fault = false
+ begin
+ header, body = Processor.unmarshal(soap_string, opt)
+ # So far, header is omitted...
+ soap_request = body.request
+ unless soap_request.is_a?(SOAPStruct)
+ raise RPCRoutingError.new("Not an RPC style.")
+ end
+ soap_response = dispatch(soap_request)
+ rescue Exception
+ soap_response = fault($!)
+ is_fault = true
+ end
+
+ header = SOAPHeader.new
+ body = SOAPBody.new(soap_response)
+ response_string = Processor.marshal(header, body, opt)
+
+ return response_string, is_fault
+ end
+
+ # Create fault response string.
+ def create_fault_response(e, charset = nil)
+ header = SOAPHeader.new
+ soap_response = fault(e)
+ body = SOAPBody.new(soap_response)
+ opt = options
+ opt[:charset] = charset
+ Processor.marshal(header, body, opt)
+ end
+
+private
+
+ # Create new response.
+ def create_response(qname, result)
+ name = fqname(qname)
+ if (@method.key?(name))
+ method = @method[name]
+ else
+ raise RPCRoutingError.new("Method: #{ name } not defined.")
+ end
+
+ soap_response = method.create_method_response
+ if soap_response.have_outparam?
+ unless result.is_a?(Array)
+ raise RPCRoutingError.new("Out parameter was not returned.")
+ end
+ outparams = {}
+ i = 1
+ soap_response.each_param_name('out', 'inout') do |outparam|
+ outparams[outparam] = Mapping.obj2soap(result[i], @mapping_registry)
+ i += 1
+ end
+ soap_response.set_outparam(outparams)
+ soap_response.retval = Mapping.obj2soap(result[0], @mapping_registry)
+ else
+ soap_response.retval = Mapping.obj2soap(result, @mapping_registry)
+ end
+ soap_response
+ end
+
+ # Create fault response.
+ def fault(e)
+ detail = Mapping::SOAPException.new(e)
+ SOAPFault.new(
+ SOAPString.new('Server'),
+ SOAPString.new(e.to_s),
+ SOAPString.new(@actor),
+ Mapping.obj2soap(detail, @mapping_registry))
+ end
+
+ # Dispatch to defined method.
+ def dispatch(soap_method)
+ request_struct = Mapping.soap2obj(soap_method, @mapping_registry)
+ values = soap_method.collect { |key, value| request_struct[key] }
+ method = lookup(soap_method.elename, values)
+ unless method
+ raise RPCRoutingError.new(
+ "Method: #{ soap_method.elename } not supported.")
+ end
+
+ result = method.call(*values)
+ create_response(soap_method.elename, result)
+ end
+
+ # Method lookup
+ def lookup(qname, values)
+ name = fqname(qname)
+ # It may be necessary to check all part of method signature...
+ if @method.member?(name)
+ @receiver[name].method(@method_name[name].intern)
+ else
+ nil
+ end
+ end
+
+ def fqname(qname)
+ "#{ qname.namespace }:#{ qname.name }"
+ end
+
+ def options
+ opt = {}
+ opt[:default_encodingstyle] = @default_encodingstyle
+ if @allow_unqualified_element
+ opt[:allow_unqualified_element] = true
+ end
+ opt
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/rpc.rb b/lib/soap/rpc/rpc.rb
new file mode 100644
index 0000000000..c3cb3228f5
--- /dev/null
+++ b/lib/soap/rpc/rpc.rb
@@ -0,0 +1,36 @@
+=begin
+SOAP4R - RPC utility.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module SOAP
+
+
+module RPC
+ ServerException = Mapping::MappedException
+
+ def self.defined_methods(obj)
+ if obj.is_a?(Module)
+ obj.methods - Module.methods
+ else
+ obj.methods - Kernel.instance_methods(true)
+ end
+ end
+end
+
+
+end
diff --git a/lib/soap/rpc/soaplet.rb b/lib/soap/rpc/soaplet.rb
new file mode 100644
index 0000000000..1a4ef99b76
--- /dev/null
+++ b/lib/soap/rpc/soaplet.rb
@@ -0,0 +1,167 @@
+=begin
+SOAP4R - SOAP handler servlet for WEBrick
+Copyright (C) 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'webrick/httpservlet/abstract'
+require 'webrick/httpstatus'
+require 'soap/rpc/router'
+require 'soap/streamHandler'
+
+module SOAP
+module RPC
+
+
+class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
+public
+ attr_reader :app_scope_router
+
+ def initialize
+ @router_map = {}
+ @app_scope_router = ::SOAP::RPC::Router.new(self.class.name)
+ end
+
+ # Add servant klass whose object has request scope. A servant object is
+ # instanciated for each request.
+ #
+ # Bare in mind that servant klasses are distinguished by HTTP SOAPAction
+ # header in request. Client which calls request-scoped servant must have a
+ # SOAPAction header which is a namespace of the servant klass.
+ # I mean, use Driver#add_method_with_soapaction instead of Driver#add_method
+ # at client side.
+ #
+ def add_rpc_request_servant(klass, namespace, mapping_registry = nil)
+ router = RequestRouter.new(klass, namespace, mapping_registry)
+ add_router(namespace, router)
+ end
+
+ # Add servant object which has application scope.
+ def add_rpc_servant(obj, namespace)
+ router = @app_scope_router
+ SOAPlet.add_servant_to_router(router, obj, namespace)
+ add_router(namespace, router)
+ end
+ alias add_servant add_rpc_servant
+
+
+ ###
+ ## Servlet interfaces for WEBrick.
+ #
+ def get_instance(config, *options)
+ @config = config
+ self
+ end
+
+ def require_path_info?
+ false
+ end
+
+ def do_GET(req, res)
+ res.header['Allow'] = 'POST'
+ raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed."
+ end
+
+ def do_POST(req, res)
+ namespace = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
+ router = lookup_router(namespace)
+
+ is_fault = false
+
+ charset = ::SOAP::StreamHandler.parse_media_type(req['content-type'])
+ begin
+ response_stream, is_fault = router.route(req.body, charset)
+ rescue Exception => e
+ response_stream = router.create_fault_response(e)
+ is_fault = true
+ end
+
+ res.body = response_stream
+ res['content-type'] = "text/xml; charset=\"#{charset}\""
+ if response_stream.is_a?(IO)
+ res.chunked = true
+ end
+
+ if is_fault
+ res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
+ end
+ end
+
+private
+
+ class RequestRouter < ::SOAP::RPC::Router
+ def initialize(klass, namespace, mapping_registry = nil)
+ super(namespace)
+ if mapping_registry
+ self.mapping_registry = mapping_registry
+ end
+ @klass = klass
+ @namespace = namespace
+ end
+
+ def route(soap_string)
+ obj = @klass.new
+ namespace = self.actor
+ router = ::SOAP::RPC::Router.new(@namespace)
+ SOAPlet.add_servant_to_router(router, obj, namespace)
+ router.route(soap_string)
+ end
+ end
+
+ def add_router(namespace, router)
+ @router_map[namespace] = router
+ end
+
+ def parse_soapaction(soapaction)
+ if /^"(.*)"$/ =~ soapaction
+ soapaction = $1
+ end
+ if soapaction.empty?
+ return nil
+ end
+ soapaction
+ end
+
+ def lookup_router(namespace)
+ if namespace
+ @router_map[namespace] || @app_scope_router
+ else
+ @app_scope_router
+ end
+ end
+
+ class << self
+ public
+ def add_servant_to_router(router, obj, namespace)
+ ::SOAP::RPC.defined_methods(obj).each do |name|
+ add_servant_method_to_router(router, obj, namespace, name)
+ end
+ end
+
+ def add_servant_method_to_router(router, obj, namespace, name)
+ qname = XSD::QName.new(namespace, name)
+ soapaction = nil
+ method = obj.method(name)
+ param_def = ::SOAP::RPC::SOAPMethod.create_param_def(
+ (1..method.arity.abs).collect { |i| "p#{ i }" })
+ router.add_method(obj, qname, soapaction, name, param_def)
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/rpc/standaloneServer.rb b/lib/soap/rpc/standaloneServer.rb
new file mode 100644
index 0000000000..bc8ab18f4c
--- /dev/null
+++ b/lib/soap/rpc/standaloneServer.rb
@@ -0,0 +1,116 @@
+=begin
+SOAP4R - WEBrick Server
+Copyright (C) 2003 by NAKAMURA, Hiroshi
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'logger'
+require 'soap/rpc/soaplet'
+require 'soap/streamHandler'
+
+# require 'webrick'
+require 'webrick/compat.rb'
+require 'webrick/version.rb'
+require 'webrick/config.rb'
+require 'webrick/log.rb'
+require 'webrick/server.rb'
+require 'webrick/utils.rb'
+require 'webrick/accesslog'
+# require 'webrick/htmlutils.rb'
+require 'webrick/httputils.rb'
+# require 'webrick/cookie.rb'
+require 'webrick/httpversion.rb'
+require 'webrick/httpstatus.rb'
+require 'webrick/httprequest.rb'
+require 'webrick/httpresponse.rb'
+require 'webrick/httpserver.rb'
+# require 'webrick/httpservlet.rb'
+# require 'webrick/httpauth.rb'
+
+
+module SOAP
+module RPC
+
+
+class StandaloneServer < Logger::Application
+ attr_reader :server
+
+ def initialize(app_name, namespace, host = "0.0.0.0", port = 8080)
+ super(app_name)
+ @logdev = Logger.new(STDERR)
+ @logdev.level = INFO
+ @namespace = namespace
+ @server = WEBrick::HTTPServer.new(
+ :BindAddress => host,
+ :Logger => logdev,
+ :AccessLog => [[logdev, WEBrick::AccessLog::COMBINED_LOG_FORMAT]],
+ :Port => port
+ )
+ @soaplet = ::SOAP::RPC::SOAPlet.new
+ on_init
+ @server.mount('/', @soaplet)
+ end
+
+ def on_init
+ # define extra methods in derived class.
+ end
+
+ def add_rpc_request_servant(klass, namespace = @namespace, mapping_registry = nil)
+ @soaplet.add_rpc_request_servant(klass, namespace, mapping_registry)
+ end
+
+ def add_rpc_servant(obj, namespace = @namespace)
+ @soaplet.add_rpc_servant(obj, namespace)
+ end
+ alias add_servant add_rpc_servant
+
+ def mapping_registry
+ @soaplet.app_scope_router.mapping_registry
+ end
+
+ def mapping_registry=(mapping_registry)
+ @soaplet.app_scope_router.mapping_registry = mapping_registry
+ end
+
+ def add_method(obj, name, *param)
+ add_method_as(obj, name, name, *param)
+ end
+
+ def add_method_as(obj, name, name_as, *param)
+ qname = XSD::QName.new(@namespace, name_as)
+ soapaction = nil
+ method = obj.method(name)
+ param_def = if param.size == 1 and param[0].is_a?(Array)
+ param[0]
+ elsif param.empty?
+ ::SOAP::RPC::SOAPMethod.create_param_def(
+ (1..method.arity.abs).collect { |i| "p#{ i }" })
+ else
+ SOAP::RPC::SOAPMethod.create_param_def(param)
+ end
+ @soaplet.app_scope_router.add_method(obj, qname, soapaction, name, param_def)
+ end
+
+private
+
+ def run
+ @server.start
+ end
+end
+
+
+end
+end
diff --git a/lib/soap/soap.rb b/lib/soap/soap.rb
new file mode 100644
index 0000000000..313af3a059
--- /dev/null
+++ b/lib/soap/soap.rb
@@ -0,0 +1,112 @@
+=begin
+SOAP4R - Base definitions.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'xsd/charset'
+
+
+module SOAP
+
+
+Version = '1.5.0'
+
+EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/'
+EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/'
+LiteralNamespace = 'http://xml.apache.org/xml-soap/literalxml'
+
+NextActor = 'http://schemas.xmlsoap.org/soap/actor/next'
+
+EleEnvelope = 'Envelope'
+EleHeader = 'Header'
+EleBody = 'Body'
+EleFault = 'Fault'
+EleFaultString = 'faultstring'
+EleFaultActor = 'faultactor'
+EleFaultCode = 'faultcode'
+EleFaultDetail = 'detail'
+
+AttrMustUnderstand = 'mustUnderstand'
+AttrEncodingStyle = 'encodingStyle'
+AttrActor = 'actor'
+AttrRoot = 'root'
+AttrArrayType = 'arrayType'
+AttrOffset = 'offset'
+AttrPosition = 'position'
+ValueArray = 'Array'
+
+EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope)
+EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader)
+EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody)
+EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault)
+EleFaultStringName = XSD::QName.new(nil, EleFaultString)
+EleFaultActorName = XSD::QName.new(nil, EleFaultActor)
+EleFaultCodeName = XSD::QName.new(nil, EleFaultCode)
+EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail)
+AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle)
+AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot)
+AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType)
+AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset)
+AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition)
+ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray)
+
+Base64Literal = 'base64'
+
+SOAPNamespaceTag = 'env'
+XSDNamespaceTag = 'xsd'
+XSINamespaceTag = 'xsi'
+
+MediaType = 'text/xml'
+
+class Error < StandardError; end
+
+class StreamError < Error; end
+class HTTPStreamError < StreamError; end
+class PostUnavailableError < HTTPStreamError; end
+class MPostUnavailableError < HTTPStreamError; end
+
+class ArrayIndexOutOfBoundsError < Error; end
+class ArrayStoreError < Error; end
+
+class RPCRoutingError < Error; end
+
+class FaultError < Error
+ attr_reader :faultcode
+ attr_reader :faultstring
+ attr_reader :faultactor
+ attr_accessor :detail
+
+ def initialize(fault)
+ @faultcode = fault.faultcode
+ @faultstring = fault.faultstring
+ @faultactor = fault.faultactor
+ @detail = fault.detail
+ super(self.to_s)
+ end
+
+ def to_s
+ str = nil
+ if @faultstring && @faultstring.respond_to?('data')
+ str = @faultstring.data
+ end
+ str || '(No faultstring)'
+ end
+end
+
+
+end
diff --git a/lib/soap/streamHandler.rb b/lib/soap/streamHandler.rb
new file mode 100644
index 0000000000..c0ca3955f7
--- /dev/null
+++ b/lib/soap/streamHandler.rb
@@ -0,0 +1,188 @@
+=begin
+SOAP4R - Stream handler.
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'soap/soap'
+
+
+module SOAP
+
+
+class StreamHandler
+ Client = begin
+ require 'http-access2'
+ if HTTPAccess2::VERSION < "2.0"
+ raise LoadError.new("http-access/2.0 or later is required.")
+ end
+ HTTPAccess2::Client
+ rescue LoadError
+ STDERR.puts "Loading http-access2 failed. Net/http is used." if $DEBUG
+ require 'soap/netHttpClient'
+ SOAP::NetHttpClient
+ end
+
+ RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]"
+ %q$Id$ =~ /: (\S+),v (\S+)/
+ RCS_FILE, RCS_REVISION = $1, $2
+
+ class ConnectionData
+ attr_accessor :send_string
+ attr_accessor :send_contenttype
+ attr_accessor :receive_string
+ attr_accessor :receive_contenttype
+
+ def initialize
+ @send_string = nil
+ @send_contenttype = nil
+ @receive_string = nil
+ @receive_contenttype = nil
+ @bag = {}
+ end
+
+ def [](idx)
+ @bag[idx]
+ end
+
+ def []=(idx, value)
+ @bag[idx] = value
+ end
+ end
+
+ attr_accessor :endpoint_url
+
+ def initialize(endpoint_url)
+ @endpoint_url = endpoint_url
+ end
+
+ def self.parse_media_type(str)
+ if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str
+ raise StreamError.new("Illegal media type.");
+ end
+ charset = $1
+ charset.gsub!(/"/, '') if charset
+ charset
+ end
+
+ def self.create_media_type(charset)
+ "#{ MediaType }; charset=#{ charset }"
+ end
+end
+
+
+class HTTPPostStreamHandler < StreamHandler
+ include SOAP
+
+public
+
+ attr_accessor :wiredump_dev
+ attr_accessor :wiredump_file_base
+ attr_accessor :charset
+
+ NofRetry = 10 # [times]
+ ConnectTimeout = 20 # [sec]
+ SendTimeout = 60 # [sec]
+ ReceiveTimeout = 60 # [sec]
+
+ def initialize(endpoint_url, proxy = nil, charset = nil)
+ super(endpoint_url)
+ @proxy = proxy || ENV['http_proxy'] || ENV['HTTP_PROXY']
+ @charset = charset || XSD::Charset.charset_label($KCODE)
+ @wiredump_dev = nil # Set an IO to get wiredump.
+ @wiredump_file_base = nil
+ @client = Client.new(@proxy, "SOAP4R/#{ Version }")
+ @client.session_manager.connect_timeout = ConnectTimeout
+ @client.session_manager.send_timeout = SendTimeout
+ @client.session_manager.receive_timeout = ReceiveTimeout
+ end
+
+ def proxy=(proxy)
+ @proxy = proxy
+ @client.proxy = @proxy
+ end
+
+ def send(soap_string, soapaction = nil, charset = @charset)
+ send_post(soap_string, soapaction, charset)
+ end
+
+ def reset
+ @client.reset(@endpoint_url)
+ end
+
+private
+
+ def send_post(soap_string, soapaction, charset)
+ data = ConnectionData.new
+ data.send_string = soap_string
+ data.send_contenttype = StreamHandler.create_media_type(charset)
+
+ wiredump_dev = if @wiredump_dev && @wiredump_dev.respond_to?("<<")
+ @wiredump_dev
+ else
+ nil
+ end
+ @client.debug_dev = wiredump_dev
+
+ if @wiredump_file_base
+ filename = @wiredump_file_base + '_request.xml'
+ f = File.open(filename, "w")
+ f << soap_string
+ f.close
+ end
+
+ extra = {}
+ extra['Content-Type'] = data.send_contenttype
+ extra['SOAPAction'] = "\"#{ soapaction }\""
+
+ wiredump_dev << "Wire dump:\n\n" if wiredump_dev
+ begin
+ res = @client.post(@endpoint_url, soap_string, extra)
+ rescue
+ @client.reset(@endpoint_url)
+ raise
+ end
+ wiredump_dev << "\n\n" if wiredump_dev
+
+ receive_string = res.content
+
+ if @wiredump_file_base
+ filename = @wiredump_file_base + '_response.xml'
+ f = File.open(filename, "w")
+ f << receive_string
+ f.close
+ end
+
+ case res.status
+ when 405
+ raise PostUnavailableError.new("#{ res.status }: #{ res.reason }")
+ when 200, 500
+ # Nothing to do.
+ else
+ raise HTTPStreamError.new("#{ res.status }: #{ res.reason }")
+ end
+
+ data.receive_string = receive_string
+ data.receive_contenttype = res.contenttype
+
+ return data
+ end
+
+ CRLF = "\r\n"
+end
+
+
+end
diff --git a/lib/soap/wsdlDriver.rb b/lib/soap/wsdlDriver.rb
new file mode 100644
index 0000000000..849effcb0b
--- /dev/null
+++ b/lib/soap/wsdlDriver.rb
@@ -0,0 +1,490 @@
+=begin
+SOAP4R - SOAP WSDL driver
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/parser'
+require 'wsdl/importer'
+require 'xsd/qname'
+require 'soap/element'
+require 'soap/baseData'
+require 'soap/streamHandler'
+require 'soap/mapping'
+require 'soap/mapping/wsdlRegistry'
+require 'soap/rpc/rpc'
+require 'soap/rpc/element'
+require 'soap/processor'
+require 'logger'
+
+
+module SOAP
+
+
+class WSDLDriverFactory
+ class FactoryError < StandardError; end
+
+ attr_reader :wsdl
+
+ def initialize(wsdl, logdev = nil)
+ @logdev = logdev
+ @wsdl = import(wsdl)
+ end
+
+ def create_driver(servicename = nil, portname = nil, opt = {})
+ service = if servicename
+ @wsdl.service(XSD::QName.new(@wsdl.targetnamespace, servicename))
+ else
+ @wsdl.services[0]
+ end
+ if service.nil?
+ raise FactoryError.new("Service #{ servicename } not found in WSDL.")
+ end
+ port = if portname
+ service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)]
+ else
+ service.ports[0]
+ end
+ if port.nil?
+ raise FactoryError.new("Port #{ portname } not found in WSDL.")
+ end
+ if port.soap_address.nil?
+ raise FactoryError.new("soap:address element not found in WSDL.")
+ end
+ WSDLDriver.new(@wsdl, port, @logdev, opt)
+ end
+
+ # Backward compatibility.
+ alias createDriver create_driver
+
+private
+
+ def import(location)
+ WSDL::Importer.import(location)
+ end
+end
+
+
+class WSDLDriver
+ class << self
+ def __attr_proxy(symbol, assignable = false)
+ name = symbol.to_s
+ module_eval <<-EOD
+ def #{name}
+ @servant.#{name}
+ end
+ EOD
+ if assignable
+ module_eval <<-EOD
+ def #{name}=(rhs)
+ @servant.#{name} = rhs
+ end
+ EOD
+ end
+ end
+ end
+
+ __attr_proxy :opt
+ __attr_proxy :logdev, true
+ __attr_proxy :mapping_registry, true # for RPC unmarshal
+ __attr_proxy :wsdl_mapping_registry, true # for RPC marshal
+ __attr_proxy :endpoint_url, true
+ __attr_proxy :wiredump_dev, true
+ __attr_proxy :wiredump_file_base, true
+ __attr_proxy :httpproxy, true
+
+ __attr_proxy :default_encodingstyle, true
+ __attr_proxy :allow_unqualified_element, true
+ __attr_proxy :generate_explicit_type, true
+
+ def reset_stream
+ @servant.reset_stream
+ end
+
+ # Backward compatibility.
+ alias generateEncodeType= generate_explicit_type=
+
+ class Servant__
+ include Logger::Severity
+ include SOAP
+
+ attr_reader :opt
+ attr_accessor :logdev
+ attr_accessor :mapping_registry
+ attr_accessor :wsdl_mapping_registry
+ attr_reader :endpoint_url
+ attr_reader :wiredump_dev
+ attr_reader :wiredump_file_base
+ attr_reader :httpproxy
+
+ attr_accessor :default_encodingstyle
+ attr_accessor :allow_unqualified_element
+ attr_accessor :generate_explicit_type
+
+ class Mapper
+ def initialize(elements, types)
+ @elements = elements
+ @types = types
+ end
+
+ def obj2ele(obj, name)
+ if ele = @elements[name]
+ _obj2ele(obj, ele)
+ elsif type = @types[name]
+ obj2type(obj, type)
+ else
+ raise RuntimeError.new("Cannot find name #{name} in schema.")
+ end
+ end
+
+ def ele2obj(ele, *arg)
+ raise NotImplementedError.new
+ end
+
+ private
+
+ def _obj2ele(obj, ele)
+ o = nil
+ if ele.type
+ if type = @types[ele.type]
+ o = obj2type(obj, type)
+ elsif type = TypeMap[ele.type]
+ o = base2soap(obj, type)
+ else
+ raise RuntimeError.new("Cannot find type #{ele.type}.")
+ end
+ o.elename = ele.name
+ elsif ele.local_complextype
+ o = SOAPElement.new(ele.name)
+ ele.local_complextype.each_element do |child_name, child_ele|
+ o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele))
+ end
+ else
+ raise RuntimeError.new("Illegal schema?")
+ end
+ o
+ end
+
+ def obj2type(obj, type)
+ o = SOAPElement.new(type.name)
+ type.each_element do |child_name, child_ele|
+ o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele))
+ end
+ o
+ end
+
+ def _ele2obj(ele)
+ raise NotImplementedError.new
+ end
+
+ def base2soap(obj, type)
+ soap_obj = nil
+ if type <= XSD::XSDString
+ soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ?
+ XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj)
+ else
+ soap_obj = type.new(obj)
+ end
+ soap_obj
+ end
+
+ def find_attribute(obj, attr_name)
+ if obj.respond_to?(attr_name)
+ obj.__send__(attr_name)
+ elsif obj.is_a?(Hash)
+ obj[attr_name] || obj[attr_name.intern]
+ else
+ obj.instance_eval("@#{ attr_name }")
+ end
+ end
+ end
+
+ def initialize(host, wsdl, port, logdev, opt)
+ @host = host
+ @wsdl = wsdl
+ @port = port
+ @logdev = logdev
+ @opt = opt.dup
+ @mapping_registry = nil # for rpc unmarshal
+ @wsdl_mapping_registry = nil # for rpc marshal
+ @endpoint_url = nil
+ @wiredump_dev = nil
+ @wiredump_file_base = nil
+ @httpproxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
+
+ @wsdl_elements = @wsdl.collect_elements
+ @wsdl_types = @wsdl.collect_complextypes
+ @rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding)
+ @wsdl_mapping_registry = Mapping::WSDLRegistry.new(@rpc_decode_typemap)
+ @doc_mapper = Mapper.new(@wsdl_elements, @wsdl_types)
+ @default_encodingstyle = EncodingNamespace
+ @allow_unqualified_element = true
+ @generate_explicit_type = false
+
+ create_handler
+ @operations = {}
+ # Convert a map which key is QName, to a Hash which key is String.
+ @port.inputoperation_map.each do |op_name, op_info|
+ @operations[op_name.name] = op_info
+ add_method_interface(op_info)
+ end
+ end
+
+ def endpoint_url=(endpoint_url)
+ @endpoint_url = endpoint_url
+ if @handler
+ @handler.endpoint_url = @endpoint_url
+ @handler.reset
+ end
+ log(DEBUG) { "endpoint_url=: set endpoint_url #{ @endpoint_url }." }
+ end
+
+ def wiredump_dev=(dev)
+ @wiredump_dev = dev
+ if @handler
+ @handler.wiredump_dev = @wiredump_dev
+ @handler.reset
+ end
+ end
+
+ def wiredump_file_base=(base)
+ @wiredump_file_base = base
+ end
+
+ def httpproxy=(httpproxy)
+ @httpproxy = httpproxy
+ if @handler
+ @handler.proxy = @httpproxy
+ @handler.reset
+ end
+ log(DEBUG) { "httpproxy=: set httpproxy #{ @httpproxy }." }
+ end
+
+ def reset_stream
+ @handler.reset
+ end
+
+ def rpc_send(method_name, *params)
+ log(INFO) { "call: calling method '#{ method_name }'." }
+ log(DEBUG) { "call: parameters '#{ params.inspect }'." }
+
+ op_info = @operations[method_name]
+ parts_names = op_info.bodyparts.collect { |part| part.name }
+ obj = create_method_obj(parts_names, params)
+ method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.optype_name)
+ method.elename = op_info.op_name
+ method.type = XSD::QName.new # Request should not be typed.
+ req_header = nil
+ req_body = SOAPBody.new(method)
+
+ if @wiredump_file_base
+ @handler.wiredump_file_base = @wiredump_file_base + '_' << method_name
+ end
+
+ begin
+ opt = create_options
+ opt[:decode_typemap] = @rpc_decode_typemap
+ res_header, res_body = invoke(req_header, req_body, op_info, opt)
+ if res_body.fault
+ raise SOAP::FaultError.new(res_body.fault)
+ end
+ rescue SOAP::FaultError => e
+ Mapping.fault2exception(e)
+ end
+
+ ret = res_body.response ?
+ Mapping.soap2obj(res_body.response, @mapping_registry) : nil
+
+ if res_body.outparams
+ outparams = res_body.outparams.collect { |outparam|
+ Mapping.soap2obj(outparam)
+ }
+ return [ret].concat(outparams)
+ else
+ return ret
+ end
+ end
+
+ # req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...]
+ # req_body: SOAPBasetype/SOAPCompoundtype
+ def document_send(name, header_obj, body_obj)
+ log(INFO) { "document_send: sending document '#{ name }'." }
+ op_info = @operations[name]
+ req_header = header_from_obj(header_obj, op_info)
+ req_body = body_from_obj(body_obj, op_info)
+ opt = create_options
+ res_header, res_body = invoke(req_header, req_body, op_info, opt)
+ if res_body.fault
+ raise SOAP::FaultError.new(res_body.fault)
+ end
+ res_body_obj = res_body.response ?
+ Mapping.soap2obj(res_body.response, @mapping_registry) : nil
+ return res_header, res_body_obj
+ end
+
+ private
+
+ def create_handler
+ endpoint_url = @endpoint_url || @port.soap_address.location
+ @handler = HTTPPostStreamHandler.new(endpoint_url, @httpproxy,
+ XSD::Charset.encoding_label)
+ @handler.wiredump_dev = @wiredump_dev
+ end
+
+ def create_method_obj(names, params)
+ o = Object.new
+ for idx in 0 ... params.length
+ o.instance_eval("@#{ names[idx] } = params[idx]")
+ end
+ o
+ end
+
+ def invoke(req_header, req_body, op_info, opt)
+ send_string = Processor.marshal(req_header, req_body, opt)
+ log(DEBUG) { "invoke: sending string #{ send_string }" }
+ data = @handler.send(send_string, op_info.soapaction)
+ log(DEBUG) { "invoke: received string #{ data.receive_string }" }
+ if data.receive_string.empty?
+ return nil, nil
+ end
+ res_charset = StreamHandler.parse_media_type(data.receive_contenttype)
+ opt[:charset] = res_charset
+ res_header, res_body = Processor.unmarshal(data.receive_string, opt)
+ return res_header, res_body
+ end
+
+ def header_from_obj(obj, op_info)
+ if obj.is_a?(SOAPHeader)
+ obj
+ elsif op_info.headerparts.empty?
+ if obj.nil?
+ nil
+ else
+ raise RuntimeError.new("No header definition in schema.")
+ end
+ elsif op_info.headerparts.size == 1
+ part = op_info.headerparts[0]
+ header = SOAPHeader.new()
+ header.add(headeritem_from_obj(obj, part.element || part.eletype))
+ header
+ else
+ header = SOAPHeader.new()
+ op_info.headerparts.each do |part|
+ child = obj[part.elename.name]
+ ele = headeritem_from_obj(child, part.element || part.eletype)
+ header.add(ele)
+ end
+ header
+ end
+ end
+
+ def headeritem_from_obj(obj, name)
+ if obj.nil?
+ SOAPElement.new(name)
+ elsif obj.is_a?(SOAPHeaderItem)
+ obj
+ else
+ @doc_mapper.obj2ele(obj, name)
+ end
+ end
+
+ def body_from_obj(obj, op_info)
+ if obj.is_a?(SOAPBody)
+ obj
+ elsif op_info.bodyparts.empty?
+ if obj.nil?
+ nil
+ else
+ raise RuntimeError.new("No body found in schema.")
+ end
+ elsif op_info.bodyparts.size == 1
+ part = op_info.bodyparts[0]
+ ele = bodyitem_from_obj(obj, part.element || part.type)
+ SOAPBody.new(ele)
+ else
+ body = SOAPBody.new
+ op_info.bodyparts.each do |part|
+ child = obj[part.elename.name]
+ ele = bodyitem_from_obj(child, part.element || part.type)
+ body.add(ele.elename.name, ele)
+ end
+ body
+ end
+ end
+
+ def bodyitem_from_obj(obj, name)
+ if obj.nil?
+ SOAPElement.new(name)
+ elsif obj.is_a?(SOAPElement)
+ obj
+ else
+ @doc_mapper.obj2ele(obj, name)
+ end
+ end
+
+ def add_method_interface(op_info)
+ case op_info.style
+ when :document
+ add_document_method_interface(op_info.op_name.name)
+ when :rpc
+ parts_names = op_info.bodyparts.collect { |part| part.name }
+ add_rpc_method_interface(op_info.op_name.name, parts_names)
+ else
+ raise RuntimeError.new("Unknown style: #{op_info.style}")
+ end
+ end
+
+ def add_document_method_interface(name)
+ @host.instance_eval <<-EOS
+ def #{ name }(headers, body)
+ @servant.document_send(#{ name.dump }, headers, body)
+ end
+ EOS
+ end
+
+ def add_rpc_method_interface(name, parts_names)
+ i = 0
+ param_names = parts_names.collect { |orgname| i += 1; "arg#{ i }" }
+ callparam_str = (param_names.collect { |pname| ", " + pname }).join
+ @host.instance_eval <<-EOS
+ def #{ name }(#{ param_names.join(", ") })
+ @servant.rpc_send(#{ name.dump }#{ callparam_str })
+ end
+ EOS
+ end
+
+ def create_options
+ opt = @opt.dup
+ opt[:default_encodingstyle] = @default_encodingstyle
+ opt[:allow_unqualified_element] = @allow_unqualified_element
+ opt[:generate_explicit_type] = @generate_explicit_type
+ opt
+ end
+
+ def log(sev)
+ @logdev.add(sev, nil, self.class) { yield } if @logdev
+ end
+ end
+
+ def initialize(wsdl, port, logdev, opt)
+ @servant = Servant__.new(self, wsdl, port, logdev, opt)
+ end
+end
+
+
+end
+
+
diff --git a/lib/wsdl/binding.rb b/lib/wsdl/binding.rb
new file mode 100644
index 0000000000..349d6edcb6
--- /dev/null
+++ b/lib/wsdl/binding.rb
@@ -0,0 +1,76 @@
+=begin
+WSDL4R - WSDL binding definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+
+
+class Binding < Info
+ attr_reader :name # required
+ attr_reader :type # required
+ attr_reader :operations
+ attr_reader :soapbinding
+
+ def initialize
+ super
+ @name = nil
+ @type = nil
+ @operations = XSD::NamedElements.new
+ @soapbinding = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def parse_element(element)
+ case element
+ when OperationName
+ o = OperationBinding.new
+ @operations << o
+ o
+ when SOAPBindingName
+ o = WSDL::SOAP::Binding.new
+ @soapbinding = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ when TypeAttrName
+ @type = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/data.rb b/lib/wsdl/data.rb
new file mode 100644
index 0000000000..4f3b845316
--- /dev/null
+++ b/lib/wsdl/data.rb
@@ -0,0 +1,73 @@
+=begin
+WSDL4R - WSDL data definitions.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/documentation'
+require 'wsdl/definitions'
+require 'wsdl/types'
+require 'wsdl/message'
+require 'wsdl/part'
+require 'wsdl/portType'
+require 'wsdl/operation'
+require 'wsdl/param'
+require 'wsdl/binding'
+require 'wsdl/operationBinding'
+require 'wsdl/service'
+require 'wsdl/port'
+require 'wsdl/import'
+
+
+module WSDL
+
+
+BindingName = XSD::QName.new(Namespace, 'binding')
+DefinitionsName = XSD::QName.new(Namespace, 'definitions')
+DocumentationName = XSD::QName.new(Namespace, 'documentation')
+FaultName = XSD::QName.new(Namespace, 'fault')
+ImportName = XSD::QName.new(Namespace, 'import')
+InputName = XSD::QName.new(Namespace, 'input')
+MessageName = XSD::QName.new(Namespace, 'message')
+OperationName = XSD::QName.new(Namespace, 'operation')
+OutputName = XSD::QName.new(Namespace, 'output')
+PartName = XSD::QName.new(Namespace, 'part')
+PortName = XSD::QName.new(Namespace, 'port')
+PortTypeName = XSD::QName.new(Namespace, 'portType')
+ServiceName = XSD::QName.new(Namespace, 'service')
+TypesName = XSD::QName.new(Namespace, 'types')
+
+SchemaName = XSD::QName.new(XSD::Namespace, 'schema')
+
+SOAPAddressName = XSD::QName.new(SOAPBindingNamespace, 'address')
+SOAPBindingName = XSD::QName.new(SOAPBindingNamespace, 'binding')
+SOAPHeaderName = XSD::QName.new(SOAPBindingNamespace, 'header')
+SOAPBodyName = XSD::QName.new(SOAPBindingNamespace, 'body')
+SOAPFaultName = XSD::QName.new(SOAPBindingNamespace, 'fault')
+SOAPOperationName = XSD::QName.new(SOAPBindingNamespace, 'operation')
+
+BindingAttrName = XSD::QName.new(nil, 'binding')
+ElementAttrName = XSD::QName.new(nil, 'element')
+LocationAttrName = XSD::QName.new(nil, 'location')
+MessageAttrName = XSD::QName.new(nil, 'message')
+NameAttrName = XSD::QName.new(nil, 'name')
+NamespaceAttrName = XSD::QName.new(nil, 'namespace')
+ParameterOrderAttrName = XSD::QName.new(nil, 'parameterOrder')
+TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace')
+TypeAttrName = XSD::QName.new(nil, 'type')
+
+
+end
diff --git a/lib/wsdl/definitions.rb b/lib/wsdl/definitions.rb
new file mode 100644
index 0000000000..7a0cff01e7
--- /dev/null
+++ b/lib/wsdl/definitions.rb
@@ -0,0 +1,233 @@
+=begin
+WSDL4R - WSDL definitions.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+
+
+class Definitions < Info
+ attr_reader :name
+ attr_reader :targetnamespace
+ attr_reader :imports
+
+ # Overrides Info#root
+ def root
+ @root
+ end
+
+ def root=(root)
+ @root = root
+ end
+
+ def initialize
+ super
+ @name = nil
+ @targetnamespace = nil
+ @types = nil
+ @imports = []
+ @messages = XSD::NamedElements.new
+ @porttypes = XSD::NamedElements.new
+ @bindings = XSD::NamedElements.new
+ @services = XSD::NamedElements.new
+
+ @anontypes = XSD::NamedElements.new
+ @root = self
+ end
+
+ def targetnamespace=(targetnamespace)
+ @targetnamespace = targetnamespace
+ if @name
+ @name = XSD::QName.new(@targetnamespace, @name.name)
+ end
+ end
+
+ def collect_elements
+ result = XSD::NamedElements.new
+ if @types
+ @types.schemas.each do |schema|
+ result.concat(schema.elements)
+ end
+ end
+ @imports.each do |import|
+ result.concat(import.content.collect_elements)
+ end
+ result
+ end
+
+ def collect_complextypes
+ result = @anontypes.dup
+ if @types
+ @types.schemas.each do |schema|
+ result.concat(schema.complextypes)
+ end
+ end
+ @imports.each do |import|
+ result.concat(import.content.collect_complextypes)
+ end
+ result
+ end
+
+ def add_type(complextype)
+ @anontypes << complextype
+ end
+
+ def messages
+ result = @messages.dup
+ @imports.each do |import|
+ result.concat(import.content.messages) if self.class === import.content
+ end
+ result
+ end
+
+ def porttypes
+ result = @porttypes.dup
+ @imports.each do |import|
+ result.concat(import.content.porttypes) if self.class === import.content
+ end
+ result
+ end
+
+ def bindings
+ result = @bindings.dup
+ @imports.each do |import|
+ result.concat(import.content.bindings) if self.class === import.content
+ end
+ result
+ end
+
+ def services
+ result = @services.dup
+ @imports.each do |import|
+ result.concat(import.content.services) if self.class === import.content
+ end
+ result
+ end
+
+ def message(name)
+ message = @messages[name]
+ return message if message
+ @imports.each do |import|
+ message = import.content.message(name) if self.class === import.content
+ return message if message
+ end
+ nil
+ end
+
+ def porttype(name)
+ porttype = @porttypes[name]
+ return porttype if porttype
+ @imports.each do |import|
+ porttype = import.content.porttype(name) if self.class === import.content
+ return porttype if porttype
+ end
+ nil
+ end
+
+ def binding(name)
+ binding = @bindings[name]
+ return binding if binding
+ @imports.each do |import|
+ binding = import.content.binding(name) if self.class === import.content
+ return binding if binding
+ end
+ nil
+ end
+
+ def service(name)
+ service = @services[name]
+ return service if service
+ @imports.each do |import|
+ service = import.content.service(name) if self.class === import.content
+ return service if service
+ end
+ nil
+ end
+
+ def porttype_binding(name)
+ binding = @bindings.find { |item| item.type == name }
+ return binding if binding
+ @imports.each do |import|
+ binding = import.content.porttype_binding(name) if self.class === import.content
+ return binding if binding
+ end
+ nil
+ end
+
+ def parse_element(element)
+ case element
+ when ImportName
+ o = Import.new
+ @imports << o
+ o
+ when TypesName
+ o = Types.new
+ @types = o
+ o
+ when MessageName
+ o = Message.new
+ @messages << o
+ o
+ when PortTypeName
+ o = PortType.new
+ @porttypes << o
+ o
+ when BindingName
+ o = Binding.new
+ @bindings << o
+ o
+ when ServiceName
+ o = Service.new
+ @services << o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(@targetnamespace, value)
+ when TargetNamespaceAttrName
+ self.targetnamespace = value
+ else
+ nil
+ end
+ end
+
+ def self.parse_element(element)
+ if element == DefinitionsName
+ Definitions.new
+ else
+ nil
+ end
+ end
+
+private
+
+end
+
+
+end
diff --git a/lib/wsdl/documentation.rb b/lib/wsdl/documentation.rb
new file mode 100644
index 0000000000..00e78a99df
--- /dev/null
+++ b/lib/wsdl/documentation.rb
@@ -0,0 +1,43 @@
+=begin
+WSDL4R - WSDL SOAP documentation element.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Documentation < Info
+ def initialize
+ super
+ end
+
+ def parse_element(element)
+ # Accepts any element.
+ self
+ end
+
+ def parse_attr(attr, value)
+ # Accepts any attribute.
+ true
+ end
+end
+
+
+end
diff --git a/lib/wsdl/import.rb b/lib/wsdl/import.rb
new file mode 100644
index 0000000000..a0fa26afaf
--- /dev/null
+++ b/lib/wsdl/import.rb
@@ -0,0 +1,81 @@
+=begin
+WSDL4R - WSDL import definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'wsdl/importer'
+
+
+module WSDL
+
+
+class Import < Info
+ attr_reader :namespace
+ attr_reader :location
+ attr_reader :content
+
+ def initialize
+ super
+ @namespace = nil
+ @location = nil
+ @content = nil
+ @web_client = nil
+ end
+
+ def parse_element(element)
+ case element
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NamespaceAttrName
+ @namespace = value
+ if @content
+ @content.targetnamespace = @namespace
+ end
+ @namespace
+ when LocationAttrName
+ @location = value
+ @content = import(@location)
+ if @content.is_a?(Definitions)
+ @content.root = root
+ if @namespace
+ @content.targetnamespace = @namespace
+ end
+ end
+ @location
+ else
+ nil
+ end
+ end
+
+private
+
+ def import(location)
+ Importer.import(location)
+ end
+end
+
+
+end
diff --git a/lib/wsdl/importer.rb b/lib/wsdl/importer.rb
new file mode 100644
index 0000000000..794e7fc74d
--- /dev/null
+++ b/lib/wsdl/importer.rb
@@ -0,0 +1,75 @@
+=begin
+WSDL4R - WSDL importer library.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Importer
+ def self.import(location)
+ new.import(location)
+ end
+
+ def initialize
+ @web_client = nil
+ end
+
+ def import(location)
+ content = nil
+ if FileTest.exist?(location)
+ content = File.open(location).read
+ else
+ proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
+ content = web_client.new(proxy, "WSDL4R").get_content(location)
+ end
+ opt = {} # charset?
+ begin
+ WSDL::Parser.new(opt).parse(content)
+ rescue WSDL::Parser::ParseError => orgexcn
+ begin
+ require 'wsdl/xmlSchema/parser'
+ WSDL::XMLSchema::Parser.new(opt).parse(content)
+ rescue
+ raise orgexcn
+ end
+ end
+ end
+
+private
+
+ def web_client
+ @web_client ||= begin
+ require 'http-access2'
+ if HTTPAccess2::VERSION < "2.0"
+ raise LoadError.new("http-access/2.0 or later is required.")
+ end
+ HTTPAccess2::Client
+ rescue LoadError
+ STDERR.puts "Loading http-access2 failed. Net/http is used." if $DEBUG
+ require 'soap/netHttpClient'
+ ::SOAP::NetHttpClient
+ end
+ @web_client
+ end
+end
+
+
+end
diff --git a/lib/wsdl/info.rb b/lib/wsdl/info.rb
new file mode 100644
index 0000000000..886b9255ae
--- /dev/null
+++ b/lib/wsdl/info.rb
@@ -0,0 +1,44 @@
+=begin
+WSDL4R - WSDL information base.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module WSDL
+
+
+class Info
+ attr_accessor :parent
+ attr_accessor :id
+
+ def initialize
+ @parent = nil
+ @id = nil
+ end
+
+ def root
+ @parent.root
+ end
+
+ def parse_element(element); end # abstract
+
+ def parse_attr(attr, value); end # abstract
+
+ def parse_epilogue; end # abstract
+end
+
+
+end
diff --git a/lib/wsdl/message.rb b/lib/wsdl/message.rb
new file mode 100644
index 0000000000..68f3bb89dd
--- /dev/null
+++ b/lib/wsdl/message.rb
@@ -0,0 +1,65 @@
+=begin
+WSDL4R - WSDL message definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Message < Info
+ attr_reader :name # required
+ attr_reader :parts
+
+ def initialize
+ super
+ @name = nil
+ @parts = []
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def parse_element(element)
+ case element
+ when PartName
+ o = Part.new
+ @parts << o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(parent.targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/operation.rb b/lib/wsdl/operation.rb
new file mode 100644
index 0000000000..ff3450d234
--- /dev/null
+++ b/lib/wsdl/operation.rb
@@ -0,0 +1,144 @@
+=begin
+WSDL4R - WSDL operation definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Operation < Info
+ class NameInfo
+ attr_reader :op_name
+ attr_reader :optype_name
+ attr_reader :parts
+ def initialize(op_name, optype_name, parts)
+ @op_name = op_name
+ @optype_name = optype_name
+ @parts = parts
+ end
+ end
+
+ attr_reader :name # required
+ attr_reader :parameter_order # optional
+ attr_reader :input
+ attr_reader :output
+ attr_reader :fault
+ attr_reader :type # required
+
+ def initialize
+ super
+ @name = nil
+ @type = nil
+ @parameter_order = nil
+ @input = nil
+ @output = nil
+ @fault = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def input_info
+ op_name = @name
+ optype_name = XSD::QName.new(targetnamespace, input.name ? input.name.name : @name.name)
+ NameInfo.new(op_name, optype_name, inputparts)
+ end
+
+ def output_info
+ op_name = @name
+ optype_name = XSD::QName.new(targetnamespace, output.name ? output.name.name : @name.name)
+ NameInfo.new(op_name, optype_name, outputparts)
+ end
+
+ def inputparts
+ sort_parts(input.find_message.parts)
+ end
+
+ def outputparts
+ sort_parts(output.find_message.parts)
+ end
+
+ def faultparts
+ sort_parts(fault.find_message.parts)
+ end
+
+ def outputname
+ XSD::QName.new(targetnamespace,
+ output.name ? output.name.name : @name.name + 'Response')
+ end
+
+ def parse_element(element)
+ case element
+ when InputName
+ o = Param.new
+ @input = o
+ o
+ when OutputName
+ o = Param.new
+ @output = o
+ o
+ when FaultName
+ o = Param.new
+ @fault = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ when TypeAttrName
+ @type = value
+ when ParameterOrderAttrName
+ @parameter_order = value.split(/\s+/)
+ else
+ nil
+ end
+ end
+
+private
+
+ def sort_parts(parts)
+ return parts.dup unless parameter_order
+ result = []
+ parameter_order.each do |orderitem|
+ if (ele = parts.find { |part| part.name == orderitem })
+ result << ele
+ end
+ end
+ if result.length == 0
+ return parts.dup
+ end
+ if parts.length != result.length
+ raise RuntimeError.new("Incomplete prarmeterOrder list.")
+ end
+ result
+ end
+end
+
+
+end
diff --git a/lib/wsdl/operationBinding.rb b/lib/wsdl/operationBinding.rb
new file mode 100644
index 0000000000..0bd0d9b105
--- /dev/null
+++ b/lib/wsdl/operationBinding.rb
@@ -0,0 +1,91 @@
+=begin
+WSDL4R - WSDL bound operation definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class OperationBinding < Info
+ attr_reader :name # required
+ attr_reader :input
+ attr_reader :output
+ attr_reader :fault
+ attr_reader :soapoperation
+
+ def initialize
+ super
+ @name = nil
+ @input = nil
+ @output = nil
+ @fault = nil
+ @soapoperation = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def porttype
+ root.porttype(parent.type)
+ end
+
+ def find_operation
+ porttype.operations[@name]
+ end
+
+ def parse_element(element)
+ case element
+ when InputName
+ o = Param.new
+ @input = o
+ o
+ when OutputName
+ o = Param.new
+ @output = o
+ o
+ when FaultName
+ o = Param.new
+ @fault = o
+ o
+ when SOAPOperationName
+ o = WSDL::SOAP::Operation.new
+ @soapoperation = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/param.rb b/lib/wsdl/param.rb
new file mode 100644
index 0000000000..10111677d2
--- /dev/null
+++ b/lib/wsdl/param.rb
@@ -0,0 +1,85 @@
+=begin
+WSDL4R - WSDL param definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Param < Info
+ attr_reader :message # required
+ attr_reader :name # optional but required for fault.
+ attr_reader :soapbody
+ attr_reader :soapheader
+ attr_reader :soapfault
+
+ def initialize
+ super
+ @message = nil
+ @name = nil
+ @soapbody = nil
+ @soapheader = []
+ @soapfault = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def find_message
+ root.message(@message)
+ end
+
+ def parse_element(element)
+ case element
+ when SOAPBodyName
+ o = WSDL::SOAP::Body.new
+ @soapbody = o
+ o
+ when SOAPHeaderName
+ o = WSDL::SOAP::Header.new
+ @soapheader << o
+ o
+ when SOAPFaultName
+ o = WSDL::SOAP::Fault.new
+ @soap_fault = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MessageAttrName
+ @message = value
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/parser.rb b/lib/wsdl/parser.rb
new file mode 100644
index 0000000000..e0a8945bb0
--- /dev/null
+++ b/lib/wsdl/parser.rb
@@ -0,0 +1,170 @@
+=begin
+WSDL4R - WSDL XML Instance parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'xsd/ns'
+require 'xsd/charset'
+require 'xsd/datatypes'
+require 'xsd/xmlparser'
+require 'wsdl/wsdl'
+require 'wsdl/data'
+require 'wsdl/xmlSchema/data'
+require 'wsdl/soap/data'
+
+
+module WSDL
+
+
+class Parser
+ include WSDL
+
+ class ParseError < Error; end
+ class FormatDecodeError < ParseError; end
+ class UnknownElementError < FormatDecodeError; end
+ class UnknownAttributeError < FormatDecodeError; end
+ class UnexpectedElementError < FormatDecodeError; end
+ class ElementConstraintError < FormatDecodeError; end
+ class AttributeConstraintError < FormatDecodeError; end
+
+private
+
+ class ParseFrame
+ attr_reader :ns
+ attr_reader :name
+ attr_accessor :node
+
+ private
+
+ def initialize(ns, name, node)
+ @ns = ns
+ @name = name
+ @node = node
+ end
+ end
+
+public
+
+ def initialize(opt = {})
+ @parser = XSD::XMLParser.create_parser(self, opt)
+ @parsestack = nil
+ @lastnode = nil
+ end
+
+ def parse(string_or_readable)
+ @parsestack = []
+ @lastnode = nil
+ @textbuf = ''
+ @parser.do_parse(string_or_readable)
+ @lastnode
+ end
+
+ def charset
+ @parser.charset
+ end
+
+ def start_element(name, attrs)
+ lastframe = @parsestack.last
+ ns = parent = nil
+ if lastframe
+ ns = lastframe.ns.clone_ns
+ parent = lastframe.node
+ else
+ ns = XSD::NS.new
+ parent = nil
+ end
+ attrs = XSD::XMLParser.filter_ns(ns, attrs)
+ node = decode_tag(ns, name, attrs, parent)
+ @parsestack << ParseFrame.new(ns, name, node)
+ end
+
+ def characters(text)
+ lastframe = @parsestack.last
+ if lastframe
+ # Need not to be cloned because character does not have attr.
+ ns = lastframe.ns
+ decode_text(ns, text)
+ else
+ p text if $DEBUG
+ end
+ end
+
+ def end_element(name)
+ lastframe = @parsestack.pop
+ unless name == lastframe.name
+ raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.")
+ end
+ decode_tag_end(lastframe.ns, lastframe.node)
+ @lastnode = lastframe.node
+ end
+
+private
+
+ def decode_tag(ns, name, attrs, parent)
+ o = nil
+ element = ns.parse(name)
+ if !parent
+ if element == DefinitionsName
+ o = Definitions.parse_element(element)
+ else
+ raise UnknownElementError.new("Unknown element #{ element }.")
+ end
+ else
+ o = parent.parse_element(element)
+ unless o
+ STDERR.puts("Unknown element #{ element }.")
+ o = Documentation.new # which accepts any element.
+ end
+ o.parent = parent
+ end
+ attrs.each do |key, value|
+ attr = unless /:/ =~ key
+ XSD::QName.new(nil, key)
+ else
+ ns.parse(key)
+ end
+ value_ele = if /:/ !~ value
+ value
+ elsif /^http:\/\// =~ value # ToDo: ugly.
+ value
+ else
+ begin
+ ns.parse(value)
+ rescue
+ value
+ end
+ end
+ unless o.parse_attr(attr, value_ele)
+ STDERR.puts("Unknown attr #{ attr }.")
+ # raise UnknownAttributeError.new("Unknown attr #{ attr }.")
+ end
+ end
+ o
+ end
+
+ def decode_tag_end(ns, node)
+ node.parse_epilogue
+ end
+
+ def decode_text(ns, text)
+ @textbuf << text
+ end
+end
+
+
+end
diff --git a/lib/wsdl/part.rb b/lib/wsdl/part.rb
new file mode 100644
index 0000000000..2aeb457c4e
--- /dev/null
+++ b/lib/wsdl/part.rb
@@ -0,0 +1,63 @@
+=begin
+WSDL4R - WSDL part definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Part < Info
+ attr_reader :name # required
+ attr_reader :element # optional
+ attr_reader :type # optional
+
+ def initialize
+ super
+ @name = nil
+ @element = nil
+ @type = nil
+ end
+
+ def parse_element(element)
+ case element
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = value
+ when ElementAttrName
+ @element = value
+ when TypeAttrName
+ @type = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/port.rb b/lib/wsdl/port.rb
new file mode 100644
index 0000000000..b389f6ca02
--- /dev/null
+++ b/lib/wsdl/port.rb
@@ -0,0 +1,95 @@
+=begin
+WSDL4R - WSDL port definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Port < Info
+ attr_reader :name # required
+ attr_reader :binding # required
+ attr_reader :soap_address
+
+ def initialize
+ super
+ @name = nil
+ @binding = nil
+ @soap_address = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def porttype
+ root.porttype(find_binding.type)
+ end
+
+ def find_binding
+ root.binding(@binding)
+ end
+
+ def inputoperation_map
+ result = {}
+ find_binding.operations.each do |op_bind|
+ op_info = op_bind.soapoperation.input_info
+ result[op_info.op_name] = op_info
+ end
+ result
+ end
+
+ def outputoperation_map
+ result = {}
+ find_binding.operations.each do |op_bind|
+ op_info = op_bind.soapoperation.output_info
+ result[op_info.op_name] = op_info
+ end
+ result
+ end
+
+ def parse_element(element)
+ case element
+ when SOAPAddressName
+ o = WSDL::SOAP::Address.new
+ @soap_address = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ when BindingAttrName
+ @binding = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/portType.rb b/lib/wsdl/portType.rb
new file mode 100644
index 0000000000..b3a99b3bc0
--- /dev/null
+++ b/lib/wsdl/portType.rb
@@ -0,0 +1,83 @@
+=begin
+WSDL4R - WSDL portType definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+
+
+class PortType < Info
+ attr_reader :name # required
+ attr_reader :operations
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def initialize
+ super
+ @name = nil
+ @operations = XSD::NamedElements.new
+ end
+
+ def find_binding
+ root.bindings.find { |item| item.type == @name }
+ end
+
+ def locations
+ bind_name = find_binding.name
+ result = []
+ root.services.each do |service|
+ service.ports.each do |port|
+ if port.binding == bind_name
+ result << port.soap_address.location if port.soap_address
+ end
+ end
+ end
+ result
+ end
+
+ def parse_element(element)
+ case element
+ when OperationName
+ o = Operation.new
+ @operations << o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/service.rb b/lib/wsdl/service.rb
new file mode 100644
index 0000000000..efaeaa727a
--- /dev/null
+++ b/lib/wsdl/service.rb
@@ -0,0 +1,72 @@
+=begin
+WSDL4R - WSDL service definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+
+
+class Service < Info
+ attr_reader :name # required
+ attr_reader :ports
+ attr_reader :soap_address
+
+ def initialize
+ super
+ @name = nil
+ @ports = XSD::NamedElements.new
+ @soap_address = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def parse_element(element)
+ case element
+ when PortName
+ o = Port.new
+ @ports << o
+ o
+ when SOAPAddressName
+ o = WSDL::SOAP::Address.new
+ @soap_address = o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
diff --git a/lib/wsdl/soap/address.rb b/lib/wsdl/soap/address.rb
new file mode 100644
index 0000000000..759918c95b
--- /dev/null
+++ b/lib/wsdl/soap/address.rb
@@ -0,0 +1,51 @@
+=begin
+WSDL4R - WSDL SOAP address definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Address < Info
+ attr_reader :location
+
+ def initialize
+ super
+ @location = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when LocationAttrName
+ @location = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/binding.rb b/lib/wsdl/soap/binding.rb
new file mode 100644
index 0000000000..e9ba3a48d1
--- /dev/null
+++ b/lib/wsdl/soap/binding.rb
@@ -0,0 +1,59 @@
+=begin
+WSDL4R - WSDL SOAP binding definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Binding < Info
+ attr_reader :style
+ attr_reader :transport
+
+ def initialize
+ super
+ @style = nil
+ @transport = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when StyleAttrName
+ if ["document", "rpc"].include?(value)
+ @style = value.intern
+ else
+ raise AttributeConstraintError.new("Unexpected value #{ value }.")
+ end
+ when TransportAttrName
+ @transport = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/body.rb b/lib/wsdl/soap/body.rb
new file mode 100644
index 0000000000..f209622410
--- /dev/null
+++ b/lib/wsdl/soap/body.rb
@@ -0,0 +1,63 @@
+=begin
+WSDL4R - WSDL SOAP body definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Body < Info
+ attr_reader :parts
+ attr_reader :use # required
+ attr_reader :encodingstyle
+ attr_reader :namespace
+
+ def initialize
+ super
+ @parts = nil
+ @use = nil
+ @encodingstyle = nil
+ @namespace = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when PartsAttrName
+ @parts = value
+ when UseAttrName
+ @use = value
+ when EncodingStyleAttrName
+ @encodingstyle = value
+ when NamespaceAttrName
+ @namespace = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/complexType.rb b/lib/wsdl/soap/complexType.rb
new file mode 100644
index 0000000000..f47ddee449
--- /dev/null
+++ b/lib/wsdl/soap/complexType.rb
@@ -0,0 +1,96 @@
+=begin
+WSDL4R - SOAP complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/xmlSchema/complexType'
+
+
+module WSDL
+module XMLSchema
+
+
+class ComplexType < Info
+ def compoundtype
+ @compoundtype ||= check_type
+ end
+
+ def check_type
+ if content
+ :TYPE_STRUCT
+ elsif complexcontent and complexcontent.base == ::SOAP::ValueArrayName
+ :TYPE_ARRAY
+ else
+ raise NotImplementedError.new("Unknown kind of complexType.")
+ end
+ end
+
+ def child_type(name = nil)
+ case compoundtype
+ when :TYPE_STRUCT
+ if ele = find_element(name)
+ ele.type
+ elsif ele = find_element_by_name(name.name)
+ ele.type
+ else
+ nil
+ end
+ when :TYPE_ARRAY
+ @contenttype ||= content_arytype
+ end
+ end
+
+ def child_defined_complextype(name)
+ unless compoundtype == :TYPE_STRUCT
+ raise RuntimeError.new("Assert: not for struct")
+ end
+ unless ele = find_element(name)
+ if name.namespace.nil?
+ ele = find_element_by_name(name.name)
+ end
+ end
+ unless ele
+ raise RuntimeError.new("Cannot find #{name} as a children of #{@name}.")
+ end
+ ele.local_complextype
+ end
+
+ def find_arytype
+ complexcontent.attributes.each do |attribute|
+ if attribute.ref == ::SOAP::AttrArrayTypeName
+ return attribute.arytype
+ end
+ end
+ nil
+ end
+
+private
+
+ def content_arytype
+ unless compoundtype == :TYPE_ARRAY
+ raise RuntimeError.new("Assert: not for array")
+ end
+ arytype = find_arytype
+ ns = arytype.namespace
+ name = arytype.name.sub(/\[(?:,)*\]$/, '')
+ XSD::QName.new(ns, name)
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/data.rb b/lib/wsdl/soap/data.rb
new file mode 100644
index 0000000000..301ae9951d
--- /dev/null
+++ b/lib/wsdl/soap/data.rb
@@ -0,0 +1,52 @@
+=begin
+WSDL4R - WSDL SOAP binding data definitions.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'wsdl/soap/definitions'
+require 'wsdl/soap/binding'
+require 'wsdl/soap/operation'
+require 'wsdl/soap/body'
+require 'wsdl/soap/header'
+require 'wsdl/soap/headerfault'
+require 'wsdl/soap/fault'
+require 'wsdl/soap/address'
+require 'wsdl/soap/complexType'
+
+
+module WSDL
+module SOAP
+
+
+HeaderFaultName = XSD::QName.new(SOAPBindingNamespace, 'headerfault')
+
+LocationAttrName = XSD::QName.new(nil, 'location')
+StyleAttrName = XSD::QName.new(nil, 'style')
+TransportAttrName = XSD::QName.new(nil, 'transport')
+UseAttrName = XSD::QName.new(nil, 'use')
+PartsAttrName = XSD::QName.new(nil, 'parts')
+PartAttrName = XSD::QName.new(nil, 'part')
+NameAttrName = XSD::QName.new(nil, 'name')
+MessageAttrName = XSD::QName.new(nil, 'message')
+EncodingStyleAttrName = XSD::QName.new(nil, 'encodingStyle')
+NamespaceAttrName = XSD::QName.new(nil, 'namespace')
+SOAPActionAttrName = XSD::QName.new(nil, 'soapAction')
+
+
+end
+end
diff --git a/lib/wsdl/soap/definitions.rb b/lib/wsdl/soap/definitions.rb
new file mode 100644
index 0000000000..08df0dcc68
--- /dev/null
+++ b/lib/wsdl/soap/definitions.rb
@@ -0,0 +1,130 @@
+=begin
+WSDL4R - WSDL additional definitions for SOAP.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+require 'soap/mapping'
+
+
+module WSDL
+
+
+class Definitions < Info
+ def soap_rpc_complextypes(binding)
+ types = rpc_operation_complextypes(binding)
+ types << array_complextype
+ types << fault_complextype
+ types << exception_complextype
+ types
+ end
+
+private
+
+ def rpc_operation_complextypes(binding)
+ types = XSD::NamedElements.new
+ binding.operations.each do |op_bind|
+ if op_bind_rpc?(op_bind)
+ operation = op_bind.find_operation
+ if op_bind.input
+ type = XMLSchema::ComplexType.new(operation_input_name(operation))
+ message = messages[operation.input.message]
+ type.sequence_elements = elements_from_message(message)
+ types << type
+ end
+ if op_bind.output
+ type = XMLSchema::ComplexType.new(operation_output_name(operation))
+ message = messages[operation.output.message]
+ type.sequence_elements = elements_from_message(message)
+ types << type
+ end
+ end
+ end
+ types
+ end
+
+ def operation_input_name(operation)
+ operation.input.name || operation.name
+ end
+
+ def operation_output_name(operation)
+ operation.output.name ||
+ XSD::QName.new(operation.name.namespace, operation.name.name + "Response")
+ end
+
+ def op_bind_rpc?(op_bind)
+ op_bind.soapoperation and op_bind.soapoperation.operation_style == :rpc
+ end
+
+ def elements_from_message(message)
+ message.parts.collect { |part|
+ qname = XSD::QName.new(nil, part.name)
+ XMLSchema::Element.new(qname, part.type)
+ }
+ end
+
+ def array_complextype
+ type = XMLSchema::ComplexType.new(::SOAP::ValueArrayName)
+ type.complexcontent = XMLSchema::ComplexContent.new
+ type.complexcontent.base = ::SOAP::ValueArrayName
+ attr = XMLSchema::Attribute.new
+ attr.ref = ::SOAP::AttrArrayTypeName
+ anytype = XSD::AnyTypeName.dup
+ anytype.name += '[]'
+ attr.arytype = anytype
+ type.complexcontent.attributes << attr
+ type
+ end
+
+=begin
+<xs:complexType name="Fault" final="extension">
+ <xs:sequence>
+ <xs:element name="faultcode" type="xs:QName" />
+ <xs:element name="faultstring" type="xs:string" />
+ <xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
+ <xs:element name="detail" type="tns:detail" minOccurs="0" />
+ </xs:sequence>
+</xs:complexType>
+=end
+ def fault_complextype
+ type = XMLSchema::ComplexType.new(::SOAP::EleFaultName)
+ faultcode = XMLSchema::Element.new(::SOAP::EleFaultCodeName, XSD::XSDQName::Type)
+ faultstring = XMLSchema::Element.new(::SOAP::EleFaultStringName, XSD::XSDString::Type)
+ faultactor = XMLSchema::Element.new(::SOAP::EleFaultActorName, XSD::XSDAnyURI::Type)
+ faultactor.minoccurs = 0
+ detail = XMLSchema::Element.new(::SOAP::EleFaultDetailName, XSD::AnyTypeName)
+ detail.minoccurs = 0
+ type.all_elements = [faultcode, faultstring, faultactor, detail]
+ type.final = 'extension'
+ type
+ end
+
+ def exception_complextype
+ type = XMLSchema::ComplexType.new(XSD::QName.new(
+ ::SOAP::Mapping::RubyCustomTypeNamespace, 'SOAPException'))
+ excn_name = XMLSchema::Element.new(XSD::QName.new(nil, 'exceptionTypeName'), XSD::XSDString::Type)
+ cause = XMLSchema::Element.new(XSD::QName.new(nil, 'cause'), XSD::AnyTypeName)
+ backtrace = XMLSchema::Element.new(XSD::QName.new(nil, 'backtrace'), ::SOAP::ValueArrayName)
+ message = XMLSchema::Element.new(XSD::QName.new(nil, 'message'), XSD::XSDString::Type)
+ type.all_elements = [excn_name, cause, backtrace, message]
+ type
+ end
+end
+
+
+end
diff --git a/lib/wsdl/soap/fault.rb b/lib/wsdl/soap/fault.rb
new file mode 100644
index 0000000000..eb57cb0233
--- /dev/null
+++ b/lib/wsdl/soap/fault.rb
@@ -0,0 +1,63 @@
+=begin
+WSDL4R - WSDL SOAP body definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Fault < Info
+ attr_reader :name # required
+ attr_reader :use # required
+ attr_reader :encodingstyle
+ attr_reader :namespace
+
+ def initialize
+ super
+ @name = nil
+ @use = nil
+ @encodingstyle = nil
+ @namespace = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ @name = value
+ when UseAttrName
+ @use = value
+ when EncodingStyleAttrName
+ @encodingstyle = value
+ when NamespaceAttrName
+ @namespace = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/header.rb b/lib/wsdl/soap/header.rb
new file mode 100644
index 0000000000..f779ba5c08
--- /dev/null
+++ b/lib/wsdl/soap/header.rb
@@ -0,0 +1,90 @@
+=begin
+WSDL4R - WSDL SOAP body definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Header < Info
+ attr_reader :headerfault
+
+ attr_reader :message # required
+ attr_reader :part # required
+ attr_reader :use # required
+ attr_reader :encodingstyle
+ attr_reader :namespace
+
+ def initialize
+ super
+ @message = nil
+ @part = nil
+ @use = nil
+ @encodingstyle = nil
+ @namespace = nil
+ @headerfault = nil
+ end
+
+ def find_message
+ root.message(@message)
+ end
+
+ def find_part
+ find_message.parts.each do |part|
+ if part.name == @part
+ return part
+ end
+ end
+ nil
+ end
+
+ def parse_element(element)
+ case element
+ when HeaderFaultName
+ o = WSDL::SOAP::HeaderFault.new
+ @headerfault = o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MessageAttrName
+ @message = value
+ when PartAttrName
+ @part = value
+ when UseAttrName
+ @use = value
+ when EncodingStyleAttrName
+ @encodingstyle = value
+ when NamespaceAttrName
+ @namespace = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/headerfault.rb b/lib/wsdl/soap/headerfault.rb
new file mode 100644
index 0000000000..c0d58e2230
--- /dev/null
+++ b/lib/wsdl/soap/headerfault.rb
@@ -0,0 +1,67 @@
+=begin
+WSDL4R - WSDL SOAP body definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class HeaderFault < Info
+ attr_reader :message # required
+ attr_reader :part # required
+ attr_reader :use # required
+ attr_reader :encodingstyle
+ attr_reader :namespace
+
+ def initialize
+ super
+ @message = nil
+ @part = nil
+ @use = nil
+ @encodingstyle = nil
+ @namespace = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MessageAttrName
+ @message = value
+ when PartAttrName
+ @part = value
+ when UseAttrName
+ @use = value
+ when EncodingStyleAttrName
+ @encodingstyle = value
+ when NamespaceAttrName
+ @namespace = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/soap/operation.rb b/lib/wsdl/soap/operation.rb
new file mode 100644
index 0000000000..2e88522f5c
--- /dev/null
+++ b/lib/wsdl/soap/operation.rb
@@ -0,0 +1,131 @@
+=begin
+WSDL4R - WSDL SOAP operation definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module SOAP
+
+
+class Operation < Info
+ class OperationInfo
+ attr_reader :style
+ attr_reader :op_name
+ attr_reader :optype_name
+ attr_reader :headerparts
+ attr_reader :bodyparts
+ attr_reader :faultpart
+ attr_reader :soapaction
+
+ def initialize(style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction)
+ @style = style
+ @op_name = op_name
+ @optype_name = optype_name
+ @headerparts = headerparts
+ @bodyparts = bodyparts
+ @faultpart = faultpart
+ @soapaction = soapaction
+ end
+ end
+
+ attr_reader :soapaction
+ attr_reader :style
+
+ def initialize
+ super
+ @soapaction = nil
+ @style = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when StyleAttrName
+ if ["document", "rpc"].include?(value)
+ @style = value.intern
+ else
+ raise AttributeConstraintError.new("Unexpected value #{ value }.")
+ end
+ when SOAPActionAttrName
+ @soapaction = value
+ else
+ nil
+ end
+ end
+
+ def input_info
+ name_info = parent.find_operation.input_info
+ param_info(name_info, parent.input)
+ end
+
+ def output_info
+ name_info = parent.find_operation.output_info
+ param_info(name_info, parent.output)
+ end
+
+ def operation_style
+ return @style if @style
+ if parent_binding.soapbinding
+ return parent_binding.soapbinding.style
+ end
+ nil
+ end
+
+private
+
+ def parent_binding
+ parent.parent
+ end
+
+ def param_info(name_info, param)
+ op_name = name_info.op_name
+ optype_name = name_info.optype_name
+
+ soapheader = param.soapheader
+ headerparts = soapheader.collect { |item| item.find_part }
+
+ soapbody = param.soapbody
+ if soapbody.encodingstyle and
+ soapbody.encodingstyle != ::SOAP::EncodingNamespace
+ raise NotImplementedError.new(
+ "EncodingStyle '#{ soapbody.encodingstyle }' not supported.")
+ end
+ if soapbody.namespace
+ op_name = op_name.dup
+ op_name.namespace = soapbody.namespace
+ end
+ if soapbody.parts
+ raise NotImplementedError.new("soap:body parts")
+ else
+ bodyparts = name_info.parts
+ end
+
+ faultpart = nil
+ soapaction = parent.soapoperation.soapaction
+ OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction)
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/types.rb b/lib/wsdl/types.rb
new file mode 100644
index 0000000000..420ab8d387
--- /dev/null
+++ b/lib/wsdl/types.rb
@@ -0,0 +1,54 @@
+=begin
+WSDL4R - WSDL types definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+
+
+class Types < Info
+ attr_reader :schemas
+
+ def initialize
+ super
+ @schemas = []
+ end
+
+ def parse_element(element)
+ case element
+ when SchemaName
+ o = XMLSchema::Schema.new
+ @schemas << o
+ o
+ when DocumentationName
+ o = Documentation.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ nil
+ end
+end
+
+
+end
diff --git a/lib/wsdl/wsdl.rb b/lib/wsdl/wsdl.rb
new file mode 100644
index 0000000000..23fd764065
--- /dev/null
+++ b/lib/wsdl/wsdl.rb
@@ -0,0 +1,34 @@
+=begin
+WSDL4R - Base definitions.
+Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+
+
+module WSDL
+
+
+Version = '0.0.2'
+
+Namespace = 'http://schemas.xmlsoap.org/wsdl/'
+SOAPBindingNamespace ='http://schemas.xmlsoap.org/wsdl/soap/'
+
+class Error < StandardError; end
+
+
+end
diff --git a/lib/wsdl/xmlSchema/all.rb b/lib/wsdl/xmlSchema/all.rb
new file mode 100644
index 0000000000..7db0fbc939
--- /dev/null
+++ b/lib/wsdl/xmlSchema/all.rb
@@ -0,0 +1,76 @@
+=begin
+WSDL4R - XMLSchema complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class All < Info
+ attr_reader :minoccurs
+ attr_reader :maxoccurs
+ attr_reader :elements
+
+ def initialize
+ super()
+ @minoccurs = 1
+ @maxoccurs = 1
+ @elements = []
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def <<(element)
+ @elements << element
+ end
+
+ def parse_element(element)
+ case element
+ when AnyName
+ o = Any.new
+ @elements << o
+ o
+ when ElementName
+ o = Element.new
+ @elements << o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MaxOccursAttrName
+ @maxoccurs = value
+ when MinOccursAttrName
+ @minoccurs = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/any.rb b/lib/wsdl/xmlSchema/any.rb
new file mode 100644
index 0000000000..46904c4107
--- /dev/null
+++ b/lib/wsdl/xmlSchema/any.rb
@@ -0,0 +1,67 @@
+=begin
+WSDL4R - XMLSchema any definition for WSDL.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Any < Info
+ attr_accessor :maxoccurs
+ attr_accessor :minoccurs
+ attr_accessor :namespace
+ attr_accessor :process_contents
+
+ def initialize
+ super()
+ @maxoccurs = 1
+ @minoccurs = 1
+ @namespace = '##any'
+ @process_contents = 'strict'
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MaxOccursAttrName
+ @maxoccurs = value
+ when MinOccursAttrName
+ @minoccurs = value
+ when NamespaceAttrName
+ @namespace = value
+ when ProcessContentsAttrName
+ @process_contents = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/attribute.rb b/lib/wsdl/xmlSchema/attribute.rb
new file mode 100644
index 0000000000..08cc9e931b
--- /dev/null
+++ b/lib/wsdl/xmlSchema/attribute.rb
@@ -0,0 +1,85 @@
+=begin
+WSDL4R - XMLSchema attribute definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Attribute < Info
+ attr_accessor :ref
+ attr_accessor :use
+ attr_accessor :form
+ attr_accessor :name
+ attr_accessor :type
+ attr_accessor :default
+ attr_accessor :fixed
+
+ attr_accessor :arytype
+
+ def initialize
+ super
+ @ref = nil
+ @use = nil
+ @form = nil
+ @name = nil
+ @type = nil
+ @default = nil
+ @fixed = nil
+
+ @arytype = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when RefAttrName
+ @ref = value
+ when UseAttrName
+ @use = value
+ when FormAttrName
+ @form = value
+ when NameAttrName
+ @name = value
+ when TypeAttrName
+ @type = value
+ when DefaultAttrName
+ @default = value
+ when FixedAttrName
+ @fixed = value
+ when ArrayTypeAttrName
+ @arytype = if value.is_a?(XSD::QName)
+ value
+ else
+ XSD::QName.new(XSD::Namespace, value)
+ end
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/choice.rb b/lib/wsdl/xmlSchema/choice.rb
new file mode 100644
index 0000000000..f31e93b3f1
--- /dev/null
+++ b/lib/wsdl/xmlSchema/choice.rb
@@ -0,0 +1,76 @@
+=begin
+WSDL4R - XMLSchema complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Choice < Info
+ attr_reader :minoccurs
+ attr_reader :maxoccurs
+ attr_reader :elements
+
+ def initialize
+ super()
+ @minoccurs = 1
+ @maxoccurs = 1
+ @elements = []
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def <<(element)
+ @elements << element
+ end
+
+ def parse_element(element)
+ case element
+ when AnyName
+ o = Any.new
+ @elements << o
+ o
+ when ElementName
+ o = Element.new
+ @elements << o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MaxOccursAttrName
+ @maxoccurs = value
+ when MinOccursAttrName
+ @minoccurs = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/complexContent.rb b/lib/wsdl/xmlSchema/complexContent.rb
new file mode 100644
index 0000000000..79c231ac2d
--- /dev/null
+++ b/lib/wsdl/xmlSchema/complexContent.rb
@@ -0,0 +1,90 @@
+=begin
+WSDL4R - XMLSchema complexContent definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+module XMLSchema
+
+
+class ComplexContent < Info
+ attr_accessor :base
+ attr_reader :derivetype
+ attr_reader :content
+ attr_reader :attributes
+
+ def initialize
+ super
+ @base = nil
+ @derivetype = nil
+ @content = nil
+ @attributes = XSD::NamedElements.new
+ end
+
+ def parse_element(element)
+ case element
+ when RestrictionName, ExtensionName
+ @derivetype = element.name
+ self
+ when AllName
+ if @derivetype.nil?
+ raise Parser::ElementConstraintError.new("base attr not found.")
+ end
+ @content = All.new
+ @content
+ when SequenceName
+ if @derivetype.nil?
+ raise Parser::ElementConstraintError.new("base attr not found.")
+ end
+ @content = Sequence.new
+ @content
+ when ChoiceName
+ if @derivetype.nil?
+ raise Parser::ElementConstraintError.new("base attr not found.")
+ end
+ @content = Choice.new
+ @content
+ when AttributeName
+ if @derivetype.nil?
+ raise Parser::ElementConstraintError.new("base attr not found.")
+ end
+ o = Attribute.new
+ @attributes << o
+ o
+ end
+ end
+
+ def parse_attr(attr, value)
+ if @derivetype.nil?
+ return nil
+ end
+ case attr
+ when BaseAttrName
+ @base = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/complexType.rb b/lib/wsdl/xmlSchema/complexType.rb
new file mode 100644
index 0000000000..c34be3e57b
--- /dev/null
+++ b/lib/wsdl/xmlSchema/complexType.rb
@@ -0,0 +1,130 @@
+=begin
+WSDL4R - XMLSchema complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'wsdl/xmlSchema/content'
+require 'xsd/namedelements'
+
+
+module WSDL
+module XMLSchema
+
+
+class ComplexType < Info
+ attr_accessor :name
+ attr_accessor :complexcontent
+ attr_accessor :content
+ attr_accessor :final
+ attr_accessor :mixed
+ attr_reader :attributes
+
+ def initialize(name = nil)
+ super()
+ @name = name
+ @complexcontent = nil
+ @content = nil
+ @final = nil
+ @mixed = false
+ @attributes = XSD::NamedElements.new
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def each_element
+ if @content
+ @content.elements.each do |element|
+ yield(element.name, element)
+ end
+ end
+ end
+
+ def find_element(name)
+ if @content
+ @content.elements.each do |element|
+ return element if name == element.name
+ end
+ end
+ nil
+ end
+
+ def find_element_by_name(name)
+ if @content
+ @content.elements.each do |element|
+ return element if name == element.name.name
+ end
+ end
+ nil
+ end
+
+ def sequence_elements=(elements)
+ @content = Sequence.new
+ elements.each do |element|
+ @content << element
+ end
+ end
+
+ def all_elements=(elements)
+ @content = All.new
+ elements.each do |element|
+ @content << element
+ end
+ end
+
+ def parse_element(element)
+ case element
+ when AllName
+ @content = All.new
+ @content
+ when SequenceName
+ @content = Sequence.new
+ @content
+ when ChoiceName
+ @content = Choice.new
+ @content
+ when ComplexContentName
+ @complexcontent = ComplexContent.new
+ @complexcontent
+ when AttributeName
+ o = Attribute.new
+ @attributes << o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when FinalAttrName
+ @final = value
+ when MixedAttrName
+ @mixed = (value == 'true')
+ when NameAttrName
+ @name = XSD::QName.new(targetnamespace, value)
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/content.rb b/lib/wsdl/xmlSchema/content.rb
new file mode 100644
index 0000000000..a1bd302701
--- /dev/null
+++ b/lib/wsdl/xmlSchema/content.rb
@@ -0,0 +1,107 @@
+=begin
+WSDL4R - XMLSchema complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Content < Info
+ attr_accessor :final
+ attr_accessor :mixed
+ attr_accessor :type
+ attr_reader :contents
+ attr_reader :elements
+
+ def initialize
+ super()
+ @final = nil
+ @mixed = false
+ @type = nil
+ @contents = []
+ @elements = []
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def <<(content)
+ @contents << content
+ update_elements
+ end
+
+ def each
+ @contents.each do |content|
+ yield content
+ end
+ end
+
+ def parse_element(element)
+ case element
+ when AllName, SequenceName, ChoiceName
+ o = Content.new
+ o.type = element.name
+ @contents << o
+ o
+ when AnyName
+ o = Any.new
+ @contents << o
+ o
+ when ElementName
+ o = Element.new
+ @contents << o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when FinalAttrName
+ @final = value
+ when MixedAttrName
+ @mixed = (value == 'true')
+ else
+ nil
+ end
+ end
+
+ def parse_epilogue
+ update_elements
+ end
+
+private
+
+ def update_elements
+ @elements = []
+ @contents.each do |content|
+ if content.is_a?(Element)
+ @elements << [content.name, content]
+ end
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/data.rb b/lib/wsdl/xmlSchema/data.rb
new file mode 100644
index 0000000000..9c9820abbd
--- /dev/null
+++ b/lib/wsdl/xmlSchema/data.rb
@@ -0,0 +1,75 @@
+=begin
+WSDL4R - XMLSchema data definitions.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/xmlSchema/schema'
+require 'wsdl/xmlSchema/import'
+require 'wsdl/xmlSchema/complexType'
+require 'wsdl/xmlSchema/complexContent'
+require 'wsdl/xmlSchema/any'
+require 'wsdl/xmlSchema/element'
+require 'wsdl/xmlSchema/all'
+require 'wsdl/xmlSchema/choice'
+require 'wsdl/xmlSchema/sequence'
+require 'wsdl/xmlSchema/attribute'
+require 'wsdl/xmlSchema/unique'
+
+
+module WSDL
+module XMLSchema
+
+
+AllName = XSD::QName.new(XSD::Namespace, 'all')
+AnyName = XSD::QName.new(XSD::Namespace, 'any')
+ArrayTypeAttrName = XSD::QName.new(Namespace, 'arrayType')
+AttributeName = XSD::QName.new(XSD::Namespace, 'attribute')
+ChoiceName = XSD::QName.new(XSD::Namespace, 'choice')
+ComplexContentName = XSD::QName.new(XSD::Namespace, 'complexContent')
+ComplexTypeName = XSD::QName.new(XSD::Namespace, 'complexType')
+ElementName = XSD::QName.new(XSD::Namespace, 'element')
+ExtensionName = XSD::QName.new(XSD::Namespace, 'extension')
+ImportName = XSD::QName.new(XSD::Namespace, 'import')
+RestrictionName = XSD::QName.new(XSD::Namespace, 'restriction')
+SequenceName = XSD::QName.new(XSD::Namespace, 'sequence')
+SchemaName = XSD::QName.new(XSD::Namespace, 'schema')
+SimpleTypeName = XSD::QName.new(XSD::Namespace, 'simpleType')
+UniqueName = XSD::QName.new(XSD::Namespace, 'unique')
+
+AttributeFormDefaultAttrName = XSD::QName.new(nil, 'attributeFormDefault')
+BaseAttrName = XSD::QName.new(nil, 'base')
+DefaultAttrName = XSD::QName.new(nil, 'default')
+ElementFormDefaultAttrName = XSD::QName.new(nil, 'elementFormDefault')
+FinalAttrName = XSD::QName.new(nil, 'final')
+FixedAttrName = XSD::QName.new(nil, 'fixed')
+FormAttrName = XSD::QName.new(nil, 'form')
+IdAttrName = XSD::QName.new(nil, 'id')
+MaxOccursAttrName = XSD::QName.new(nil, 'maxOccurs')
+MinOccursAttrName = XSD::QName.new(nil, 'minOccurs')
+MixedAttrName = XSD::QName.new(nil, 'mixed')
+NameAttrName = XSD::QName.new(nil, 'name')
+NamespaceAttrName = XSD::QName.new(nil, 'namespace')
+NillableAttrName = XSD::QName.new(nil, 'nillable')
+RefAttrName = XSD::QName.new(nil, 'ref')
+SchemaLocationAttrName = XSD::QName.new(nil, 'schemaLocation')
+TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace')
+TypeAttrName = XSD::QName.new(nil, 'type')
+UseAttrName = XSD::QName.new(nil, 'use')
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/element.rb b/lib/wsdl/xmlSchema/element.rb
new file mode 100644
index 0000000000..d6d17c08cf
--- /dev/null
+++ b/lib/wsdl/xmlSchema/element.rb
@@ -0,0 +1,115 @@
+=begin
+WSDL4R - XMLSchema element definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Element < Info
+ attr_accessor :name # required
+ attr_accessor :type
+ attr_accessor :local_complextype
+ attr_accessor :constraint
+ attr_accessor :maxoccurs
+ attr_accessor :minoccurs
+ attr_accessor :nillable
+
+ def initialize(name = nil, type = XSD::AnyTypeName)
+ super()
+ @name = name
+ @type = type
+ @local_complextype = nil
+ @constraint = nil
+ @maxoccurs = 1
+ @minoccurs = 1
+ @nillable = nil
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def parse_element(element)
+ case element
+ when ComplexTypeName
+ @type = nil
+ @local_complextype = ComplexType.new
+ @local_complextype
+ when UniqueName
+ @constraint = Unique.new
+ @constraint
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NameAttrName
+ #@name = XSD::QName.new(nil, value)
+ @name = XSD::QName.new(targetnamespace, value)
+ when TypeAttrName
+ @type = if value.is_a?(XSD::QName)
+ value
+ else
+ XSD::QName.new(XSD::Namespace, value)
+ end
+ when MaxOccursAttrName
+ case parent
+ when All
+ if value != '1'
+ raise Parser::AttrConstraintError.new(
+ "Cannot parse #{ value } for #{ attr }.")
+ end
+ @maxoccurs = value
+ when Sequence
+ @maxoccurs = value
+ else
+ raise NotImplementedError.new
+ end
+ @maxoccurs
+ when MinOccursAttrName
+ case parent
+ when All
+ if ['0', '1'].include?(value)
+ @minoccurs = value
+ else
+ raise Parser::AttrConstraintError.new(
+ "Cannot parse #{ value } for #{ attr }.")
+ end
+ when Sequence
+ @minoccurs = value
+ else
+ raise NotImplementedError.new
+ end
+ @minoccurs
+ when NillableAttrName
+ @nillable = (value == 'true')
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/import.rb b/lib/wsdl/xmlSchema/import.rb
new file mode 100644
index 0000000000..2267125a70
--- /dev/null
+++ b/lib/wsdl/xmlSchema/import.rb
@@ -0,0 +1,55 @@
+=begin
+WSDL4R - XMLSchema import definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Import < Info
+ attr_reader :namespace
+ attr_reader :schemalocation
+
+ def initialize
+ super
+ @namespace = nil
+ @schemalocation = nil
+ end
+
+ def parse_element(element)
+ nil
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when NamespaceAttrName
+ @namespace = value
+ when SchemaLocationAttrName
+ @schemalocation = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/parser.rb b/lib/wsdl/xmlSchema/parser.rb
new file mode 100644
index 0000000000..6e893cdc7e
--- /dev/null
+++ b/lib/wsdl/xmlSchema/parser.rb
@@ -0,0 +1,172 @@
+=begin
+WSDL4R - WSDL XML Instance parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'xsd/ns'
+require 'xsd/charset'
+require 'xsd/datatypes'
+require 'xsd/xmlparser'
+require 'wsdl/xmlSchema/data'
+
+
+module WSDL
+module XMLSchema
+
+
+class Parser
+ include XSD
+
+ class ParseError < Error; end
+ class FormatDecodeError < Error; end
+ class UnknownElementError < FormatDecodeError; end
+ class UnknownAttributeError < FormatDecodeError; end
+ class UnexpectedElementError < FormatDecodeError; end
+ class ElementConstraintError < FormatDecodeError; end
+ class AttributeConstraintError < FormatDecodeError; end
+
+private
+
+ class ParseFrame
+ attr_reader :ns
+ attr_reader :name
+ attr_accessor :node
+
+ private
+
+ def initialize(ns, name, node)
+ @ns = ns
+ @name = name
+ @node = node
+ end
+ end
+
+public
+
+ def initialize(opt = {})
+ @parser = XSD::XMLParser.create_parser(self, opt)
+ @parsestack = nil
+ @lastnode = nil
+ end
+
+ def parse(string_or_readable)
+ @parsestack = []
+ @lastnode = nil
+ @textbuf = ''
+ @parser.do_parse(string_or_readable)
+ @lastnode
+ end
+
+ def charset
+ @parser.charset
+ end
+
+ def start_element(name, attrs)
+ lastframe = @parsestack.last
+ ns = parent = nil
+ if lastframe
+ ns = lastframe.ns.clone_ns
+ parent = lastframe.node
+ else
+ ns = XSD::NS.new
+ parent = nil
+ end
+ attrs = XSD::XMLParser.filter_ns(ns, attrs)
+ node = decode_tag(ns, name, attrs, parent)
+ @parsestack << ParseFrame.new(ns, name, node)
+ end
+
+ def characters(text)
+ lastframe = @parsestack.last
+ if lastframe
+ # Need not to be cloned because character does not have attr.
+ ns = lastframe.ns
+ decode_text(ns, text)
+ else
+ p text if $DEBUG
+ end
+ end
+
+ def end_element(name)
+ lastframe = @parsestack.pop
+ unless name == lastframe.name
+ raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.")
+ end
+ decode_tag_end(lastframe.ns, lastframe.node)
+ @lastnode = lastframe.node
+ end
+
+private
+
+ def decode_tag(ns, name, attrs, parent)
+ o = nil
+ element = ns.parse(name)
+ if !parent
+ if element == SchemaName
+ o = Schema.parse_element(element)
+ else
+ raise UnknownElementError.new("Unknown element #{ element }.")
+ end
+ else
+ o = parent.parse_element(element)
+ unless o
+ raise UnknownElementError.new("Unknown element #{ element }.")
+ end
+ o.parent = parent
+ end
+ attrs.each do |key, value|
+ attr = unless /:/ =~ key
+ XSD::QName.new(nil, key)
+ else
+ ns.parse(key)
+ end
+ value_ele = if /:/ !~ value
+ value
+ elsif /^http:\/\// =~ value # ToDo: ugly.
+ value
+ else
+ begin
+ ns.parse(value)
+ rescue
+ value
+ end
+ end
+ if attr == IdAttrName
+ o.id = value_ele
+ else
+ unless o.parse_attr(attr, value_ele)
+ STDERR.puts("Unknown attr #{ attr }.")
+ # raise UnknownAttributeError.new("Unknown attr #{ attr }.")
+ end
+ end
+ end
+ o
+ end
+
+ def decode_tag_end(ns, node)
+ node.parse_epilogue
+ end
+
+ def decode_text(ns, text)
+ @textbuf << text
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/schema.rb b/lib/wsdl/xmlSchema/schema.rb
new file mode 100644
index 0000000000..3a9aa6842e
--- /dev/null
+++ b/lib/wsdl/xmlSchema/schema.rb
@@ -0,0 +1,105 @@
+=begin
+WSDL4R - XMLSchema schema definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+require 'xsd/namedelements'
+
+
+module WSDL
+module XMLSchema
+
+
+class Schema < Info
+ attr_reader :targetnamespace # required
+ attr_reader :complextypes
+ attr_reader :elements
+ attr_reader :attributes
+ attr_reader :imports
+ attr_accessor :attributeformdefault
+ attr_accessor :elementformdefault
+
+ def initialize
+ super
+ @targetnamespace = nil
+ @complextypes = XSD::NamedElements.new
+ @elements = XSD::NamedElements.new
+ @attributes = XSD::NamedElements.new
+ @imports = []
+ @elementformdefault = nil
+ end
+
+ def parse_element(element)
+ case element
+ when ImportName
+ o = Import.new
+ @imports << o
+ o
+ when ComplexTypeName
+ o = ComplexType.new
+ @complextypes << o
+ o
+ when ElementName
+ o = Element.new
+ @elements << o
+ o
+ when AttributeName
+ o = Attribute.new
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when TargetNamespaceAttrName
+ @targetnamespace = value
+ when AttributeFormDefaultAttrName
+ @attributeformdefault = value
+ when ElementFormDefaultAttrName
+ @elementformdefault = value
+ else
+ nil
+ end
+ end
+
+ def collect_elements
+ result = XSD::NamedElements.new
+ result.concat(@elements)
+ result
+ end
+
+ def collect_complextypes
+ result = XSD::NamedElements.new
+ result.concat(@complextypes)
+ result
+ end
+
+ def self.parse_element(element)
+ if element == SchemaName
+ Schema.new
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/sequence.rb b/lib/wsdl/xmlSchema/sequence.rb
new file mode 100644
index 0000000000..fb5ca1aef6
--- /dev/null
+++ b/lib/wsdl/xmlSchema/sequence.rb
@@ -0,0 +1,76 @@
+=begin
+WSDL4R - XMLSchema complexType definition for WSDL.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Sequence < Info
+ attr_reader :minoccurs
+ attr_reader :maxoccurs
+ attr_reader :elements
+
+ def initialize
+ super()
+ @minoccurs = 1
+ @maxoccurs = 1
+ @elements = []
+ end
+
+ def targetnamespace
+ parent.targetnamespace
+ end
+
+ def <<(element)
+ @elements << element
+ end
+
+ def parse_element(element)
+ case element
+ when AnyName
+ o = Any.new
+ @elements << o
+ o
+ when ElementName
+ o = Element.new
+ @elements << o
+ o
+ else
+ nil
+ end
+ end
+
+ def parse_attr(attr, value)
+ case attr
+ when MaxOccursAttrName
+ @maxoccurs = value
+ when MinOccursAttrName
+ @minoccurs = value
+ else
+ nil
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/wsdl/xmlSchema/unique.rb b/lib/wsdl/xmlSchema/unique.rb
new file mode 100644
index 0000000000..1d2573f6b0
--- /dev/null
+++ b/lib/wsdl/xmlSchema/unique.rb
@@ -0,0 +1,45 @@
+=begin
+WSDL4R - XMLSchema unique element.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'wsdl/info'
+
+
+module WSDL
+module XMLSchema
+
+
+class Unique < Info
+ def initialize
+ super
+ end
+
+ def parse_element(element)
+ # Accepts any element.
+ self
+ end
+
+ def parse_attr(attr, value)
+ # Accepts any attribute.
+ true
+ end
+end
+
+
+end
+end
diff --git a/lib/xsd/charset.rb b/lib/xsd/charset.rb
new file mode 100644
index 0000000000..6dda959155
--- /dev/null
+++ b/lib/xsd/charset.rb
@@ -0,0 +1,175 @@
+=begin
+XSD4R - Charset handling library.
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module XSD
+
+
+module Charset
+ @encoding = $KCODE
+
+ class XSDError < StandardError; end
+ class CharsetError < XSDError; end
+ class UnknownCharsetError < CharsetError; end
+ class CharsetConversionError < CharsetError; end
+
+public
+
+ ###
+ ## Maps
+ #
+ EncodingConvertMap = {}
+ def Charset.init
+ begin
+ require 'xsd/iconvcharset'
+ @encoding = 'UTF8'
+ EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) }
+ EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) }
+ EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift-jis", "euc-jp", str) }
+ if /(mswin|bccwin|mingw|cygwin)/ =~ RUBY_PLATFORM
+ EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("cp932", "utf-8", str) }
+ EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "cp932", str) }
+ EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "cp932", str) }
+ else
+ EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift-jis", "utf-8", str) }
+ EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "shift-jis", str) }
+ EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "shift-jis", str) }
+ end
+ rescue LoadError
+ begin
+ require 'nkf'
+ EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| NKF.nkf('-sXm0', str) }
+ EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| NKF.nkf('-eXm0', str) }
+ rescue LoadError
+ end
+
+ begin
+ require 'uconv'
+ @encoding = 'UTF8'
+ EncodingConvertMap[['UTF8', 'EUC' ]] = Uconv.method(:u8toeuc)
+ EncodingConvertMap[['UTF8', 'SJIS']] = Uconv.method(:u8tosjis)
+ EncodingConvertMap[['EUC' , 'UTF8']] = Uconv.method(:euctou8)
+ EncodingConvertMap[['SJIS', 'UTF8']] = Uconv.method(:sjistou8)
+ rescue LoadError
+ end
+ end
+ end
+ self.init
+
+ CharsetMap = {
+ 'NONE' => 'us-ascii',
+ 'EUC' => 'euc-jp',
+ 'SJIS' => 'shift_jis',
+ 'UTF8' => 'utf-8',
+ }
+
+
+ ###
+ ## handlers
+ #
+ def Charset.encoding
+ @encoding
+ end
+
+ def Charset.encoding_label
+ charset_label(@encoding)
+ end
+
+ def Charset.encoding_to_xml(str, charset)
+ encoding_conv(str, @encoding, charset_str(charset))
+ end
+
+ def Charset.encoding_from_xml(str, charset)
+ encoding_conv(str, charset_str(charset), @encoding)
+ end
+
+ def Charset.encoding_conv(str, enc_from, enc_to)
+ if enc_from == enc_to or enc_from == 'NONE' or enc_to == 'NONE'
+ str
+ elsif converter = EncodingConvertMap[[enc_from, enc_to]]
+ converter.call(str)
+ else
+ raise CharsetConversionError.new(
+ "Converter not found: #{ enc_from } -> #{ enc_to }")
+ end
+ end
+
+ def Charset.charset_label(encoding)
+ CharsetMap[encoding.upcase]
+ end
+
+ def Charset.charset_str(label)
+ CharsetMap.index(label.downcase)
+ end
+
+ # Original regexps: http://www.din.or.jp/~ohzaki/perl.htm
+ # ascii_euc = '[\x00-\x7F]'
+ ascii_euc = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted.
+ twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])'
+ threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])'
+ character_euc = "(?:#{ ascii_euc }|#{ twobytes_euc }|#{ threebytes_euc })"
+ EUCRegexp = Regexp.new("\\A#{ character_euc }*\\z", nil, "NONE")
+
+ # onebyte_sjis = '[\x00-\x7F\xA1-\xDF]'
+ onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted.
+ twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'
+ character_sjis = "(?:#{ onebyte_sjis }|#{ twobytes_sjis })"
+ SJISRegexp = Regexp.new("\\A#{ character_sjis }*\\z", nil, "NONE")
+
+ # 0xxxxxxx
+ #ascii_utf8 = '[\0-\x7F]'
+ ascii_utf8 = '[\x9\xA\xD\x20-\x7F]' # XML 1.0 restricted.
+ # 110yyyyy 10xxxxxx
+ twobytes_utf8 = '(?:[\xC0-\xDF][\x80-\xBF])'
+ # 1110zzzz 10yyyyyy 10xxxxxx
+ threebytes_utf8 = '(?:[\xE0-\xEF][\x80-\xBF][\x80-\xBF])'
+ # 11110uuu 10uuuzzz 10yyyyyy 10xxxxxx
+ fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])'
+ character_utf8 = "(?:#{ ascii_utf8 }|#{ twobytes_utf8 }|#{ threebytes_utf8 }|#{ fourbytes_utf8 })"
+ UTF8Regexp = Regexp.new("\\A#{ character_utf8 }*\\z", nil, "NONE")
+
+ def Charset.is_utf8(str)
+ UTF8Regexp =~ str
+ end
+
+ def Charset.is_euc(str)
+ EUCRegexp =~ str
+ end
+
+ def Charset.is_sjis(str)
+ SJISRegexp =~ str
+ end
+
+ def Charset.is_ces(str, code = $KCODE)
+ case code
+ when 'NONE'
+ true
+ when 'UTF8'
+ is_utf8(str)
+ when 'EUC'
+ is_euc(str)
+ when 'SJIS'
+ is_sjis(str)
+ else
+ raise UnknownCharsetError.new("Unknown charset: #{ code }")
+ end
+ end
+end
+
+
+end
diff --git a/lib/xsd/datatypes.rb b/lib/xsd/datatypes.rb
new file mode 100644
index 0000000000..03e42d21d2
--- /dev/null
+++ b/lib/xsd/datatypes.rb
@@ -0,0 +1,1094 @@
+=begin
+XSD4R - XML Schema Datatype implementation.
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'xsd/charset'
+require 'uri'
+
+
+###
+## XMLSchamaDatatypes general definitions.
+#
+module XSD
+
+
+Namespace = 'http://www.w3.org/2001/XMLSchema'
+InstanceNamespace = 'http://www.w3.org/2001/XMLSchema-instance'
+
+AttrType = 'type'
+NilValue = 'true'
+
+AnyTypeLiteral = 'anyType'
+AnySimpleTypeLiteral = 'anySimpleType'
+NilLiteral = 'nil'
+StringLiteral = 'string'
+BooleanLiteral = 'boolean'
+DecimalLiteral = 'decimal'
+FloatLiteral = 'float'
+DoubleLiteral = 'double'
+DurationLiteral = 'duration'
+DateTimeLiteral = 'dateTime'
+TimeLiteral = 'time'
+DateLiteral = 'date'
+GYearMonthLiteral = 'gYearMonth'
+GYearLiteral = 'gYear'
+GMonthDayLiteral = 'gMonthDay'
+GDayLiteral = 'gDay'
+GMonthLiteral = 'gMonth'
+HexBinaryLiteral = 'hexBinary'
+Base64BinaryLiteral = 'base64Binary'
+AnyURILiteral = 'anyURI'
+QNameLiteral = 'QName'
+
+NormalizedStringLiteral = 'normalizedString'
+IntegerLiteral = 'integer'
+LongLiteral = 'long'
+IntLiteral = 'int'
+ShortLiteral = 'short'
+
+AttrTypeName = QName.new(InstanceNamespace, AttrType)
+AttrNilName = QName.new(InstanceNamespace, NilLiteral)
+
+AnyTypeName = QName.new(Namespace, AnyTypeLiteral)
+AnySimpleTypeName = QName.new(Namespace, AnySimpleTypeLiteral)
+
+class Error < StandardError; end
+class ValueSpaceError < Error; end
+
+
+###
+## The base class of all datatypes with Namespace.
+#
+class NSDBase
+ @@types = []
+
+ attr_accessor :type
+
+ def self.inherited(klass)
+ @@types << klass
+ end
+
+ def self.types
+ @@types
+ end
+
+ def initialize
+ @type = nil
+ end
+end
+
+
+###
+## The base class of XSD datatypes.
+#
+class XSDAnySimpleType < NSDBase
+ include XSD
+ Type = QName.new(Namespace, AnySimpleTypeLiteral)
+
+ # @data represents canonical space (ex. Integer: 123).
+ attr_reader :data
+ # @is_nil represents this data is nil or not.
+ attr_accessor :is_nil
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ @data = nil
+ @is_nil = true
+ set(value) if value
+ end
+
+ # set accepts a string which follows lexical space (ex. String: "+123"), or
+ # an object which follows canonical space (ex. Integer: 123).
+ def set(value)
+ if value.nil?
+ @is_nil = true
+ @data = nil
+ else
+ @is_nil = false
+ _set(value)
+ end
+ end
+
+ # to_s creates a string which follows lexical space (ex. String: "123").
+ def to_s()
+ if @is_nil
+ ""
+ else
+ _to_s
+ end
+ end
+
+ def trim(data)
+ data.sub(/\A\s*(\S*)\s*\z/, '\1')
+ end
+
+private
+
+ def _set(value)
+ @data = value
+ end
+
+ def _to_s
+ @data.to_s
+ end
+end
+
+class XSDNil < XSDAnySimpleType
+ Type = QName.new(Namespace, NilLiteral)
+ Value = 'true'
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value)
+ end
+
+private
+
+ def _set(value)
+ @data = value
+ end
+end
+
+
+###
+## Primitive datatypes.
+#
+class XSDString < XSDAnySimpleType
+ Type = QName.new(Namespace, StringLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ @encoding = nil
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ unless XSD::Charset.is_ces(value, XSD::Charset.encoding)
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+ @data = value
+ end
+end
+
+class XSDBoolean < XSDAnySimpleType
+ Type = QName.new(Namespace, BooleanLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value)
+ end
+
+private
+
+ def _set(value)
+ if value.is_a?(String)
+ str = trim(value)
+ if str == 'true' || str == '1'
+ @data = true
+ elsif str == 'false' || str == '0'
+ @data = false
+ else
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ else
+ @data = value ? true : false
+ end
+ end
+end
+
+class XSDDecimal < XSDAnySimpleType
+ Type = QName.new(Namespace, DecimalLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ @sign = ''
+ @number = ''
+ @point = 0
+ set(value) if value
+ end
+
+ def nonzero?
+ (@number != '0')
+ end
+
+private
+
+ def _set(d)
+ if d.is_a?(String)
+ # Integer("00012") => 10 in Ruby.
+ d.sub!(/^([+\-]?)0*(?=\d)/, "\\1")
+ end
+ set_str(d)
+ end
+
+ def set_str(str)
+ /^([+\-]?)(\d*)(?:\.(\d*)?)?$/ =~ trim(str.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+
+ @sign = $1 || '+'
+ int_part = $2
+ frac_part = $3
+
+ int_part = '0' if int_part.empty?
+ frac_part = frac_part ? frac_part.sub(/0+$/, '') : ''
+ @point = - frac_part.size
+ @number = int_part + frac_part
+
+ # normalize
+ if @sign == '+'
+ @sign = ''
+ elsif @sign == '-'
+ if @number == '0'
+ @sign = ''
+ end
+ end
+
+ @data = _to_s
+ end
+
+ # 0.0 -> 0; right?
+ def _to_s
+ str = @number.dup
+ if @point.nonzero?
+ str[@number.size + @point, 0] = '.'
+ end
+ @sign + str
+ end
+end
+
+class XSDFloat < XSDAnySimpleType
+ Type = QName.new(Namespace, FloatLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ # "NaN".to_f => 0 in some environment. libc?
+ if value.is_a?(Float)
+ @data = narrow32bit(value)
+ return
+ end
+
+ str = trim(value.to_s)
+ if str == 'NaN'
+ @data = 0.0/0.0
+ elsif str == 'INF'
+ @data = 1.0/0.0
+ elsif str == '-INF'
+ @data = -1.0/0.0
+ else
+ if /^[+\-\.\deE]+$/ !~ str
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ # Float("-1.4E") might fail on some system.
+ str << '0' if /e$/i =~ str
+ begin
+ @data = narrow32bit(Float(str))
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+ end
+
+ # Do I have to convert 0.0 -> 0 and -0.0 -> -0 ?
+ def _to_s
+ if @data.nan?
+ 'NaN'
+ elsif @data.infinite? == 1
+ 'INF'
+ elsif @data.infinite? == -1
+ '-INF'
+ else
+ sprintf("%.10g", @data)
+ end
+ end
+
+ # Convert to single-precision 32-bit floating point value.
+ def narrow32bit(f)
+ if f.nan? || f.infinite?
+ f
+ else
+ packed = [f].pack("f")
+ (/\A\0*\z/ =~ packed)? 0.0 : f
+ end
+ end
+end
+
+# Ruby's Float is double-precision 64-bit floating point value.
+class XSDDouble < XSDAnySimpleType
+ Type = QName.new(Namespace, DoubleLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ # "NaN".to_f => 0 in some environment. libc?
+ if value.is_a?(Float)
+ @data = value
+ return
+ end
+
+ str = trim(value.to_s)
+ if str == 'NaN'
+ @data = 0.0/0.0
+ elsif str == 'INF'
+ @data = 1.0/0.0
+ elsif str == '-INF'
+ @data = -1.0/0.0
+ else
+ begin
+ @data = Float(str)
+ rescue ArgumentError
+ # '1.4e' cannot be parsed on some architecture.
+ if /e\z/i =~ str
+ begin
+ @data = Float(str + '0')
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ else
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+ end
+ end
+
+ # Do I have to convert 0.0 -> 0 and -0.0 -> -0 ?
+ def _to_s
+ if @data.nan?
+ 'NaN'
+ elsif @data.infinite? == 1
+ 'INF'
+ elsif @data.infinite? == -1
+ '-INF'
+ else
+ sprintf("%.16g", @data)
+ end
+ end
+end
+
+class XSDDuration < XSDAnySimpleType
+ Type = QName.new(Namespace, DurationLiteral)
+
+ attr_accessor :sign
+ attr_accessor :year
+ attr_accessor :month
+ attr_accessor :day
+ attr_accessor :hour
+ attr_accessor :min
+ attr_accessor :sec
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ @sign = nil
+ @year = nil
+ @month = nil
+ @day = nil
+ @hour = nil
+ @min = nil
+ @sec = nil
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ /^([+\-]?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ =~ trim(value.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+
+ if ($5 and ((!$2 and !$3 and !$4) or (!$6 and !$7 and !$8)))
+ # Should we allow 'PT5S' here?
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+
+ @sign = $1
+ @year = $2.to_i
+ @month = $3.to_i
+ @day = $4.to_i
+ @hour = $6.to_i
+ @min = $7.to_i
+ @sec = $8 ? XSDDecimal.new($8) : 0
+ @data = _to_s
+ end
+
+ def _to_s
+ str = ''
+ str << @sign if @sign
+ str << 'P'
+ l = ''
+ l << "#{ @year }Y" if @year.nonzero?
+ l << "#{ @month }M" if @month.nonzero?
+ l << "#{ @day }D" if @day.nonzero?
+ r = ''
+ r << "#{ @hour }H" if @hour.nonzero?
+ r << "#{ @min }M" if @min.nonzero?
+ r << "#{ @sec }S" if @sec.nonzero?
+ str << l
+ if l.empty?
+ str << "0D"
+ end
+ unless r.empty?
+ str << "T" << r
+ end
+ str
+ end
+end
+
+
+require 'rational'
+require 'date'
+unless Object.const_defined?('DateTime')
+ raise LoadError.new('XSD4R requires date2/3.2 or later to be installed. You can download it from http://www.funaba.org/en/ruby.html#date2')
+end
+
+module XSDDateTimeImpl
+ SecInDay = 86400 # 24 * 60 * 60
+
+ def to_time
+ begin
+ if @data.of * SecInDay == Time.now.utc_offset
+ d = @data
+ usec = (d.sec_fraction * SecInDay * 1000000).to_f
+ Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec)
+ else
+ d = @data.newof
+ usec = (d.sec_fraction * SecInDay * 1000000).to_f
+ Time.gm(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec)
+ end
+ rescue ArgumentError
+ nil
+ end
+ end
+
+ def tz2of(str)
+ /^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str
+ sign = $1
+ hour = $2.to_i
+ min = $3.to_i
+
+ of = case sign
+ when '+'
+ of = +(hour.to_r * 60 + min) / 1440 # 24 * 60
+ when '-'
+ of = -(hour.to_r * 60 + min) / 1440 # 24 * 60
+ else
+ 0
+ end
+ of
+ end
+
+ def of2tz(offset)
+ diffmin = offset * 24 * 60
+ if diffmin.zero?
+ 'Z'
+ else
+ ((diffmin < 0) ? '-' : '+') << format('%02d:%02d',
+ (diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i)
+ end
+ end
+
+ def _set(t)
+ if (t.is_a?(Date))
+ @data = t
+ elsif (t.is_a?(Time))
+ sec, min, hour, mday, month, year = t.to_a[0..5]
+ diffday = t.usec.to_r / 1000000 / SecInDay
+ of = t.utc_offset.to_r / SecInDay
+ @data = DateTime.civil(year, month, mday, hour, min, sec, of)
+ @data += diffday
+ else
+ set_str(t)
+ end
+ end
+
+ def add_tz(s)
+ s + of2tz(@data.offset)
+ end
+end
+
+class XSDDateTime < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, DateTimeLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^([+\-]?\d\d\d\d\d*)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+ if $1 == '0000'
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ year = $1.to_i
+ if year < 0
+ year += 1
+ end
+ mon = $2.to_i
+ mday = $3.to_i
+ hour = $4.to_i
+ min = $5.to_i
+ sec = $6.to_i
+ secfrac = $7
+ zonestr = $8
+
+ @data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr))
+
+ if secfrac
+ diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay
+ # jd = @data.jd
+ # day_fraction = @data.day_fraction + diffday
+ # @data = DateTime.new0(DateTime.jd_to_rjd(jd, day_fraction,
+ # @data.offset), @data.offset)
+ #
+ # Thanks to Funaba-san, above code can be simply written as below.
+ @data += diffday
+ # FYI: new0 and jd_to_rjd are not necessary to use if you don't have
+ # exceptional reason.
+ end
+ end
+
+ def _to_s
+ year = (@data.year > 0) ? @data.year : @data.year - 1
+ s = format('%.4d-%02d-%02dT%02d:%02d:%02d',
+ year, @data.mon, @data.mday, @data.hour, @data.min, @data.sec)
+ if @data.sec_fraction.nonzero?
+ fr = @data.sec_fraction * SecInDay
+ shiftsize = fr.denominator.to_s.size
+ fr_s = (fr * (10 ** shiftsize)).to_i.to_s
+ s << '.' << '0' * (shiftsize - fr_s.size) << fr_s.sub(/0+$/, '')
+ end
+ add_tz(s)
+ end
+end
+
+class XSDTime < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, TimeLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ hour = $1.to_i
+ min = $2.to_i
+ sec = $3.to_i
+ secfrac = $4
+ zonestr = $5
+
+ @data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr))
+
+ if secfrac
+ @data += secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay
+ end
+ end
+
+ def _to_s
+ s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec)
+ if @data.sec_fraction.nonzero?
+ fr = @data.sec_fraction * SecInDay
+ shiftsize = fr.denominator.to_s.size
+ fr_s = (fr * (10 ** shiftsize)).to_i.to_s
+ s << '.' << '0' * (shiftsize - fr_s.size) << fr_s.sub(/0+$/, '')
+ end
+ add_tz(s)
+ end
+end
+
+class XSDDate < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, DateLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^([+\-]?\d\d\d\d\d*)-(\d\d)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ year = $1.to_i
+ if year < 0
+ year += 1
+ end
+ mon = $2.to_i
+ mday = $3.to_i
+ zonestr = $4
+
+ @data = DateTime.civil(year, mon, mday, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ year = (@data.year > 0) ? @data.year : @data.year - 1
+ s = format('%.4d-%02d-%02d', year, @data.mon, @data.mday)
+ add_tz(s)
+ end
+end
+
+class XSDGYearMonth < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, GYearMonthLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^([+\-]?\d\d\d\d\d*)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ year = $1.to_i
+ if year < 0
+ year += 1
+ end
+ mon = $2.to_i
+ zonestr = $3
+
+ @data = DateTime.civil(year, mon, 1, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ year = (@data.year > 0) ? @data.year : @data.year - 1
+ s = format('%.4d-%02d', year, @data.mon)
+ add_tz(s)
+ end
+end
+
+class XSDGYear < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, GYearLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^([+\-]?\d\d\d\d\d*)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ year = $1.to_i
+ if year < 0
+ year += 1
+ end
+ zonestr = $2
+
+ @data = DateTime.civil(year, 1, 1, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ year = (@data.year > 0) ? @data.year : @data.year - 1
+ s = format('%.4d', year)
+ add_tz(s)
+ end
+end
+
+class XSDGMonthDay < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, GMonthDayLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^(\d\d)-(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ mon = $1.to_i
+ mday = $2.to_i
+ zonestr = $3
+
+ @data = DateTime.civil(1, mon, mday, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ s = format('%02d-%02d', @data.mon, @data.mday)
+ add_tz(s)
+ end
+end
+
+class XSDGDay < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, GDayLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ mday = $1.to_i
+ zonestr = $2
+
+ @data = DateTime.civil(1, 1, mday, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ s = format('%02d', @data.mday)
+ add_tz(s)
+ end
+end
+
+class XSDGMonth < XSDAnySimpleType
+ include XSDDateTimeImpl
+ Type = QName.new(Namespace, GMonthLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(t)
+ /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ trim(t.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.")
+ end
+
+ mon = $1.to_i
+ zonestr = $2
+
+ @data = DateTime.civil(1, mon, 1, 0, 0, 0, tz2of(zonestr))
+ end
+
+ def _to_s
+ s = format('%02d', @data.mon)
+ add_tz(s)
+ end
+end
+
+class XSDHexBinary < XSDAnySimpleType
+ Type = QName.new(Namespace, HexBinaryLiteral)
+
+ # String in Ruby could be a binary.
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+ def set_encoded(value)
+ if /^[0-9a-fA-F]*$/ !~ value
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+ @data = trim(String.new(value))
+ @is_nil = false
+ end
+
+ def string
+ [@data].pack("H*")
+ end
+
+private
+
+ def _set(value)
+ @data = value.unpack("H*")[0]
+ @data.tr!('a-f', 'A-F')
+ end
+end
+
+class XSDBase64Binary < XSDAnySimpleType
+ Type = QName.new(Namespace, Base64BinaryLiteral)
+
+ # String in Ruby could be a binary.
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+ def set_encoded(value)
+ if /^[A-Za-z0-9+\/=]*$/ !~ value
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+ @data = trim(String.new(value))
+ @is_nil = false
+ end
+
+ def string
+ @data.unpack("m")[0]
+ end
+
+private
+
+ def _set(value)
+ @data = trim([value].pack("m"))
+ end
+end
+
+class XSDAnyURI < XSDAnySimpleType
+ Type = QName.new(Namespace, AnyURILiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ begin
+ @data = URI.parse(trim(value.to_s))
+ rescue URI::InvalidURIError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+ end
+end
+
+class XSDQName < XSDAnySimpleType
+ Type = QName.new(Namespace, QNameLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ /^(?:([^:]+):)?([^:]+)$/ =~ trim(value.to_s)
+ unless Regexp.last_match
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+
+ @prefix = $1
+ @localpart = $2
+ @data = _to_s
+ end
+
+ def _to_s
+ if @prefix
+ "#{ @prefix }:#{ @localpart }"
+ else
+ "#{ @localpart }"
+ end
+ end
+end
+
+
+###
+## Derived types
+#
+class XSDNormalizedString < XSDString
+ Type = QName.new(Namespace, NormalizedStringLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def _set(value)
+ if /[\t\r\n]/ =~ value
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.")
+ end
+ super
+ end
+end
+
+class XSDInteger < XSDDecimal
+ Type = QName.new(Namespace, IntegerLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(str)
+ begin
+ @data = Integer(str)
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+
+ def _to_s()
+ @data.to_s
+ end
+end
+
+class XSDLong < XSDInteger
+ Type = QName.new(Namespace, LongLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(str)
+ begin
+ @data = Integer(str)
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ unless validate(@data)
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+
+ MaxInclusive = +9223372036854775807
+ MinInclusive = -9223372036854775808
+ def validate(v)
+ ((MinInclusive <= v) && (v <= MaxInclusive))
+ end
+end
+
+class XSDInt < XSDLong
+ Type = QName.new(Namespace, IntLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(str)
+ begin
+ @data = Integer(str)
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ unless validate(@data)
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+
+ MaxInclusive = +2147483647
+ MinInclusive = -2147483648
+ def validate(v)
+ ((MinInclusive <= v) && (v <= MaxInclusive))
+ end
+end
+
+class XSDShort < XSDInt
+ Type = QName.new(Namespace, ShortLiteral)
+
+ def initialize(value = nil)
+ super()
+ @type = Type
+ set(value) if value
+ end
+
+private
+
+ def set_str(str)
+ begin
+ @data = Integer(str)
+ rescue ArgumentError
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ unless validate(@data)
+ raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.")
+ end
+ end
+
+ MaxInclusive = +32767
+ MinInclusive = -32768
+ def validate(v)
+ ((MinInclusive <= v) && (v <= MaxInclusive))
+ end
+end
+
+
+end
diff --git a/lib/xsd/datatypes1999.rb b/lib/xsd/datatypes1999.rb
new file mode 100644
index 0000000000..6b6b6be20a
--- /dev/null
+++ b/lib/xsd/datatypes1999.rb
@@ -0,0 +1,31 @@
+=begin
+XSD4R - XML Schema Datatype 1999 support
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/datatypes'
+
+
+module XSD
+ Namespace.replace('http://www.w3.org/1999/XMLSchema')
+ InstanceNamespace.replace('http://www.w3.org/1999/XMLSchema-instance')
+ AnyTypeLiteral.replace('ur-type')
+ AnySimpleTypeLiteral.replace('ur-type')
+ NilLiteral.replace('null')
+ NilValue.replace('1')
+ DateTimeLiteral.replace('timeInstant')
+end
diff --git a/lib/xsd/iconvcharset.rb b/lib/xsd/iconvcharset.rb
new file mode 100644
index 0000000000..f607b7db45
--- /dev/null
+++ b/lib/xsd/iconvcharset.rb
@@ -0,0 +1,44 @@
+=begin
+XSD4R - Charset handling with iconv.
+Copyright (C) 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'iconv'
+
+
+module XSD
+
+
+class IconvCharset
+ def self.safe_iconv(to, from, str)
+ iconv = Iconv.new(to, from)
+ out = ""
+ begin
+ out << iconv.iconv(str)
+ rescue Iconv::IllegalSequence => e
+ out << e.success
+ ch, str = e.failed.split(//, 2)
+ out << '?'
+ STDERR.puts("Failed to convert #{ch}")
+ retry
+ end
+ return out
+ end
+end
+
+
+end
diff --git a/lib/xsd/namedelements.rb b/lib/xsd/namedelements.rb
new file mode 100644
index 0000000000..76f958a9e5
--- /dev/null
+++ b/lib/xsd/namedelements.rb
@@ -0,0 +1,86 @@
+=begin
+XSD4R - WSDL named element collection.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module XSD
+
+
+class NamedElements
+ include Enumerable
+
+ def initialize
+ @elements = []
+ @cache = {}
+ end
+
+ def dup
+ o = NamedElements.new
+ o.elements = @elements.dup
+ o
+ end
+
+ def size
+ @elements.size
+ end
+
+ def [](idx)
+ if idx.is_a?(Numeric)
+ @elements[idx]
+ else
+ @cache[idx] ||= @elements.find { |item| item.name == idx }
+ end
+ end
+
+ def find_name(name)
+ @elements.find { |item| item.name.name == name }
+ end
+
+ def each
+ @elements.each do |element|
+ yield(element)
+ end
+ end
+
+ def <<(rhs)
+ @elements << rhs
+ self
+ end
+
+ def +(rhs)
+ o = NamedElements.new
+ o.elements = @elements + rhs.elements
+ o
+ end
+
+ def concat(rhs)
+ @elements.concat(rhs.elements)
+ self
+ end
+
+protected
+
+ def elements=(rhs)
+ @elements = rhs
+ end
+
+ def elements
+ @elements
+ end
+end
+
+end
diff --git a/lib/xsd/ns.rb b/lib/xsd/ns.rb
new file mode 100644
index 0000000000..0767b2c30d
--- /dev/null
+++ b/lib/xsd/ns.rb
@@ -0,0 +1,141 @@
+=begin
+XSD4R - XML Schema Namespace library
+Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/datatypes'
+
+
+module XSD
+
+
+class NS
+ class Assigner
+ def initialize
+ @count = 0
+ end
+
+ def assign(ns)
+ @count += 1
+ "n#{ @count }"
+ end
+ end
+
+ attr_reader :default_namespace
+
+ class FormatError < Error; end
+
+public
+
+ def initialize(tag2ns = {})
+ @tag2ns = tag2ns
+ @assigner = nil
+ @ns2tag = {}
+ @tag2ns.each do |tag, ns|
+ @ns2tag[ns] = tag
+ end
+ @default_namespace = nil
+ end
+
+ def assign(ns, tag = nil)
+ if (tag == '')
+ @default_namespace = ns
+ tag
+ else
+ @assigner ||= Assigner.new
+ tag ||= @assigner.assign(ns)
+ @ns2tag[ns] = tag
+ @tag2ns[tag] = ns
+ tag
+ end
+ end
+
+ def assigned?(ns)
+ @ns2tag.key?(ns)
+ end
+
+ def assigned_tag?(tag)
+ @tag2ns.key?(tag)
+ end
+
+ def clone_ns
+ cloned = NS.new(@tag2ns.dup)
+ cloned.assigner = @assigner
+ cloned.assign(@default_namespace, '') if @default_namespace
+ cloned
+ end
+
+ def name(name)
+ if (name.namespace == @default_namespace)
+ name.name
+ elsif @ns2tag.key?(name.namespace)
+ @ns2tag[name.namespace] + ':' << name.name
+ else
+ raise FormatError.new('Namespace: ' << name.namespace << ' not defined yet.')
+ end
+ end
+
+ def compare(ns, name, rhs)
+ if (ns == @default_namespace)
+ return true if (name == rhs)
+ end
+ @tag2ns.each do |assigned_tag, assigned_ns|
+ if assigned_ns == ns && "#{ assigned_tag }:#{ name }" == rhs
+ return true
+ end
+ end
+ false
+ end
+
+ # $1 and $2 are necessary.
+ ParseRegexp = Regexp.new('^([^:]+)(?::(.+))?$')
+
+ def parse(elem)
+ ns = nil
+ name = nil
+ ParseRegexp =~ elem
+ if $2
+ ns = @tag2ns[$1]
+ name = $2
+ if !ns
+ raise FormatError.new('Unknown namespace qualifier: ' << $1)
+ end
+ elsif $1
+ ns = @default_namespace
+ name = $1
+ end
+ if !name
+ raise FormatError.new("Illegal element format: #{ elem }")
+ end
+ XSD::QName.new(ns, name)
+ end
+
+ def each_ns
+ @ns2tag.each do |ns, tag|
+ yield(ns, tag)
+ end
+ end
+
+protected
+
+ def assigner=(assigner)
+ @assigner = assigner
+ end
+end
+
+
+end
diff --git a/lib/xsd/qname.rb b/lib/xsd/qname.rb
new file mode 100644
index 0000000000..150a837c1d
--- /dev/null
+++ b/lib/xsd/qname.rb
@@ -0,0 +1,77 @@
+=begin
+XSD4R - XML QName definition.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+module XSD
+
+
+class QName
+ attr_accessor :namespace
+ attr_accessor :name
+
+ def initialize(namespace = nil, name = nil)
+ @namespace = namespace
+ @name = name
+ end
+
+ def dup_name(name)
+ self.class.new(@namespace, name)
+ end
+
+ def match(rhs)
+ unless self.class === rhs
+ return false
+ end
+ if rhs.namespace and (rhs.namespace != @namespace)
+ return false
+ end
+ if rhs.name and (rhs.name != @name)
+ return false
+ end
+ true
+ end
+
+ def ==(rhs)
+ (self.class === rhs && @namespace == rhs.namespace && @name == rhs.name)
+ end
+
+ def ===(rhs)
+ (self == rhs)
+ end
+
+ def eql?(rhs)
+ (self == rhs)
+ end
+
+ def hash
+ @namespace.hash ^ @name.hash
+ end
+
+ def to_s
+ "{#{ namespace }}#{ name }"
+ end
+
+ NormalizedNameRegexp = /^\{([^}]*)\}(.*)$/
+ def parse(str)
+ NormalizedNameRegexp =~ str
+ self.new($1, $2)
+ end
+end
+
+
+end
diff --git a/lib/xsd/xmlparser.rb b/lib/xsd/xmlparser.rb
new file mode 100644
index 0000000000..7d6d389261
--- /dev/null
+++ b/lib/xsd/xmlparser.rb
@@ -0,0 +1,72 @@
+=begin
+XSD4R - XML Instance parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/xmlparser/parser'
+
+
+module XSD
+
+
+module XMLParser
+ def create_parser(host, opt)
+ XSD::XMLParser::Parser.create_parser(host, opt)
+ end
+ module_function :create_parser
+
+ # $1 is necessary.
+ NSParseRegexp = Regexp.new('^xmlns:?(.*)$')
+
+ def filter_ns(ns, attrs)
+ return attrs if attrs.nil? or attrs.empty?
+ newattrs = {}
+ attrs.each do |key, value|
+ if (NSParseRegexp =~ key)
+ # '' means 'default namespace'.
+ tag = $1 || ''
+ ns.assign(value, tag)
+ else
+ newattrs[key] = value
+ end
+ end
+ newattrs
+ end
+ module_function :filter_ns
+end
+
+
+end
+
+
+# Try to load XML processor.
+loaded = false
+[
+ 'xsd/xmlparser/xmlscanner',
+ 'xsd/xmlparser/xmlparser',
+ 'xsd/xmlparser/rexmlparser',
+].each do |lib|
+ begin
+ require lib
+ loaded = true
+ break
+ rescue LoadError
+ end
+end
+unless loaded
+ raise RuntimeError.new("XML processor module not found.")
+end
diff --git a/lib/xsd/xmlparser/parser.rb b/lib/xsd/xmlparser/parser.rb
new file mode 100644
index 0000000000..0c7fd48084
--- /dev/null
+++ b/lib/xsd/xmlparser/parser.rb
@@ -0,0 +1,107 @@
+=begin
+XSD4R - XML Instance parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/qname'
+require 'xsd/ns'
+require 'xsd/charset'
+
+
+module XSD
+module XMLParser
+
+
+class Parser
+ class ParseError < Error; end
+ class FormatDecodeError < ParseError; end
+ class UnknownElementError < FormatDecodeError; end
+ class UnknownAttributeError < FormatDecodeError; end
+ class UnexpectedElementError < FormatDecodeError; end
+ class ElementConstraintError < FormatDecodeError; end
+
+ @@parser_factory = nil
+
+ def self.factory
+ @@parser_factory
+ end
+
+ def self.create_parser(host, opt = {})
+ @@parser_factory.new(host, opt)
+ end
+
+ def self.add_factory(factory)
+ if $DEBUG
+ puts "Set #{ factory } as XML processor."
+ end
+ @@parser_factory = factory
+ end
+
+public
+
+ attr_accessor :charset
+
+ def initialize(host, opt = {})
+ @host = host
+ @charset = opt[:charset] || 'us-ascii'
+ end
+
+ def parse(string_or_readable)
+ @textbuf = ''
+ prologue
+ do_parse(string_or_readable)
+ epilogue
+ end
+
+private
+
+ def do_parse(string_or_readable)
+ raise NotImplementError.new(
+ 'Method do_parse must be defined in derived class.')
+ end
+
+ def start_element(name, attrs)
+ @host.start_element(name, attrs)
+ end
+
+ def characters(text)
+ @host.characters(text)
+ end
+
+ def end_element(name)
+ @host.end_element(name)
+ end
+
+ def prologue
+ end
+
+ def epilogue
+ end
+
+ def xmldecl_encoding=(charset)
+ if @charset.nil?
+ @charset = charset
+ else
+ # Definition in a stream (like HTTP) has a priority.
+ p "encoding definition: #{ charset } is ignored." if $DEBUG
+ end
+ end
+end
+
+
+end
+end
diff --git a/lib/xsd/xmlparser/rexmlparser.rb b/lib/xsd/xmlparser/rexmlparser.rb
new file mode 100644
index 0000000000..2500d432d8
--- /dev/null
+++ b/lib/xsd/xmlparser/rexmlparser.rb
@@ -0,0 +1,65 @@
+=begin
+XSD4R - REXMLParser XML parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/xmlparser'
+require 'rexml/streamlistener'
+require 'rexml/document'
+
+
+module XSD
+module XMLParser
+
+
+class REXMLParser < XSD::XMLParser::Parser
+ include REXML::StreamListener
+
+ def do_parse(string_or_readable)
+ source = nil
+ source = REXML::SourceFactory.create_from(string_or_readable)
+ source.encoding = charset if charset
+ # Listener passes a String in utf-8.
+ @charset = 'utf-8'
+ REXML::Document.parse_stream(source, self)
+ end
+
+ def epilogue
+ end
+
+ def tag_start(name, attrs)
+ start_element(name, attrs)
+ end
+
+ def tag_end(name)
+ end_element(name)
+ end
+
+ def text(text)
+ characters(text)
+ end
+
+ def xmldecl(version, encoding, standalone)
+ # Version should be checked.
+ end
+
+ add_factory(self)
+end
+
+
+end
+end
diff --git a/lib/xsd/xmlparser/xmlparser.rb b/lib/xsd/xmlparser/xmlparser.rb
new file mode 100644
index 0000000000..f555b99b26
--- /dev/null
+++ b/lib/xsd/xmlparser/xmlparser.rb
@@ -0,0 +1,61 @@
+=begin
+XSD4R - XMLParser XML parser library.
+Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/xmlparser'
+require 'xml/parser'
+
+
+module XSD
+module XMLParser
+
+
+class XMLParser < XSD::XMLParser::Parser
+ class Listener < XML::Parser
+ begin
+ require 'xml/encoding-ja'
+ include XML::Encoding_ja
+ rescue LoadError
+ # uconv may not be installed.
+ end
+ end
+
+ def do_parse(string_or_readable)
+ # XMLParser passes a String in utf-8.
+ @charset = 'utf-8'
+ @parser = Listener.new
+ @parser.parse(string_or_readable) do |type, name, data|
+ case type
+ when XML::Parser::START_ELEM
+ start_element(name, data)
+ when XML::Parser::END_ELEM
+ end_element(name)
+ when XML::Parser::CDATA
+ characters(data)
+ else
+ raise FormatDecodeError.new("Unexpected XML: #{ type }/#{ name }/#{ data }.")
+ end
+ end
+ end
+
+ add_factory(self)
+end
+
+
+end
+end
diff --git a/lib/xsd/xmlparser/xmlscanner.rb b/lib/xsd/xmlparser/xmlscanner.rb
new file mode 100644
index 0000000000..c10e275b9e
--- /dev/null
+++ b/lib/xsd/xmlparser/xmlscanner.rb
@@ -0,0 +1,158 @@
+=begin
+XSD4R - XMLScan XML parser library.
+Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PRATICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+=end
+
+
+require 'xsd/xmlparser'
+require 'xmlscan/scanner'
+
+
+module XSD
+module XMLParser
+
+
+class XMLScanner < XSD::XMLParser::Parser
+ include XMLScan::Visitor
+
+ def do_parse(string_or_readable)
+ @attrs = {}
+ @curattr = nil
+ @scanner = XMLScan::XMLScanner.new(self)
+ @scanner.kcode = ::XSD::Charset.charset_str(charset) if charset
+ @scanner.parse(string_or_readable)
+ end
+
+ def scanner_kcode=(charset)
+ @scanner.kcode = ::XSD::Charset.charset_str(charset) if charset
+ self.xmldecl_encoding = charset
+ end
+
+ ENTITY_REF_MAP = {
+ 'lt' => '<',
+ 'gt' => '>',
+ 'amp' => '&',
+ 'quot' => '"',
+ 'apos' => '\''
+ }
+
+ def parse_error(msg)
+ raise ParseError.new(msg)
+ end
+
+ def wellformed_error(msg)
+ raise NotWellFormedError.new(msg)
+ end
+
+ def valid_error(msg)
+ raise NotValidError.new(msg)
+ end
+
+ def warning(msg)
+ p msg if $DEBUG
+ end
+
+ # def on_xmldecl; end
+
+ def on_xmldecl_version(str)
+ # 1.0 expected.
+ end
+
+ def on_xmldecl_encoding(str)
+ self.scanner_kcode = str
+ end
+
+ # def on_xmldecl_standalone(str); end
+
+ # def on_xmldecl_other(name, value); end
+
+ # def on_xmldecl_end; end
+
+ # def on_doctype(root, pubid, sysid); end
+
+ # def on_prolog_space(str); end
+
+ # def on_comment(str); end
+
+ # def on_pi(target, pi); end
+
+ def on_chardata(str)
+ characters(str)
+ end
+
+ # def on_cdata(str); end
+
+ def on_etag(name)
+ end_element(name)
+ end
+
+ def on_entityref(ref)
+ characters(ENTITY_REF_MAP[ref])
+ end
+
+ def on_charref(code)
+ characters([code].pack('U'))
+ end
+
+ def on_charref_hex(code)
+ on_charref(code)
+ end
+
+ # def on_start_document; end
+
+ # def on_end_document; end
+
+ def on_stag(name)
+ @attrs = {}
+ end
+
+ def on_attribute(name)
+ @attrs[name] = @curattr = ''
+ end
+
+ def on_attr_value(str)
+ @curattr << str
+ end
+
+ def on_attr_entityref(ref)
+ @curattr << ENTITY_REF_MAP[ref]
+ end
+
+ def on_attr_charref(code)
+ @curattr << [code].pack('U')
+ end
+
+ def on_attr_charref_hex(code)
+ on_attr_charref(code)
+ end
+
+ # def on_attribute_end(name); end
+
+ def on_stag_end_empty(name)
+ on_stag_end(name)
+ on_etag(name)
+ end
+
+ def on_stag_end(name)
+ start_element(name, @attrs)
+ end
+
+ add_factory(self)
+end
+
+
+end
+end
diff --git a/sample/soap/babelfish.rb b/sample/soap/babelfish.rb
new file mode 100644
index 0000000000..eb2421449a
--- /dev/null
+++ b/sample/soap/babelfish.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+text = ARGV.shift || 'Hello world.'
+lang = ARGV.shift || 'en_fr'
+
+require 'soap/rpc/driver'
+
+server = 'http://services.xmethods.net/perl/soaplite.cgi'
+InterfaceNS = 'urn:xmethodsBabelFish'
+wireDumpDev = nil # STDERR
+
+drv = SOAP::RPC::Driver.new(server, InterfaceNS)
+drv.wiredump_dev = wireDumpDev
+drv.add_method_with_soapaction('BabelFish', InterfaceNS + "#BabelFish", 'translationmode', 'sourcedata')
+
+p drv.BabelFish(lang, text)
diff --git a/sample/soap/calc/calc.rb b/sample/soap/calc/calc.rb
new file mode 100644
index 0000000000..6bc78803b3
--- /dev/null
+++ b/sample/soap/calc/calc.rb
@@ -0,0 +1,17 @@
+module CalcService
+ def self.add(lhs, rhs)
+ lhs + rhs
+ end
+
+ def self.sub(lhs, rhs)
+ lhs - rhs
+ end
+
+ def self.multi(lhs, rhs)
+ lhs * rhs
+ end
+
+ def self.div(lhs, rhs)
+ lhs / rhs
+ end
+end
diff --git a/sample/soap/calc/calc2.rb b/sample/soap/calc/calc2.rb
new file mode 100644
index 0000000000..e9cf6bbca7
--- /dev/null
+++ b/sample/soap/calc/calc2.rb
@@ -0,0 +1,29 @@
+class CalcService2
+ def initialize(value = 0)
+ @value = value
+ end
+
+ def set(value)
+ @value = value
+ end
+
+ def get
+ @value
+ end
+
+ def +(rhs)
+ @value + rhs
+ end
+
+ def -(rhs)
+ @value - rhs
+ end
+
+ def *(rhs)
+ @value * rhs
+ end
+
+ def /(rhs)
+ @value / rhs
+ end
+end
diff --git a/sample/soap/calc/client.rb b/sample/soap/calc/client.rb
new file mode 100644
index 0000000000..57a4c0ba5b
--- /dev/null
+++ b/sample/soap/calc/client.rb
@@ -0,0 +1,26 @@
+require 'soap/rpc/driver'
+
+server = ARGV.shift || 'http://localhost:7000/'
+# server = 'http://localhost:8808/server.cgi'
+
+calc = SOAP::RPC::Driver.new(server, 'http://tempuri.org/calcService')
+#calc.wiredump_dev = STDERR
+calc.add_method('add', 'lhs', 'rhs')
+calc.add_method('sub', 'lhs', 'rhs')
+calc.add_method('multi', 'lhs', 'rhs')
+calc.add_method('div', 'lhs', 'rhs')
+
+puts 'add: 1 + 2 # => 3'
+puts calc.add(1, 2)
+puts 'sub: 1.1 - 2.2 # => -1.1'
+puts calc.sub(1.1, 2.2)
+puts 'multi: 1.1 * 2.2 # => 2.42'
+puts calc.multi(1.1, 2.2)
+puts 'div: 5 / 2 # => 2'
+puts calc.div(5, 2)
+puts 'div: 5.0 / 2 # => 2.5'
+puts calc.div(5.0, 2)
+puts 'div: 1.1 / 0 # => Infinity'
+puts calc.div(1.1, 0)
+puts 'div: 1 / 0 # => ZeroDivisionError'
+puts calc.div(1, 0)
diff --git a/sample/soap/calc/client2.rb b/sample/soap/calc/client2.rb
new file mode 100644
index 0000000000..2c53f09d42
--- /dev/null
+++ b/sample/soap/calc/client2.rb
@@ -0,0 +1,29 @@
+require 'soap/rpc/driver'
+
+server = ARGV.shift || 'http://localhost:7000/'
+# server = 'http://localhost:8808/server2.cgi'
+
+var = SOAP::RPC::Driver.new( server, 'http://tempuri.org/calcService' )
+var.add_method( 'set', 'newValue' )
+var.add_method( 'get' )
+var.add_method_as( '+', 'add', 'rhs' )
+var.add_method_as( '-', 'sub', 'rhs' )
+var.add_method_as( '*', 'multi', 'rhs' )
+var.add_method_as( '/', 'div', 'rhs' )
+
+puts 'var.set( 1 )'
+puts '# Bare in mind that another client set another value to this service.'
+puts '# This is only a sample for proof of concept.'
+var.set( 1 )
+puts 'var + 2 # => 1 + 2 = 3'
+puts var + 2
+puts 'var - 2.2 # => 1 - 2.2 = -1.2'
+puts var - 2.2
+puts 'var * 2.2 # => 1 * 2.2 = 2.2'
+puts var * 2.2
+puts 'var / 2 # => 1 / 2 = 0'
+puts var / 2
+puts 'var / 2.0 # => 1 / 2.0 = 0.5'
+puts var / 2.0
+puts 'var / 0 # => 1 / 0 => ZeroDivisionError'
+puts var / 0
diff --git a/sample/soap/calc/httpd.rb b/sample/soap/calc/httpd.rb
new file mode 100644
index 0000000000..ee8ab09f50
--- /dev/null
+++ b/sample/soap/calc/httpd.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'webrick'
+require 'getopts'
+
+getopts "", 'r:', 'p:8808'
+
+s = WEBrick::HTTPServer.new(
+ :BindAddress => "0.0.0.0",
+ :Port => $OPT_p.to_i,
+ :DocumentRoot => $OPT_r || ".",
+ :CGIPathEnv => ENV['PATH']
+)
+trap(:INT){ s.shutdown }
+s.start
diff --git a/sample/soap/calc/server.cgi b/sample/soap/calc/server.cgi
new file mode 100644
index 0000000000..c4fa687550
--- /dev/null
+++ b/sample/soap/calc/server.cgi
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/cgistub'
+
+class CalcServer < SOAP::RPC::CGIStub
+ def initialize(*arg)
+ super
+
+ require 'calc'
+ servant = CalcService
+ add_servant(servant, 'http://tempuri.org/calcService')
+ end
+end
+
+status = CalcServer.new('CalcServer', nil).start
diff --git a/sample/soap/calc/server.rb b/sample/soap/calc/server.rb
new file mode 100644
index 0000000000..12a3968b5a
--- /dev/null
+++ b/sample/soap/calc/server.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'calc'
+
+class CalcServer < SOAP::RPC::StandaloneServer
+ def initialize(*arg)
+ super
+
+ servant = CalcService
+ add_servant(servant, 'http://tempuri.org/calcService')
+ end
+end
+
+if $0 == __FILE__
+ status = CalcServer.new('CalcServer', nil, '0.0.0.0', 7000).start
+end
diff --git a/sample/soap/calc/server2.rb b/sample/soap/calc/server2.rb
new file mode 100644
index 0000000000..735721de64
--- /dev/null
+++ b/sample/soap/calc/server2.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'calc2'
+
+class CalcServer2 < SOAP::RPC::StandaloneServer
+ def on_init
+ servant = CalcService2.new
+ add_method(servant, 'set', 'newValue')
+ add_method(servant, 'get')
+ add_method_as(servant, '+', 'add', 'lhs')
+ add_method_as(servant, '-', 'sub', 'lhs')
+ add_method_as(servant, '*', 'multi', 'lhs')
+ add_method_as(servant, '/', 'div', 'lhs')
+ end
+end
+
+if $0 == __FILE__
+ status = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 7000).start
+end
diff --git a/sample/soap/digraph.rb b/sample/soap/digraph.rb
new file mode 100644
index 0000000000..bf4a650cfe
--- /dev/null
+++ b/sample/soap/digraph.rb
@@ -0,0 +1,43 @@
+require 'soap/marshal'
+
+class Node; include SOAP::Marshallable
+ attr_reader :first, :second, :str
+
+ def initialize(*init_next)
+ @first = init_next[0]
+ @second = init_next[1]
+ end
+end
+
+n9 = Node.new
+n81 = Node.new(n9)
+n82 = Node.new(n9)
+n7 = Node.new(n81, n82)
+n61 = Node.new(n7)
+n62 = Node.new(n7)
+n5 = Node.new(n61, n62)
+n41 = Node.new(n5)
+n42 = Node.new(n5)
+n3 = Node.new(n41, n42)
+n21 = Node.new(n3)
+n22 = Node.new(n3)
+n1 = Node.new(n21, n22)
+
+File.open("digraph_marshalled_string.soap", "wb") do |f|
+ SOAP::Marshal.dump(n1, f)
+end
+
+marshalledString = File.open("digraph_marshalled_string.soap").read
+
+puts marshalledString
+
+newnode = SOAP::Marshal.unmarshal(marshalledString)
+
+puts newnode.inspect
+
+p newnode.first.first.__id__
+p newnode.second.first.__id__
+p newnode.first.first.first.first.__id__
+p newnode.second.first.second.first.__id__
+
+File.unlink("digraph_marshalled_string.soap")
diff --git a/sample/soap/exchange/client.rb b/sample/soap/exchange/client.rb
new file mode 100644
index 0000000000..2aa277afef
--- /dev/null
+++ b/sample/soap/exchange/client.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+require "soap/rpc/driver"
+
+ExchangeServiceNamespace = 'http://tempuri.org/exchangeService'
+
+server = ARGV.shift || "http://localhost:7000/"
+# server = "http://localhost:8808/server.cgi"
+
+logger = nil
+wiredump_dev = nil
+# logger = Logger.new(STDERR)
+# wiredump_dev = STDERR
+
+drv = SOAP::RPC::Driver.new(server, ExchangeServiceNamespace)
+drv.wiredump_dev = wiredump_dev
+drv.add_method("rate", "country1", "country2")
+
+p drv.rate("USA", "Japan")
diff --git a/sample/soap/exchange/exchange.rb b/sample/soap/exchange/exchange.rb
new file mode 100644
index 0000000000..00f930deb8
--- /dev/null
+++ b/sample/soap/exchange/exchange.rb
@@ -0,0 +1,17 @@
+require 'soap/rpc/driver'
+
+ExchangeServiceNamespace = 'http://tempuri.org/exchangeService'
+
+class Exchange
+ ForeignServer = "http://services.xmethods.net/soap"
+ Namespace = "urn:xmethods-CurrencyExchange"
+
+ def initialize
+ @drv = SOAP::RPC::Driver.new(ForeignServer, Namespace)
+ @drv.add_method("getRate", "country1", "country2")
+ end
+
+ def rate(country1, country2)
+ return @drv.getRate(country1, country2)
+ end
+end
diff --git a/sample/soap/exchange/httpd.rb b/sample/soap/exchange/httpd.rb
new file mode 100644
index 0000000000..ee8ab09f50
--- /dev/null
+++ b/sample/soap/exchange/httpd.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'webrick'
+require 'getopts'
+
+getopts "", 'r:', 'p:8808'
+
+s = WEBrick::HTTPServer.new(
+ :BindAddress => "0.0.0.0",
+ :Port => $OPT_p.to_i,
+ :DocumentRoot => $OPT_r || ".",
+ :CGIPathEnv => ENV['PATH']
+)
+trap(:INT){ s.shutdown }
+s.start
diff --git a/sample/soap/exchange/server.cgi b/sample/soap/exchange/server.cgi
new file mode 100644
index 0000000000..16bc85a042
--- /dev/null
+++ b/sample/soap/exchange/server.cgi
@@ -0,0 +1,14 @@
+#!/usr/local/bin/ruby
+
+require 'soap/rpc/cgistub'
+require 'exchange'
+
+class ExchangeServer < SOAP::RPC::CGIStub
+ def initialize(*arg)
+ super
+ servant = Exchange.new
+ add_servant(servant)
+ end
+end
+
+status = ExchangeServer.new('SampleStructServer', ExchangeServiceNamespace).start
diff --git a/sample/soap/exchange/server.rb b/sample/soap/exchange/server.rb
new file mode 100644
index 0000000000..d510d54a76
--- /dev/null
+++ b/sample/soap/exchange/server.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'exchange'
+
+class ExchangeServer < SOAP::RPC::StandaloneServer
+ def initialize(*arg)
+ super
+ servant = Exchange.new
+ add_servant(servant)
+ end
+end
+
+if $0 == __FILE__
+ status = ExchangeServer.new('SampleStructServer', ExchangeServiceNamespace, '0.0.0.0', 7000).start
+end
diff --git a/sample/soap/helloworld/hw_c.rb b/sample/soap/helloworld/hw_c.rb
new file mode 100644
index 0000000000..253d0a409b
--- /dev/null
+++ b/sample/soap/helloworld/hw_c.rb
@@ -0,0 +1,6 @@
+require 'soap/rpc/driver'
+
+s = SOAP::RPC::Driver.new('http://localhost:2000/', 'urn:hws')
+s.add_method("hello_world", "from")
+
+p s.hello_world(self.to_s)
diff --git a/sample/soap/helloworld/hw_s.rb b/sample/soap/helloworld/hw_s.rb
new file mode 100644
index 0000000000..b917f72fc0
--- /dev/null
+++ b/sample/soap/helloworld/hw_s.rb
@@ -0,0 +1,17 @@
+require 'soap/rpc/standaloneServer'
+
+class HelloWorldServer < SOAP::RPC::StandaloneServer
+ def on_init
+ @log.level = Logger::Severity::DEBUG
+ add_method(self, 'hello_world', 'from')
+ end
+
+ def hello_world(from)
+ "Hello World, from #{ from }"
+ end
+end
+
+if $0 == __FILE__
+ server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 2000)
+ server.start
+end
diff --git a/sample/soap/icd/IICD.rb b/sample/soap/icd/IICD.rb
new file mode 100644
index 0000000000..3b1fa9b32c
--- /dev/null
+++ b/sample/soap/icd/IICD.rb
@@ -0,0 +1,17 @@
+module IICD
+ # All methods in a single namespace?!
+ InterfaceNS = 'http://www.iwebmethod.net'
+
+ Methods = [
+ ['SearchWord', 'query', 'partial'],
+ ['GetItemById', 'id'],
+ ['EnumWords'],
+ ['FullTextSearch', 'query'],
+ ]
+
+ def IICD.add_method(drv)
+ Methods.each do |method, *param|
+ drv.add_method_with_soapaction(method, InterfaceNS + "/#{ method }", *param )
+ end
+ end
+end
diff --git a/sample/soap/icd/icd.rb b/sample/soap/icd/icd.rb
new file mode 100644
index 0000000000..6e1e51c996
--- /dev/null
+++ b/sample/soap/icd/icd.rb
@@ -0,0 +1,46 @@
+#!/usr/bin/env ruby
+
+$KCODE = 'SJIS'
+
+require 'soap/rpc/driver'
+require 'IICD'; include IICD
+
+server = 'http://www.iwebmethod.net/icd1.0/icd.asmx'
+wiredump_dev = nil # STDERR
+
+icd = SOAP::RPC::Driver.new(server, IICD::InterfaceNS)
+icd.wiredump_dev = wiredump_dev
+icd.default_encodingstyle = SOAP::EncodingStyle::ASPDotNetHandler::Namespace
+IICD::add_method(icd)
+
+puts "ƒL[ƒ[ƒh: 'microsoft'‚ÅŒ©o‚µŒŸõ"
+result = icd.SearchWord('microsoft', true)
+
+id = nil
+result.WORD.each do |word|
+ puts "Title: " << word.title
+ puts "Id: " << word.id
+ puts "English: " << word.english
+ puts "Japanese: " << word.japanese
+ puts "----"
+ id = word.id
+end
+
+item = icd.GetItemById(id)
+puts
+puts
+puts "Title: " << item.word.title
+puts "ˆÓ–¡: " << item.meaning
+
+#p icd.EnumWords
+
+puts
+puts
+puts "ƒL[ƒ[ƒh: 'IBM'‚Å‘S•¶ŒŸõ"
+icd.FullTextSearch("IBM").WORD.each do |word|
+ puts "Title: " << word.title
+ puts "Id: " << word.id
+ puts "English: " << word.english
+ puts "Japanese: " << word.japanese
+ puts "----"
+end
diff --git a/sample/soap/raa/iRAA.rb b/sample/soap/raa/iRAA.rb
new file mode 100644
index 0000000000..2b188fb887
--- /dev/null
+++ b/sample/soap/raa/iRAA.rb
@@ -0,0 +1,154 @@
+require 'soap/mapping'
+
+
+module RAA; extend SOAP
+
+
+InterfaceNS = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"
+MappingRegistry = SOAP::Mapping::Registry.new
+
+Methods = [
+ ['getAllListings', ['retval', 'return']],
+ ['getProductTree', ['retval', 'return']],
+ ['getInfoFromCategory', ['in', 'category'], [ 'retval', 'return']],
+ ['getModifiedInfoSince', ['in', 'time'], [ 'retval', 'return']],
+ ['getInfoFromName', ['in', 'name'], ['retval', 'return']],
+]
+
+
+class Category
+ include SOAP::Marshallable
+
+ @@schema_type = 'Category'
+ @@schema_ns = InterfaceNS
+
+ attr_reader :major, :minor
+
+ def initialize(major, minor = nil)
+ @major = major
+ @minor = minor
+ end
+
+ def to_s
+ "#{ @major }/#{ @minor }"
+ end
+
+ def ==(rhs)
+ if @major != rhs.major
+ false
+ elsif !@minor or !rhs.minor
+ true
+ else
+ @minor == rhs.minor
+ end
+ end
+end
+
+MappingRegistry.set(
+ ::RAA::Category,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new(InterfaceNS, "Category") }
+)
+
+class Product
+ include SOAP::Marshallable
+
+ @@schema_type = 'Product'
+ @@schema_ns = InterfaceNS
+
+ attr_reader :id, :name
+ attr_accessor :short_description, :version, :status, :homepage, :download, :license, :description
+
+ def initialize(name, short_description = nil, version = nil, status = nil, homepage = nil, download = nil, license = nil, description = nil)
+ @name = name
+ @short_description = short_description
+ @version = version
+ @status = status
+ @homepage = homepage
+ @download = download
+ @license = license
+ @description = description
+ end
+end
+
+MappingRegistry.set(
+ ::RAA::Product,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new(InterfaceNS, "Product") }
+)
+
+class Owner
+ include SOAP::Marshallable
+
+ @@schema_type = 'Owner'
+ @@schema_ns = InterfaceNS
+
+ attr_reader :id
+ attr_accessor :email, :name
+
+ def initialize(email, name)
+ @email = email
+ @name = name
+ @id = "#{ @email }-#{ @name }"
+ end
+end
+
+MappingRegistry.set(
+ ::RAA::Owner,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new(InterfaceNS, "Owner") }
+)
+
+class Info
+ include SOAP::Marshallable
+
+ @@schema_type = 'Info'
+ @@schema_ns = InterfaceNS
+
+ attr_accessor :category, :product, :owner, :updated, :created
+
+ def initialize(category = nil, product = nil, owner = nil, updated = nil, created = nil)
+ @category = category
+ @product = product
+ @owner = owner
+ @updated = updated
+ @created = created
+ end
+
+ def <=>(rhs)
+ @updated <=> rhs.updated
+ end
+
+ def eql?(rhs)
+ @product.name == rhs.product.name
+ end
+end
+
+MappingRegistry.set(
+ ::RAA::Info,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new(InterfaceNS, "Info") }
+)
+
+class StringArray < Array; end
+MappingRegistry.set(
+ ::RAA::StringArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::XSDString::Type }
+)
+
+class InfoArray < Array; end
+MappingRegistry.set(
+ ::RAA::InfoArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new(InterfaceNS, 'Info') }
+)
+
+
+end
diff --git a/sample/soap/raa/soap4r.rb b/sample/soap/raa/soap4r.rb
new file mode 100644
index 0000000000..b93d1e7dbe
--- /dev/null
+++ b/sample/soap/raa/soap4r.rb
@@ -0,0 +1,30 @@
+#!/usr/bin/env ruby
+
+require 'iRAA'
+require 'soap/rpc/driver'
+
+
+server = ARGV.shift || 'http://raa.ruby-lang.org/soap/1.0.2/'
+
+raa = SOAP::RPC::Driver.new(server, RAA::InterfaceNS)
+raa.mapping_registry = RAA::MappingRegistry
+RAA::Methods.each do |name, *params|
+ raa.add_method(name, params)
+end
+# raa.wiredump_dev = STDOUT
+
+p raa.getAllListings().sort
+
+p raa.getProductTree()
+
+p raa.getInfoFromCategory(RAA::Category.new("Library", "XML"))
+
+t = Time.at(Time.now.to_i - 24 * 3600)
+p raa.getModifiedInfoSince(t)
+
+p raa.getModifiedInfoSince(DateTime.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec))
+
+o = raa.getInfoFromName("SOAP4R")
+p o.class
+p o.owner.name
+p o
diff --git a/sample/soap/sampleStruct/client.rb b/sample/soap/sampleStruct/client.rb
new file mode 100644
index 0000000000..b55c7fdfc5
--- /dev/null
+++ b/sample/soap/sampleStruct/client.rb
@@ -0,0 +1,16 @@
+require 'soap/rpc/driver'
+
+require 'iSampleStruct'
+
+server = ARGV.shift || 'http://localhost:7000/'
+# server = 'http://localhost:8808/server.cgi'
+
+drv = SOAP::RPC::Driver.new(server, SampleStructServiceNamespace)
+drv.wiredump_dev = STDERR
+drv.add_method('hi', 'sampleStruct')
+
+o1 = SampleStruct.new
+puts "Sending struct: #{ o1.inspect }"
+puts
+o2 = drv.hi(o1)
+puts "Received (wrapped): #{ o2.inspect }"
diff --git a/sample/soap/sampleStruct/httpd.rb b/sample/soap/sampleStruct/httpd.rb
new file mode 100644
index 0000000000..ee8ab09f50
--- /dev/null
+++ b/sample/soap/sampleStruct/httpd.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'webrick'
+require 'getopts'
+
+getopts "", 'r:', 'p:8808'
+
+s = WEBrick::HTTPServer.new(
+ :BindAddress => "0.0.0.0",
+ :Port => $OPT_p.to_i,
+ :DocumentRoot => $OPT_r || ".",
+ :CGIPathEnv => ENV['PATH']
+)
+trap(:INT){ s.shutdown }
+s.start
diff --git a/sample/soap/sampleStruct/iSampleStruct.rb b/sample/soap/sampleStruct/iSampleStruct.rb
new file mode 100644
index 0000000000..399ea52eb8
--- /dev/null
+++ b/sample/soap/sampleStruct/iSampleStruct.rb
@@ -0,0 +1,22 @@
+require 'soap/mapping'
+
+SampleStructServiceNamespace = 'http://tempuri.org/sampleStructService'
+
+class SampleStruct; include SOAP::Marshallable
+ attr_accessor :sampleArray
+ attr_accessor :date
+
+ def initialize
+ @sampleArray = SampleArray[ "cyclic", self ]
+ @date = DateTime.now
+ end
+
+ def wrap( rhs )
+ @sampleArray = SampleArray[ "wrap", rhs.dup ]
+ @date = DateTime.now
+ self
+ end
+end
+
+class SampleArray < Array; include SOAP::Marshallable
+end
diff --git a/sample/soap/sampleStruct/sampleStruct.rb b/sample/soap/sampleStruct/sampleStruct.rb
new file mode 100644
index 0000000000..394c1bff09
--- /dev/null
+++ b/sample/soap/sampleStruct/sampleStruct.rb
@@ -0,0 +1,13 @@
+require 'iSampleStruct'
+
+class SampleStructService
+ def hi(struct)
+ ack = SampleStruct.new
+ ack.wrap(struct)
+ ack
+ end
+end
+
+if __FILE__ == $0
+ p SampleStructService.new.hi(SampleStruct.new)
+end
diff --git a/sample/soap/sampleStruct/server.cgi b/sample/soap/sampleStruct/server.cgi
new file mode 100644
index 0000000000..42751386a0
--- /dev/null
+++ b/sample/soap/sampleStruct/server.cgi
@@ -0,0 +1,14 @@
+#!/usr/local/bin/ruby
+
+require 'soap/rpc/cgistub'
+require 'sampleStruct'
+
+class SampleStructServer < SOAP::RPC::CGIStub
+ def initialize(*arg)
+ super
+ servant = SampleStructService.new
+ add_servant(servant)
+ end
+end
+
+status = SampleStructServer.new('SampleStructServer', SampleStructServiceNamespace).start
diff --git a/sample/soap/sampleStruct/server.rb b/sample/soap/sampleStruct/server.rb
new file mode 100644
index 0000000000..3caa31a052
--- /dev/null
+++ b/sample/soap/sampleStruct/server.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'sampleStruct'
+
+class SampleStructServer < SOAP::RPC::StandaloneServer
+ def initialize(*arg)
+ super
+ servant = SampleStructService.new
+ add_servant(servant)
+ end
+end
+
+if $0 == __FILE__
+ status = SampleStructServer.new('SampleStructServer', SampleStructServiceNamespace, '0.0.0.0', 7000).start
+end
diff --git a/sample/wsdl/amazon/AmazonSearch.rb b/sample/wsdl/amazon/AmazonSearch.rb
new file mode 100644
index 0000000000..29397c2d56
--- /dev/null
+++ b/sample/wsdl/amazon/AmazonSearch.rb
@@ -0,0 +1,3701 @@
+# http://soap.amazon.com
+class ProductLineArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ProductLineArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ProductLine
+ @@schema_type = "ProductLine"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def Mode
+ @mode
+ end
+
+ def Mode=(value)
+ @mode = value
+ end
+
+ def ProductInfo
+ @productInfo
+ end
+
+ def ProductInfo=(value)
+ @productInfo = value
+ end
+
+ def initialize(mode = nil,
+ productInfo = nil)
+ @mode = mode
+ @productInfo = productInfo
+ end
+end
+
+# http://soap.amazon.com
+class ProductInfo
+ @@schema_type = "ProductInfo"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def TotalResults
+ @totalResults
+ end
+
+ def TotalResults=(value)
+ @totalResults = value
+ end
+
+ def TotalPages
+ @totalPages
+ end
+
+ def TotalPages=(value)
+ @totalPages = value
+ end
+
+ def ListName
+ @listName
+ end
+
+ def ListName=(value)
+ @listName = value
+ end
+
+ def Details
+ @details
+ end
+
+ def Details=(value)
+ @details = value
+ end
+
+ def initialize(totalResults = nil,
+ totalPages = nil,
+ listName = nil,
+ details = nil)
+ @totalResults = totalResults
+ @totalPages = totalPages
+ @listName = listName
+ @details = details
+ end
+end
+
+# http://soap.amazon.com
+class DetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "DetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class Details
+ @@schema_type = "Details"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def Url
+ @url
+ end
+
+ def Url=(value)
+ @url = value
+ end
+
+ def Asin
+ @asin
+ end
+
+ def Asin=(value)
+ @asin = value
+ end
+
+ def ProductName
+ @productName
+ end
+
+ def ProductName=(value)
+ @productName = value
+ end
+
+ def Catalog
+ @catalog
+ end
+
+ def Catalog=(value)
+ @catalog = value
+ end
+
+ def KeyPhrases
+ @keyPhrases
+ end
+
+ def KeyPhrases=(value)
+ @keyPhrases = value
+ end
+
+ def Artists
+ @artists
+ end
+
+ def Artists=(value)
+ @artists = value
+ end
+
+ def Authors
+ @authors
+ end
+
+ def Authors=(value)
+ @authors = value
+ end
+
+ def Mpn
+ @mpn
+ end
+
+ def Mpn=(value)
+ @mpn = value
+ end
+
+ def Starring
+ @starring
+ end
+
+ def Starring=(value)
+ @starring = value
+ end
+
+ def Directors
+ @directors
+ end
+
+ def Directors=(value)
+ @directors = value
+ end
+
+ def TheatricalReleaseDate
+ @theatricalReleaseDate
+ end
+
+ def TheatricalReleaseDate=(value)
+ @theatricalReleaseDate = value
+ end
+
+ def ReleaseDate
+ @releaseDate
+ end
+
+ def ReleaseDate=(value)
+ @releaseDate = value
+ end
+
+ def Manufacturer
+ @manufacturer
+ end
+
+ def Manufacturer=(value)
+ @manufacturer = value
+ end
+
+ def Distributor
+ @distributor
+ end
+
+ def Distributor=(value)
+ @distributor = value
+ end
+
+ def ImageUrlSmall
+ @imageUrlSmall
+ end
+
+ def ImageUrlSmall=(value)
+ @imageUrlSmall = value
+ end
+
+ def ImageUrlMedium
+ @imageUrlMedium
+ end
+
+ def ImageUrlMedium=(value)
+ @imageUrlMedium = value
+ end
+
+ def ImageUrlLarge
+ @imageUrlLarge
+ end
+
+ def ImageUrlLarge=(value)
+ @imageUrlLarge = value
+ end
+
+ def ListPrice
+ @listPrice
+ end
+
+ def ListPrice=(value)
+ @listPrice = value
+ end
+
+ def OurPrice
+ @ourPrice
+ end
+
+ def OurPrice=(value)
+ @ourPrice = value
+ end
+
+ def UsedPrice
+ @usedPrice
+ end
+
+ def UsedPrice=(value)
+ @usedPrice = value
+ end
+
+ def RefurbishedPrice
+ @refurbishedPrice
+ end
+
+ def RefurbishedPrice=(value)
+ @refurbishedPrice = value
+ end
+
+ def CollectiblePrice
+ @collectiblePrice
+ end
+
+ def CollectiblePrice=(value)
+ @collectiblePrice = value
+ end
+
+ def ThirdPartyNewPrice
+ @thirdPartyNewPrice
+ end
+
+ def ThirdPartyNewPrice=(value)
+ @thirdPartyNewPrice = value
+ end
+
+ def NumberOfOfferings
+ @numberOfOfferings
+ end
+
+ def NumberOfOfferings=(value)
+ @numberOfOfferings = value
+ end
+
+ def ThirdPartyNewCount
+ @thirdPartyNewCount
+ end
+
+ def ThirdPartyNewCount=(value)
+ @thirdPartyNewCount = value
+ end
+
+ def UsedCount
+ @usedCount
+ end
+
+ def UsedCount=(value)
+ @usedCount = value
+ end
+
+ def CollectibleCount
+ @collectibleCount
+ end
+
+ def CollectibleCount=(value)
+ @collectibleCount = value
+ end
+
+ def RefurbishedCount
+ @refurbishedCount
+ end
+
+ def RefurbishedCount=(value)
+ @refurbishedCount = value
+ end
+
+ def ThirdPartyProductInfo
+ @thirdPartyProductInfo
+ end
+
+ def ThirdPartyProductInfo=(value)
+ @thirdPartyProductInfo = value
+ end
+
+ def SalesRank
+ @salesRank
+ end
+
+ def SalesRank=(value)
+ @salesRank = value
+ end
+
+ def BrowseList
+ @browseList
+ end
+
+ def BrowseList=(value)
+ @browseList = value
+ end
+
+ def Media
+ @media
+ end
+
+ def Media=(value)
+ @media = value
+ end
+
+ def ReadingLevel
+ @readingLevel
+ end
+
+ def ReadingLevel=(value)
+ @readingLevel = value
+ end
+
+ def Publisher
+ @publisher
+ end
+
+ def Publisher=(value)
+ @publisher = value
+ end
+
+ def NumMedia
+ @numMedia
+ end
+
+ def NumMedia=(value)
+ @numMedia = value
+ end
+
+ def Isbn
+ @isbn
+ end
+
+ def Isbn=(value)
+ @isbn = value
+ end
+
+ def Features
+ @features
+ end
+
+ def Features=(value)
+ @features = value
+ end
+
+ def MpaaRating
+ @mpaaRating
+ end
+
+ def MpaaRating=(value)
+ @mpaaRating = value
+ end
+
+ def EsrbRating
+ @esrbRating
+ end
+
+ def EsrbRating=(value)
+ @esrbRating = value
+ end
+
+ def AgeGroup
+ @ageGroup
+ end
+
+ def AgeGroup=(value)
+ @ageGroup = value
+ end
+
+ def Availability
+ @availability
+ end
+
+ def Availability=(value)
+ @availability = value
+ end
+
+ def Upc
+ @upc
+ end
+
+ def Upc=(value)
+ @upc = value
+ end
+
+ def Tracks
+ @tracks
+ end
+
+ def Tracks=(value)
+ @tracks = value
+ end
+
+ def Accessories
+ @accessories
+ end
+
+ def Accessories=(value)
+ @accessories = value
+ end
+
+ def Platforms
+ @platforms
+ end
+
+ def Platforms=(value)
+ @platforms = value
+ end
+
+ def Encoding
+ @encoding
+ end
+
+ def Encoding=(value)
+ @encoding = value
+ end
+
+ def Reviews
+ @reviews
+ end
+
+ def Reviews=(value)
+ @reviews = value
+ end
+
+ def SimilarProducts
+ @similarProducts
+ end
+
+ def SimilarProducts=(value)
+ @similarProducts = value
+ end
+
+ def Lists
+ @lists
+ end
+
+ def Lists=(value)
+ @lists = value
+ end
+
+ def Status
+ @status
+ end
+
+ def Status=(value)
+ @status = value
+ end
+
+ def initialize(url = nil,
+ asin = nil,
+ productName = nil,
+ catalog = nil,
+ keyPhrases = nil,
+ artists = nil,
+ authors = nil,
+ mpn = nil,
+ starring = nil,
+ directors = nil,
+ theatricalReleaseDate = nil,
+ releaseDate = nil,
+ manufacturer = nil,
+ distributor = nil,
+ imageUrlSmall = nil,
+ imageUrlMedium = nil,
+ imageUrlLarge = nil,
+ listPrice = nil,
+ ourPrice = nil,
+ usedPrice = nil,
+ refurbishedPrice = nil,
+ collectiblePrice = nil,
+ thirdPartyNewPrice = nil,
+ numberOfOfferings = nil,
+ thirdPartyNewCount = nil,
+ usedCount = nil,
+ collectibleCount = nil,
+ refurbishedCount = nil,
+ thirdPartyProductInfo = nil,
+ salesRank = nil,
+ browseList = nil,
+ media = nil,
+ readingLevel = nil,
+ publisher = nil,
+ numMedia = nil,
+ isbn = nil,
+ features = nil,
+ mpaaRating = nil,
+ esrbRating = nil,
+ ageGroup = nil,
+ availability = nil,
+ upc = nil,
+ tracks = nil,
+ accessories = nil,
+ platforms = nil,
+ encoding = nil,
+ reviews = nil,
+ similarProducts = nil,
+ lists = nil,
+ status = nil)
+ @url = url
+ @asin = asin
+ @productName = productName
+ @catalog = catalog
+ @keyPhrases = keyPhrases
+ @artists = artists
+ @authors = authors
+ @mpn = mpn
+ @starring = starring
+ @directors = directors
+ @theatricalReleaseDate = theatricalReleaseDate
+ @releaseDate = releaseDate
+ @manufacturer = manufacturer
+ @distributor = distributor
+ @imageUrlSmall = imageUrlSmall
+ @imageUrlMedium = imageUrlMedium
+ @imageUrlLarge = imageUrlLarge
+ @listPrice = listPrice
+ @ourPrice = ourPrice
+ @usedPrice = usedPrice
+ @refurbishedPrice = refurbishedPrice
+ @collectiblePrice = collectiblePrice
+ @thirdPartyNewPrice = thirdPartyNewPrice
+ @numberOfOfferings = numberOfOfferings
+ @thirdPartyNewCount = thirdPartyNewCount
+ @usedCount = usedCount
+ @collectibleCount = collectibleCount
+ @refurbishedCount = refurbishedCount
+ @thirdPartyProductInfo = thirdPartyProductInfo
+ @salesRank = salesRank
+ @browseList = browseList
+ @media = media
+ @readingLevel = readingLevel
+ @publisher = publisher
+ @numMedia = numMedia
+ @isbn = isbn
+ @features = features
+ @mpaaRating = mpaaRating
+ @esrbRating = esrbRating
+ @ageGroup = ageGroup
+ @availability = availability
+ @upc = upc
+ @tracks = tracks
+ @accessories = accessories
+ @platforms = platforms
+ @encoding = encoding
+ @reviews = reviews
+ @similarProducts = similarProducts
+ @lists = lists
+ @status = status
+ end
+end
+
+# http://soap.amazon.com
+class KeyPhraseArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "KeyPhraseArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class KeyPhrase
+ @@schema_type = "KeyPhrase"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def KeyPhrase
+ @keyPhrase
+ end
+
+ def KeyPhrase=(value)
+ @keyPhrase = value
+ end
+
+ def Type
+ @type
+ end
+
+ def Type=(value)
+ @type = value
+ end
+
+ def initialize(keyPhrase = nil,
+ type = nil)
+ @keyPhrase = keyPhrase
+ @type = type
+ end
+end
+
+# http://soap.amazon.com
+class ArtistArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ArtistArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class AuthorArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "AuthorArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class StarringArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "StarringArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class DirectorArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "DirectorArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class BrowseNodeArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "BrowseNodeArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class BrowseNode
+ @@schema_type = "BrowseNode"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def BrowseId
+ @browseId
+ end
+
+ def BrowseId=(value)
+ @browseId = value
+ end
+
+ def BrowseName
+ @browseName
+ end
+
+ def BrowseName=(value)
+ @browseName = value
+ end
+
+ def initialize(browseId = nil,
+ browseName = nil)
+ @browseId = browseId
+ @browseName = browseName
+ end
+end
+
+# http://soap.amazon.com
+class FeaturesArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "FeaturesArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class TrackArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "TrackArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class Track
+ @@schema_type = "Track"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def TrackName
+ @trackName
+ end
+
+ def TrackName=(value)
+ @trackName = value
+ end
+
+ def ByArtist
+ @byArtist
+ end
+
+ def ByArtist=(value)
+ @byArtist = value
+ end
+
+ def initialize(trackName = nil,
+ byArtist = nil)
+ @trackName = trackName
+ @byArtist = byArtist
+ end
+end
+
+# http://soap.amazon.com
+class AccessoryArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "AccessoryArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class PlatformArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "PlatformArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class Reviews
+ @@schema_type = "Reviews"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def AvgCustomerRating
+ @avgCustomerRating
+ end
+
+ def AvgCustomerRating=(value)
+ @avgCustomerRating = value
+ end
+
+ def TotalCustomerReviews
+ @totalCustomerReviews
+ end
+
+ def TotalCustomerReviews=(value)
+ @totalCustomerReviews = value
+ end
+
+ def CustomerReviews
+ @customerReviews
+ end
+
+ def CustomerReviews=(value)
+ @customerReviews = value
+ end
+
+ def initialize(avgCustomerRating = nil,
+ totalCustomerReviews = nil,
+ customerReviews = nil)
+ @avgCustomerRating = avgCustomerRating
+ @totalCustomerReviews = totalCustomerReviews
+ @customerReviews = customerReviews
+ end
+end
+
+# http://soap.amazon.com
+class CustomerReviewArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "CustomerReviewArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class CustomerReview
+ @@schema_type = "CustomerReview"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def Rating
+ @rating
+ end
+
+ def Rating=(value)
+ @rating = value
+ end
+
+ def Summary
+ @summary
+ end
+
+ def Summary=(value)
+ @summary = value
+ end
+
+ def Comment
+ @comment
+ end
+
+ def Comment=(value)
+ @comment = value
+ end
+
+ def initialize(rating = nil,
+ summary = nil,
+ comment = nil)
+ @rating = rating
+ @summary = summary
+ @comment = comment
+ end
+end
+
+# http://soap.amazon.com
+class SimilarProductsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "SimilarProductsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ListArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ListArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class MarketplaceSearch
+ @@schema_type = "MarketplaceSearch"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def MarketplaceSearchDetails
+ @marketplaceSearchDetails
+ end
+
+ def MarketplaceSearchDetails=(value)
+ @marketplaceSearchDetails = value
+ end
+
+ def initialize(marketplaceSearchDetails = nil)
+ @marketplaceSearchDetails = marketplaceSearchDetails
+ end
+end
+
+# http://soap.amazon.com
+class SellerProfile
+ @@schema_type = "SellerProfile"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def SellerProfileDetails
+ @sellerProfileDetails
+ end
+
+ def SellerProfileDetails=(value)
+ @sellerProfileDetails = value
+ end
+
+ def initialize(sellerProfileDetails = nil)
+ @sellerProfileDetails = sellerProfileDetails
+ end
+end
+
+# http://soap.amazon.com
+class SellerSearch
+ @@schema_type = "SellerSearch"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def SellerSearchDetails
+ @sellerSearchDetails
+ end
+
+ def SellerSearchDetails=(value)
+ @sellerSearchDetails = value
+ end
+
+ def initialize(sellerSearchDetails = nil)
+ @sellerSearchDetails = sellerSearchDetails
+ end
+end
+
+# http://soap.amazon.com
+class MarketplaceSearchDetails
+ @@schema_type = "MarketplaceSearchDetails"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def NumberOfOpenListings
+ @numberOfOpenListings
+ end
+
+ def NumberOfOpenListings=(value)
+ @numberOfOpenListings = value
+ end
+
+ def ListingProductInfo
+ @listingProductInfo
+ end
+
+ def ListingProductInfo=(value)
+ @listingProductInfo = value
+ end
+
+ def initialize(numberOfOpenListings = nil,
+ listingProductInfo = nil)
+ @numberOfOpenListings = numberOfOpenListings
+ @listingProductInfo = listingProductInfo
+ end
+end
+
+# http://soap.amazon.com
+class MarketplaceSearchDetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "MarketplaceSearchDetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class SellerProfileDetails
+ @@schema_type = "SellerProfileDetails"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def SellerNickname
+ @sellerNickname
+ end
+
+ def SellerNickname=(value)
+ @sellerNickname = value
+ end
+
+ def OverallFeedbackRating
+ @overallFeedbackRating
+ end
+
+ def OverallFeedbackRating=(value)
+ @overallFeedbackRating = value
+ end
+
+ def NumberOfFeedback
+ @numberOfFeedback
+ end
+
+ def NumberOfFeedback=(value)
+ @numberOfFeedback = value
+ end
+
+ def NumberOfCanceledBids
+ @numberOfCanceledBids
+ end
+
+ def NumberOfCanceledBids=(value)
+ @numberOfCanceledBids = value
+ end
+
+ def NumberOfCanceledAuctions
+ @numberOfCanceledAuctions
+ end
+
+ def NumberOfCanceledAuctions=(value)
+ @numberOfCanceledAuctions = value
+ end
+
+ def StoreId
+ @storeId
+ end
+
+ def StoreId=(value)
+ @storeId = value
+ end
+
+ def StoreName
+ @storeName
+ end
+
+ def StoreName=(value)
+ @storeName = value
+ end
+
+ def SellerFeedback
+ @sellerFeedback
+ end
+
+ def SellerFeedback=(value)
+ @sellerFeedback = value
+ end
+
+ def initialize(sellerNickname = nil,
+ overallFeedbackRating = nil,
+ numberOfFeedback = nil,
+ numberOfCanceledBids = nil,
+ numberOfCanceledAuctions = nil,
+ storeId = nil,
+ storeName = nil,
+ sellerFeedback = nil)
+ @sellerNickname = sellerNickname
+ @overallFeedbackRating = overallFeedbackRating
+ @numberOfFeedback = numberOfFeedback
+ @numberOfCanceledBids = numberOfCanceledBids
+ @numberOfCanceledAuctions = numberOfCanceledAuctions
+ @storeId = storeId
+ @storeName = storeName
+ @sellerFeedback = sellerFeedback
+ end
+end
+
+# http://soap.amazon.com
+class SellerProfileDetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "SellerProfileDetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class SellerSearchDetails
+ @@schema_type = "SellerSearchDetails"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def SellerNickname
+ @sellerNickname
+ end
+
+ def SellerNickname=(value)
+ @sellerNickname = value
+ end
+
+ def StoreId
+ @storeId
+ end
+
+ def StoreId=(value)
+ @storeId = value
+ end
+
+ def StoreName
+ @storeName
+ end
+
+ def StoreName=(value)
+ @storeName = value
+ end
+
+ def NumberOfOpenListings
+ @numberOfOpenListings
+ end
+
+ def NumberOfOpenListings=(value)
+ @numberOfOpenListings = value
+ end
+
+ def ListingProductInfo
+ @listingProductInfo
+ end
+
+ def ListingProductInfo=(value)
+ @listingProductInfo = value
+ end
+
+ def initialize(sellerNickname = nil,
+ storeId = nil,
+ storeName = nil,
+ numberOfOpenListings = nil,
+ listingProductInfo = nil)
+ @sellerNickname = sellerNickname
+ @storeId = storeId
+ @storeName = storeName
+ @numberOfOpenListings = numberOfOpenListings
+ @listingProductInfo = listingProductInfo
+ end
+end
+
+# http://soap.amazon.com
+class SellerSearchDetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "SellerSearchDetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ListingProductInfo
+ @@schema_type = "ListingProductInfo"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def ListingProductDetails
+ @listingProductDetails
+ end
+
+ def ListingProductDetails=(value)
+ @listingProductDetails = value
+ end
+
+ def initialize(listingProductDetails = nil)
+ @listingProductDetails = listingProductDetails
+ end
+end
+
+# http://soap.amazon.com
+class ListingProductDetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ListingProductDetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ListingProductDetails
+ @@schema_type = "ListingProductDetails"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def ExchangeId
+ @exchangeId
+ end
+
+ def ExchangeId=(value)
+ @exchangeId = value
+ end
+
+ def ListingId
+ @listingId
+ end
+
+ def ListingId=(value)
+ @listingId = value
+ end
+
+ def ExchangeTitle
+ @exchangeTitle
+ end
+
+ def ExchangeTitle=(value)
+ @exchangeTitle = value
+ end
+
+ def ExchangePrice
+ @exchangePrice
+ end
+
+ def ExchangePrice=(value)
+ @exchangePrice = value
+ end
+
+ def ExchangeAsin
+ @exchangeAsin
+ end
+
+ def ExchangeAsin=(value)
+ @exchangeAsin = value
+ end
+
+ def ExchangeEndDate
+ @exchangeEndDate
+ end
+
+ def ExchangeEndDate=(value)
+ @exchangeEndDate = value
+ end
+
+ def ExchangeTinyImage
+ @exchangeTinyImage
+ end
+
+ def ExchangeTinyImage=(value)
+ @exchangeTinyImage = value
+ end
+
+ def ExchangeSellerId
+ @exchangeSellerId
+ end
+
+ def ExchangeSellerId=(value)
+ @exchangeSellerId = value
+ end
+
+ def ExchangeSellerNickname
+ @exchangeSellerNickname
+ end
+
+ def ExchangeSellerNickname=(value)
+ @exchangeSellerNickname = value
+ end
+
+ def ExchangeStartDate
+ @exchangeStartDate
+ end
+
+ def ExchangeStartDate=(value)
+ @exchangeStartDate = value
+ end
+
+ def ExchangeStatus
+ @exchangeStatus
+ end
+
+ def ExchangeStatus=(value)
+ @exchangeStatus = value
+ end
+
+ def ExchangeQuantity
+ @exchangeQuantity
+ end
+
+ def ExchangeQuantity=(value)
+ @exchangeQuantity = value
+ end
+
+ def ExchangeQuantityAllocated
+ @exchangeQuantityAllocated
+ end
+
+ def ExchangeQuantityAllocated=(value)
+ @exchangeQuantityAllocated = value
+ end
+
+ def ExchangeFeaturedCategory
+ @exchangeFeaturedCategory
+ end
+
+ def ExchangeFeaturedCategory=(value)
+ @exchangeFeaturedCategory = value
+ end
+
+ def ExchangeCondition
+ @exchangeCondition
+ end
+
+ def ExchangeCondition=(value)
+ @exchangeCondition = value
+ end
+
+ def ExchangeConditionType
+ @exchangeConditionType
+ end
+
+ def ExchangeConditionType=(value)
+ @exchangeConditionType = value
+ end
+
+ def ExchangeAvailability
+ @exchangeAvailability
+ end
+
+ def ExchangeAvailability=(value)
+ @exchangeAvailability = value
+ end
+
+ def ExchangeOfferingType
+ @exchangeOfferingType
+ end
+
+ def ExchangeOfferingType=(value)
+ @exchangeOfferingType = value
+ end
+
+ def ExchangeSellerState
+ @exchangeSellerState
+ end
+
+ def ExchangeSellerState=(value)
+ @exchangeSellerState = value
+ end
+
+ def ExchangeSellerCountry
+ @exchangeSellerCountry
+ end
+
+ def ExchangeSellerCountry=(value)
+ @exchangeSellerCountry = value
+ end
+
+ def ExchangeSellerRating
+ @exchangeSellerRating
+ end
+
+ def ExchangeSellerRating=(value)
+ @exchangeSellerRating = value
+ end
+
+ def initialize(exchangeId = nil,
+ listingId = nil,
+ exchangeTitle = nil,
+ exchangePrice = nil,
+ exchangeAsin = nil,
+ exchangeEndDate = nil,
+ exchangeTinyImage = nil,
+ exchangeSellerId = nil,
+ exchangeSellerNickname = nil,
+ exchangeStartDate = nil,
+ exchangeStatus = nil,
+ exchangeQuantity = nil,
+ exchangeQuantityAllocated = nil,
+ exchangeFeaturedCategory = nil,
+ exchangeCondition = nil,
+ exchangeConditionType = nil,
+ exchangeAvailability = nil,
+ exchangeOfferingType = nil,
+ exchangeSellerState = nil,
+ exchangeSellerCountry = nil,
+ exchangeSellerRating = nil)
+ @exchangeId = exchangeId
+ @listingId = listingId
+ @exchangeTitle = exchangeTitle
+ @exchangePrice = exchangePrice
+ @exchangeAsin = exchangeAsin
+ @exchangeEndDate = exchangeEndDate
+ @exchangeTinyImage = exchangeTinyImage
+ @exchangeSellerId = exchangeSellerId
+ @exchangeSellerNickname = exchangeSellerNickname
+ @exchangeStartDate = exchangeStartDate
+ @exchangeStatus = exchangeStatus
+ @exchangeQuantity = exchangeQuantity
+ @exchangeQuantityAllocated = exchangeQuantityAllocated
+ @exchangeFeaturedCategory = exchangeFeaturedCategory
+ @exchangeCondition = exchangeCondition
+ @exchangeConditionType = exchangeConditionType
+ @exchangeAvailability = exchangeAvailability
+ @exchangeOfferingType = exchangeOfferingType
+ @exchangeSellerState = exchangeSellerState
+ @exchangeSellerCountry = exchangeSellerCountry
+ @exchangeSellerRating = exchangeSellerRating
+ end
+end
+
+# http://soap.amazon.com
+class SellerFeedback
+ @@schema_type = "SellerFeedback"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def Feedback
+ @feedback
+ end
+
+ def Feedback=(value)
+ @feedback = value
+ end
+
+ def initialize(feedback = nil)
+ @feedback = feedback
+ end
+end
+
+# http://soap.amazon.com
+class FeedbackArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "FeedbackArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class Feedback
+ @@schema_type = "Feedback"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def FeedbackRating
+ @feedbackRating
+ end
+
+ def FeedbackRating=(value)
+ @feedbackRating = value
+ end
+
+ def FeedbackComments
+ @feedbackComments
+ end
+
+ def FeedbackComments=(value)
+ @feedbackComments = value
+ end
+
+ def FeedbackDate
+ @feedbackDate
+ end
+
+ def FeedbackDate=(value)
+ @feedbackDate = value
+ end
+
+ def FeedbackRater
+ @feedbackRater
+ end
+
+ def FeedbackRater=(value)
+ @feedbackRater = value
+ end
+
+ def initialize(feedbackRating = nil,
+ feedbackComments = nil,
+ feedbackDate = nil,
+ feedbackRater = nil)
+ @feedbackRating = feedbackRating
+ @feedbackComments = feedbackComments
+ @feedbackDate = feedbackDate
+ @feedbackRater = feedbackRater
+ end
+end
+
+# http://soap.amazon.com
+class ThirdPartyProductInfo
+ @@schema_type = "ThirdPartyProductInfo"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def ThirdPartyProductDetails
+ @thirdPartyProductDetails
+ end
+
+ def ThirdPartyProductDetails=(value)
+ @thirdPartyProductDetails = value
+ end
+
+ def initialize(thirdPartyProductDetails = nil)
+ @thirdPartyProductDetails = thirdPartyProductDetails
+ end
+end
+
+# http://soap.amazon.com
+class ThirdPartyProductDetailsArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ThirdPartyProductDetailsArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ThirdPartyProductDetails
+ @@schema_type = "ThirdPartyProductDetails"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def OfferingType
+ @offeringType
+ end
+
+ def OfferingType=(value)
+ @offeringType = value
+ end
+
+ def SellerId
+ @sellerId
+ end
+
+ def SellerId=(value)
+ @sellerId = value
+ end
+
+ def SellerNickname
+ @sellerNickname
+ end
+
+ def SellerNickname=(value)
+ @sellerNickname = value
+ end
+
+ def ExchangeId
+ @exchangeId
+ end
+
+ def ExchangeId=(value)
+ @exchangeId = value
+ end
+
+ def OfferingPrice
+ @offeringPrice
+ end
+
+ def OfferingPrice=(value)
+ @offeringPrice = value
+ end
+
+ def Condition
+ @condition
+ end
+
+ def Condition=(value)
+ @condition = value
+ end
+
+ def ConditionType
+ @conditionType
+ end
+
+ def ConditionType=(value)
+ @conditionType = value
+ end
+
+ def ExchangeAvailability
+ @exchangeAvailability
+ end
+
+ def ExchangeAvailability=(value)
+ @exchangeAvailability = value
+ end
+
+ def SellerCountry
+ @sellerCountry
+ end
+
+ def SellerCountry=(value)
+ @sellerCountry = value
+ end
+
+ def SellerState
+ @sellerState
+ end
+
+ def SellerState=(value)
+ @sellerState = value
+ end
+
+ def ShipComments
+ @shipComments
+ end
+
+ def ShipComments=(value)
+ @shipComments = value
+ end
+
+ def SellerRating
+ @sellerRating
+ end
+
+ def SellerRating=(value)
+ @sellerRating = value
+ end
+
+ def initialize(offeringType = nil,
+ sellerId = nil,
+ sellerNickname = nil,
+ exchangeId = nil,
+ offeringPrice = nil,
+ condition = nil,
+ conditionType = nil,
+ exchangeAvailability = nil,
+ sellerCountry = nil,
+ sellerState = nil,
+ shipComments = nil,
+ sellerRating = nil)
+ @offeringType = offeringType
+ @sellerId = sellerId
+ @sellerNickname = sellerNickname
+ @exchangeId = exchangeId
+ @offeringPrice = offeringPrice
+ @condition = condition
+ @conditionType = conditionType
+ @exchangeAvailability = exchangeAvailability
+ @sellerCountry = sellerCountry
+ @sellerState = sellerState
+ @shipComments = shipComments
+ @sellerRating = sellerRating
+ end
+end
+
+# http://soap.amazon.com
+class KeywordRequest
+ @@schema_type = "KeywordRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def keyword
+ @keyword
+ end
+
+ def keyword=(value)
+ @keyword = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(keyword = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @keyword = keyword
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class PowerRequest
+ @@schema_type = "PowerRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def power
+ @power
+ end
+
+ def power=(value)
+ @power = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(power = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @power = power
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class BrowseNodeRequest
+ @@schema_type = "BrowseNodeRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def browse_node
+ @browse_node
+ end
+
+ def browse_node=(value)
+ @browse_node = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(browse_node = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ locale = nil)
+ @browse_node = browse_node
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class AsinRequest
+ @@schema_type = "AsinRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def asin
+ @asin
+ end
+
+ def asin=(value)
+ @asin = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def offer
+ @offer
+ end
+
+ def offer=(value)
+ @offer = value
+ end
+
+ def offerpage
+ @offerpage
+ end
+
+ def offerpage=(value)
+ @offerpage = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(asin = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ offer = nil,
+ offerpage = nil,
+ locale = nil)
+ @asin = asin
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @offer = offer
+ @offerpage = offerpage
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class BlendedRequest
+ @@schema_type = "BlendedRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def blended
+ @blended
+ end
+
+ def blended=(value)
+ @blended = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(blended = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ locale = nil)
+ @blended = blended
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class UpcRequest
+ @@schema_type = "UpcRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def upc
+ @upc
+ end
+
+ def upc=(value)
+ @upc = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(upc = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @upc = upc
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ArtistRequest
+ @@schema_type = "ArtistRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def artist
+ @artist
+ end
+
+ def artist=(value)
+ @artist = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(artist = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @artist = artist
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class AuthorRequest
+ @@schema_type = "AuthorRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def author
+ @author
+ end
+
+ def author=(value)
+ @author = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(author = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @author = author
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ActorRequest
+ @@schema_type = "ActorRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def actor
+ @actor
+ end
+
+ def actor=(value)
+ @actor = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(actor = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @actor = actor
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class DirectorRequest
+ @@schema_type = "DirectorRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def director
+ @director
+ end
+
+ def director=(value)
+ @director = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(director = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @director = director
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ExchangeRequest
+ @@schema_type = "ExchangeRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def exchange_id
+ @exchange_id
+ end
+
+ def exchange_id=(value)
+ @exchange_id = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(exchange_id = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ locale = nil)
+ @exchange_id = exchange_id
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ManufacturerRequest
+ @@schema_type = "ManufacturerRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def manufacturer
+ @manufacturer
+ end
+
+ def manufacturer=(value)
+ @manufacturer = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def mode
+ @mode
+ end
+
+ def mode=(value)
+ @mode = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def variations
+ @variations
+ end
+
+ def variations=(value)
+ @variations = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(manufacturer = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil,
+ variations = nil,
+ locale = nil)
+ @manufacturer = manufacturer
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ @variations = variations
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ListManiaRequest
+ @@schema_type = "ListManiaRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def lm_id
+ @lm_id
+ end
+
+ def lm_id=(value)
+ @lm_id = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(lm_id = nil,
+ page = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ locale = nil)
+ @lm_id = lm_id
+ @page = page
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class WishlistRequest
+ @@schema_type = "WishlistRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def wishlist_id
+ @wishlist_id
+ end
+
+ def wishlist_id=(value)
+ @wishlist_id = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(wishlist_id = nil,
+ page = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ locale = nil)
+ @wishlist_id = wishlist_id
+ @page = page
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class MarketplaceRequest
+ @@schema_type = "MarketplaceRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def marketplace_search
+ @marketplace_search
+ end
+
+ def marketplace_search=(value)
+ @marketplace_search = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def keyword
+ @keyword
+ end
+
+ def keyword=(value)
+ @keyword = value
+ end
+
+ def keyword_search
+ @keyword_search
+ end
+
+ def keyword_search=(value)
+ @keyword_search = value
+ end
+
+ def browse_id
+ @browse_id
+ end
+
+ def browse_id=(value)
+ @browse_id = value
+ end
+
+ def zipcode
+ @zipcode
+ end
+
+ def zipcode=(value)
+ @zipcode = value
+ end
+
+ def area_id
+ @area_id
+ end
+
+ def area_id=(value)
+ @area_id = value
+ end
+
+ def geo
+ @geo
+ end
+
+ def geo=(value)
+ @geo = value
+ end
+
+ def sort
+ @sort
+ end
+
+ def sort=(value)
+ @sort = value
+ end
+
+ def listing_id
+ @listing_id
+ end
+
+ def listing_id=(value)
+ @listing_id = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def index
+ @index
+ end
+
+ def index=(value)
+ @index = value
+ end
+
+ def initialize(marketplace_search = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ page = nil,
+ keyword = nil,
+ keyword_search = nil,
+ browse_id = nil,
+ zipcode = nil,
+ area_id = nil,
+ geo = nil,
+ sort = nil,
+ listing_id = nil,
+ locale = nil,
+ index = nil)
+ @marketplace_search = marketplace_search
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @page = page
+ @keyword = keyword
+ @keyword_search = keyword_search
+ @browse_id = browse_id
+ @zipcode = zipcode
+ @area_id = area_id
+ @geo = geo
+ @sort = sort
+ @listing_id = listing_id
+ @locale = locale
+ @index = index
+ end
+end
+
+# http://soap.amazon.com
+class SellerProfileRequest
+ @@schema_type = "SellerProfileRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def seller_id
+ @seller_id
+ end
+
+ def seller_id=(value)
+ @seller_id = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(seller_id = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ page = nil,
+ locale = nil)
+ @seller_id = seller_id
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @page = page
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class SellerRequest
+ @@schema_type = "SellerRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def seller_id
+ @seller_id
+ end
+
+ def seller_id=(value)
+ @seller_id = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def offerstatus
+ @offerstatus
+ end
+
+ def offerstatus=(value)
+ @offerstatus = value
+ end
+
+ def page
+ @page
+ end
+
+ def page=(value)
+ @page = value
+ end
+
+ def seller_browse_id
+ @seller_browse_id
+ end
+
+ def seller_browse_id=(value)
+ @seller_browse_id = value
+ end
+
+ def keyword
+ @keyword
+ end
+
+ def keyword=(value)
+ @keyword = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def index
+ @index
+ end
+
+ def index=(value)
+ @index = value
+ end
+
+ def initialize(seller_id = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ offerstatus = nil,
+ page = nil,
+ seller_browse_id = nil,
+ keyword = nil,
+ locale = nil,
+ index = nil)
+ @seller_id = seller_id
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @offerstatus = offerstatus
+ @page = page
+ @seller_browse_id = seller_browse_id
+ @keyword = keyword
+ @locale = locale
+ @index = index
+ end
+end
+
+# http://soap.amazon.com
+class SimilarityRequest
+ @@schema_type = "SimilarityRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def asin
+ @asin
+ end
+
+ def asin=(value)
+ @asin = value
+ end
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def type
+ @type
+ end
+
+ def type=(value)
+ @type = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(asin = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ locale = nil)
+ @asin = asin
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ItemIdArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ItemIdArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ItemArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ItemArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class Item
+ @@schema_type = "Item"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def ItemId
+ @itemId
+ end
+
+ def ItemId=(value)
+ @itemId = value
+ end
+
+ def ProductName
+ @productName
+ end
+
+ def ProductName=(value)
+ @productName = value
+ end
+
+ def Catalog
+ @catalog
+ end
+
+ def Catalog=(value)
+ @catalog = value
+ end
+
+ def Asin
+ @asin
+ end
+
+ def Asin=(value)
+ @asin = value
+ end
+
+ def ExchangeId
+ @exchangeId
+ end
+
+ def ExchangeId=(value)
+ @exchangeId = value
+ end
+
+ def Quantity
+ @quantity
+ end
+
+ def Quantity=(value)
+ @quantity = value
+ end
+
+ def ListPrice
+ @listPrice
+ end
+
+ def ListPrice=(value)
+ @listPrice = value
+ end
+
+ def OurPrice
+ @ourPrice
+ end
+
+ def OurPrice=(value)
+ @ourPrice = value
+ end
+
+ def initialize(itemId = nil,
+ productName = nil,
+ catalog = nil,
+ asin = nil,
+ exchangeId = nil,
+ quantity = nil,
+ listPrice = nil,
+ ourPrice = nil)
+ @itemId = itemId
+ @productName = productName
+ @catalog = catalog
+ @asin = asin
+ @exchangeId = exchangeId
+ @quantity = quantity
+ @listPrice = listPrice
+ @ourPrice = ourPrice
+ end
+end
+
+# http://soap.amazon.com
+class ItemQuantityArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ItemQuantityArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class ItemQuantity
+ @@schema_type = "ItemQuantity"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def ItemId
+ @itemId
+ end
+
+ def ItemId=(value)
+ @itemId = value
+ end
+
+ def Quantity
+ @quantity
+ end
+
+ def Quantity=(value)
+ @quantity = value
+ end
+
+ def initialize(itemId = nil,
+ quantity = nil)
+ @itemId = itemId
+ @quantity = quantity
+ end
+end
+
+# http://soap.amazon.com
+class AddItemArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "AddItemArray"
+ @@schema_ns = "http://soap.amazon.com"
+end
+
+# http://soap.amazon.com
+class AddItem
+ @@schema_type = "AddItem"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def Asin
+ @asin
+ end
+
+ def Asin=(value)
+ @asin = value
+ end
+
+ def ExchangeId
+ @exchangeId
+ end
+
+ def ExchangeId=(value)
+ @exchangeId = value
+ end
+
+ def Quantity
+ @quantity
+ end
+
+ def Quantity=(value)
+ @quantity = value
+ end
+
+ def initialize(asin = nil,
+ exchangeId = nil,
+ quantity = nil)
+ @asin = asin
+ @exchangeId = exchangeId
+ @quantity = quantity
+ end
+end
+
+# http://soap.amazon.com
+class ShoppingCart
+ @@schema_type = "ShoppingCart"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def PurchaseUrl
+ @purchaseUrl
+ end
+
+ def PurchaseUrl=(value)
+ @purchaseUrl = value
+ end
+
+ def Items
+ @items
+ end
+
+ def Items=(value)
+ @items = value
+ end
+
+ def initialize(cartId = nil,
+ hMAC = nil,
+ purchaseUrl = nil,
+ items = nil)
+ @cartId = cartId
+ @hMAC = hMAC
+ @purchaseUrl = purchaseUrl
+ @items = items
+ end
+end
+
+# http://soap.amazon.com
+class GetShoppingCartRequest
+ @@schema_type = "GetShoppingCartRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(tag = nil,
+ devtag = nil,
+ cartId = nil,
+ hMAC = nil,
+ locale = nil)
+ @tag = tag
+ @devtag = devtag
+ @cartId = cartId
+ @hMAC = hMAC
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ClearShoppingCartRequest
+ @@schema_type = "ClearShoppingCartRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(tag = nil,
+ devtag = nil,
+ cartId = nil,
+ hMAC = nil,
+ locale = nil)
+ @tag = tag
+ @devtag = devtag
+ @cartId = cartId
+ @hMAC = hMAC
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class AddShoppingCartItemsRequest
+ @@schema_type = "AddShoppingCartItemsRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def Items
+ @items
+ end
+
+ def Items=(value)
+ @items = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(tag = nil,
+ devtag = nil,
+ cartId = nil,
+ hMAC = nil,
+ items = nil,
+ locale = nil)
+ @tag = tag
+ @devtag = devtag
+ @cartId = cartId
+ @hMAC = hMAC
+ @items = items
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class RemoveShoppingCartItemsRequest
+ @@schema_type = "RemoveShoppingCartItemsRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def Items
+ @items
+ end
+
+ def Items=(value)
+ @items = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(tag = nil,
+ devtag = nil,
+ cartId = nil,
+ hMAC = nil,
+ items = nil,
+ locale = nil)
+ @tag = tag
+ @devtag = devtag
+ @cartId = cartId
+ @hMAC = hMAC
+ @items = items
+ @locale = locale
+ end
+end
+
+# http://soap.amazon.com
+class ModifyShoppingCartItemsRequest
+ @@schema_type = "ModifyShoppingCartItemsRequest"
+ @@schema_ns = "http://soap.amazon.com"
+
+ def tag
+ @tag
+ end
+
+ def tag=(value)
+ @tag = value
+ end
+
+ def devtag
+ @devtag
+ end
+
+ def devtag=(value)
+ @devtag = value
+ end
+
+ def CartId
+ @cartId
+ end
+
+ def CartId=(value)
+ @cartId = value
+ end
+
+ def HMAC
+ @hMAC
+ end
+
+ def HMAC=(value)
+ @hMAC = value
+ end
+
+ def Items
+ @items
+ end
+
+ def Items=(value)
+ @items = value
+ end
+
+ def locale
+ @locale
+ end
+
+ def locale=(value)
+ @locale = value
+ end
+
+ def initialize(tag = nil,
+ devtag = nil,
+ cartId = nil,
+ hMAC = nil,
+ items = nil,
+ locale = nil)
+ @tag = tag
+ @devtag = devtag
+ @cartId = cartId
+ @hMAC = hMAC
+ @items = items
+ @locale = locale
+ end
+end
+
diff --git a/sample/wsdl/amazon/AmazonSearchDriver.rb b/sample/wsdl/amazon/AmazonSearchDriver.rb
new file mode 100644
index 0000000000..bf532b75a5
--- /dev/null
+++ b/sample/wsdl/amazon/AmazonSearchDriver.rb
@@ -0,0 +1,445 @@
+require 'AmazonSearch.rb'
+
+require 'soap/rpc/driver'
+
+class AmazonSearchPort < SOAP::RPC::Driver
+ MappingRegistry = ::SOAP::Mapping::Registry.new
+
+ MappingRegistry.set(
+ KeywordRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "KeywordRequest") }
+ )
+ MappingRegistry.set(
+ ProductInfo,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ProductInfo") }
+ )
+ MappingRegistry.set(
+ DetailsArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "Details") }
+ )
+ MappingRegistry.set(
+ PowerRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "PowerRequest") }
+ )
+ MappingRegistry.set(
+ BrowseNodeRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "BrowseNodeRequest") }
+ )
+ MappingRegistry.set(
+ AsinRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "AsinRequest") }
+ )
+ MappingRegistry.set(
+ BlendedRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "BlendedRequest") }
+ )
+ MappingRegistry.set(
+ ProductLineArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ProductLine") }
+ )
+ MappingRegistry.set(
+ UpcRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "UpcRequest") }
+ )
+ MappingRegistry.set(
+ AuthorRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "AuthorRequest") }
+ )
+ MappingRegistry.set(
+ ArtistRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ArtistRequest") }
+ )
+ MappingRegistry.set(
+ ActorRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ActorRequest") }
+ )
+ MappingRegistry.set(
+ ManufacturerRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ManufacturerRequest") }
+ )
+ MappingRegistry.set(
+ DirectorRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "DirectorRequest") }
+ )
+ MappingRegistry.set(
+ ListManiaRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ListManiaRequest") }
+ )
+ MappingRegistry.set(
+ WishlistRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "WishlistRequest") }
+ )
+ MappingRegistry.set(
+ ExchangeRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ExchangeRequest") }
+ )
+ MappingRegistry.set(
+ ListingProductDetails,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ListingProductDetails") }
+ )
+ MappingRegistry.set(
+ MarketplaceRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "MarketplaceRequest") }
+ )
+ MappingRegistry.set(
+ MarketplaceSearch,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "MarketplaceSearch") }
+ )
+ MappingRegistry.set(
+ MarketplaceSearchDetailsArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "MarketplaceSearchDetails") }
+ )
+ MappingRegistry.set(
+ SellerProfileRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerProfileRequest") }
+ )
+ MappingRegistry.set(
+ SellerProfile,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerProfile") }
+ )
+ MappingRegistry.set(
+ SellerProfileDetailsArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerProfileDetails") }
+ )
+ MappingRegistry.set(
+ SellerRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerRequest") }
+ )
+ MappingRegistry.set(
+ SellerSearch,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerSearch") }
+ )
+ MappingRegistry.set(
+ SellerSearchDetailsArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerSearchDetails") }
+ )
+ MappingRegistry.set(
+ SimilarityRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SimilarityRequest") }
+ )
+ MappingRegistry.set(
+ GetShoppingCartRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "GetShoppingCartRequest") }
+ )
+ MappingRegistry.set(
+ ShoppingCart,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ShoppingCart") }
+ )
+ MappingRegistry.set(
+ ItemArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "Item") }
+ )
+ MappingRegistry.set(
+ ClearShoppingCartRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ClearShoppingCartRequest") }
+ )
+ MappingRegistry.set(
+ AddShoppingCartItemsRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "AddShoppingCartItemsRequest") }
+ )
+ MappingRegistry.set(
+ AddItemArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "AddItem") }
+ )
+ MappingRegistry.set(
+ RemoveShoppingCartItemsRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "RemoveShoppingCartItemsRequest") }
+ )
+ MappingRegistry.set(
+ ItemIdArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://www.w3.org/2001/XMLSchema", "string") }
+ )
+ MappingRegistry.set(
+ ModifyShoppingCartItemsRequest,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ModifyShoppingCartItemsRequest") }
+ )
+ MappingRegistry.set(
+ ItemQuantityArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ItemQuantity") }
+ )
+ MappingRegistry.set(
+ Details,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "Details") }
+ )
+ MappingRegistry.set(
+ ProductLine,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ProductLine") }
+ )
+ MappingRegistry.set(
+ MarketplaceSearchDetails,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "MarketplaceSearchDetails") }
+ )
+ MappingRegistry.set(
+ SellerProfileDetails,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerProfileDetails") }
+ )
+ MappingRegistry.set(
+ SellerSearchDetails,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "SellerSearchDetails") }
+ )
+ MappingRegistry.set(
+ Item,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "Item") }
+ )
+ MappingRegistry.set(
+ AddItem,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "AddItem") }
+ )
+ MappingRegistry.set(
+ ItemQuantity,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("http://soap.amazon.com", "ItemQuantity") }
+ )
+
+ Methods = [
+ ["KeywordSearchRequest", "keywordSearchRequest", [
+ ["in", "KeywordSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "KeywordRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["PowerSearchRequest", "powerSearchRequest", [
+ ["in", "PowerSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "PowerRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["BrowseNodeSearchRequest", "browseNodeSearchRequest", [
+ ["in", "BrowseNodeSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "BrowseNodeRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["AsinSearchRequest", "asinSearchRequest", [
+ ["in", "AsinSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "AsinRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["BlendedSearchRequest", "blendedSearchRequest", [
+ ["in", "BlendedSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "BlendedRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPArray, "http://soap.amazon.com", "ProductLine"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["UpcSearchRequest", "upcSearchRequest", [
+ ["in", "UpcSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "UpcRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["AuthorSearchRequest", "authorSearchRequest", [
+ ["in", "AuthorSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "AuthorRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ArtistSearchRequest", "artistSearchRequest", [
+ ["in", "ArtistSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ArtistRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ActorSearchRequest", "actorSearchRequest", [
+ ["in", "ActorSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ActorRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ManufacturerSearchRequest", "manufacturerSearchRequest", [
+ ["in", "ManufacturerSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ManufacturerRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["DirectorSearchRequest", "directorSearchRequest", [
+ ["in", "DirectorSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "DirectorRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ListManiaSearchRequest", "listManiaSearchRequest", [
+ ["in", "ListManiaSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ListManiaRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["WishlistSearchRequest", "wishlistSearchRequest", [
+ ["in", "WishlistSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "WishlistRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ExchangeSearchRequest", "exchangeSearchRequest", [
+ ["in", "ExchangeSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ExchangeRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ListingProductDetails"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["MarketplaceSearchRequest", "marketplaceSearchRequest", [
+ ["in", "MarketplaceSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "MarketplaceRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "MarketplaceSearch"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["SellerProfileSearchRequest", "sellerProfileSearchRequest", [
+ ["in", "SellerProfileSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "SellerProfileRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "SellerProfile"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["SellerSearchRequest", "sellerSearchRequest", [
+ ["in", "SellerSearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "SellerRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "SellerSearch"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["SimilaritySearchRequest", "similaritySearchRequest", [
+ ["in", "SimilaritySearchRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "SimilarityRequest"]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ProductInfo"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["GetShoppingCartRequest", "getShoppingCartRequest", [
+ ["in", "GetShoppingCartRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "GetShoppingCartRequest"]],
+ ["retval", "ShoppingCart",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ShoppingCart"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ClearShoppingCartRequest", "clearShoppingCartRequest", [
+ ["in", "ClearShoppingCartRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ClearShoppingCartRequest"]],
+ ["retval", "ShoppingCart",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ShoppingCart"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["AddShoppingCartItemsRequest", "addShoppingCartItemsRequest", [
+ ["in", "AddShoppingCartItemsRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "AddShoppingCartItemsRequest"]],
+ ["retval", "ShoppingCart",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ShoppingCart"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["RemoveShoppingCartItemsRequest", "removeShoppingCartItemsRequest", [
+ ["in", "RemoveShoppingCartItemsRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "RemoveShoppingCartItemsRequest"]],
+ ["retval", "ShoppingCart",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ShoppingCart"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"],
+ ["ModifyShoppingCartItemsRequest", "modifyShoppingCartItemsRequest", [
+ ["in", "ModifyShoppingCartItemsRequest",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ModifyShoppingCartItemsRequest"]],
+ ["retval", "ShoppingCart",
+ [::SOAP::SOAPStruct, "http://soap.amazon.com", "ShoppingCart"]]],
+ "http://soap.amazon.com", "http://soap.amazon.com"]
+ ]
+
+ DefaultEndpointUrl = "http://soap.amazon.com/onca/soap2"
+
+ def initialize(endpoint_url = nil)
+ endpoint_url ||= DefaultEndpointUrl
+ super(endpoint_url, nil)
+ self.mapping_registry = MappingRegistry
+ init_methods
+ end
+
+private
+
+ def init_methods
+ Methods.each do |name_as, name, params, soapaction, namespace|
+ qname = XSD::QName.new(namespace, name_as)
+ @proxy.add_method(qname, soapaction, name, params)
+ add_rpc_method_interface(name, params)
+ end
+ end
+end
+
diff --git a/sample/wsdl/amazon/sampleClient.rb b/sample/wsdl/amazon/sampleClient.rb
new file mode 100644
index 0000000000..71bafd7345
--- /dev/null
+++ b/sample/wsdl/amazon/sampleClient.rb
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+
+# This file is a sample based on AmazonSearchServiceClient.rb, which can be
+# generated by WSDL file and wsdl2ruby.rb.
+#
+# $ wsdl2ruby.rb --type client --force \
+# --wsdl http://soap.amazon.com/schemas2/AmazonWebServices.wsdl
+#
+# See wsdlDriver.rb to use WSDL file directly (slow).
+require 'AmazonSearchDriver.rb'
+
+endpoint_url = ARGV.shift
+obj = AmazonSearchPort.new(endpoint_url)
+
+# Uncomment the below line to see SOAP wiredumps.
+# obj.wiredump_dev = STDERR
+
+# SYNOPSIS
+# KeywordSearchRequest(keywordSearchRequest)
+#
+# ARGS
+# keywordSearchRequest KeywordRequest - {urn:PI/DevCentral/SoapService}KeywordRequest
+#
+# RETURNS
+# return ProductInfo - {urn:PI/DevCentral/SoapService}ProductInfo
+#
+# RAISES
+# N/A
+#
+keywordSearchRequest = KeywordRequest.new("Ruby Object", "1", "books", "webservices-20", "lite", "", "+salesrank")
+obj.keywordSearchRequest(keywordSearchRequest).Details.each do |detail|
+ puts "== #{detail.ProductName}"
+ puts "Author: #{detail.Authors.join(", ")}"
+ puts "Release date: #{detail.ReleaseDate}"
+ puts "List price: #{detail.ListPrice}, our price: #{detail.OurPrice}"
+ puts
+end
diff --git a/sample/wsdl/amazon/wsdlDriver.rb b/sample/wsdl/amazon/wsdlDriver.rb
new file mode 100644
index 0000000000..baf55a4968
--- /dev/null
+++ b/sample/wsdl/amazon/wsdlDriver.rb
@@ -0,0 +1,48 @@
+require 'soap/wsdlDriver'
+
+book = ARGV.shift || "Ruby"
+
+# AmazonSearch.rb is generated from WSDL.
+# Run "wsdl2ruby.rb --wsdl http://soap.amazon.com/schemas2/AmazonWebServices.wsdl --classDef --force"
+require 'AmazonSearch.rb'
+
+=begin
+Or, define the class by yourself like this.
+
+class KeywordRequest
+ def initialize(keyword = nil,
+ page = nil,
+ mode = nil,
+ tag = nil,
+ type = nil,
+ devtag = nil,
+ sort = nil)
+ @keyword = keyword
+ @page = page
+ @mode = mode
+ @tag = tag
+ @type = type
+ @devtag = devtag
+ @sort = sort
+ end
+end
+=end
+
+# You must get 'developer's token" from http://associates.amazon.com/exec/panama/associates/ntg/browse/-/1067662 to use Amazon Web Services 2.0.
+#devtag = File.open(File.expand_path("~/.amazon_key")).read.chomp
+
+AMAZON_WSDL = 'http://soap.amazon.com/schemas2/AmazonWebServices.wsdl'
+amazon = SOAP::WSDLDriverFactory.new(AMAZON_WSDL).create_driver
+p "WSDL loaded"
+amazon.generate_explicit_type = true
+#amazon.wiredump_dev = STDERR
+
+# Show sales rank.
+req = KeywordRequest.new(book, "1", "books", "webservices-20", "lite", devtag, "+salesrank")
+amazon.KeywordSearchRequest(req).Details.each do |detail|
+ puts "== #{detail.ProductName}"
+ puts "Author: #{detail.Authors.join(", ")}"
+ puts "Release date: #{detail.ReleaseDate}"
+ puts "List price: #{detail.ListPrice}, our price: #{detail.OurPrice}"
+ puts
+end
diff --git a/sample/wsdl/googleSearch/GoogleSearch.rb b/sample/wsdl/googleSearch/GoogleSearch.rb
new file mode 100644
index 0000000000..e124208b91
--- /dev/null
+++ b/sample/wsdl/googleSearch/GoogleSearch.rb
@@ -0,0 +1,258 @@
+# urn:GoogleSearch
+class GoogleSearchResult
+ @@schema_type = "GoogleSearchResult"
+ @@schema_ns = "urn:GoogleSearch"
+
+ def documentFiltering
+ @documentFiltering
+ end
+
+ def documentFiltering=(value)
+ @documentFiltering = value
+ end
+
+ def searchComments
+ @searchComments
+ end
+
+ def searchComments=(value)
+ @searchComments = value
+ end
+
+ def estimatedTotalResultsCount
+ @estimatedTotalResultsCount
+ end
+
+ def estimatedTotalResultsCount=(value)
+ @estimatedTotalResultsCount = value
+ end
+
+ def estimateIsExact
+ @estimateIsExact
+ end
+
+ def estimateIsExact=(value)
+ @estimateIsExact = value
+ end
+
+ def resultElements
+ @resultElements
+ end
+
+ def resultElements=(value)
+ @resultElements = value
+ end
+
+ def searchQuery
+ @searchQuery
+ end
+
+ def searchQuery=(value)
+ @searchQuery = value
+ end
+
+ def startIndex
+ @startIndex
+ end
+
+ def startIndex=(value)
+ @startIndex = value
+ end
+
+ def endIndex
+ @endIndex
+ end
+
+ def endIndex=(value)
+ @endIndex = value
+ end
+
+ def searchTips
+ @searchTips
+ end
+
+ def searchTips=(value)
+ @searchTips = value
+ end
+
+ def directoryCategories
+ @directoryCategories
+ end
+
+ def directoryCategories=(value)
+ @directoryCategories = value
+ end
+
+ def searchTime
+ @searchTime
+ end
+
+ def searchTime=(value)
+ @searchTime = value
+ end
+
+ def initialize(documentFiltering = nil,
+ searchComments = nil,
+ estimatedTotalResultsCount = nil,
+ estimateIsExact = nil,
+ resultElements = nil,
+ searchQuery = nil,
+ startIndex = nil,
+ endIndex = nil,
+ searchTips = nil,
+ directoryCategories = nil,
+ searchTime = nil)
+ @documentFiltering = documentFiltering
+ @searchComments = searchComments
+ @estimatedTotalResultsCount = estimatedTotalResultsCount
+ @estimateIsExact = estimateIsExact
+ @resultElements = resultElements
+ @searchQuery = searchQuery
+ @startIndex = startIndex
+ @endIndex = endIndex
+ @searchTips = searchTips
+ @directoryCategories = directoryCategories
+ @searchTime = searchTime
+ end
+end
+
+# urn:GoogleSearch
+class ResultElement
+ @@schema_type = "ResultElement"
+ @@schema_ns = "urn:GoogleSearch"
+
+ def summary
+ @summary
+ end
+
+ def summary=(value)
+ @summary = value
+ end
+
+ def URL
+ @uRL
+ end
+
+ def URL=(value)
+ @uRL = value
+ end
+
+ def snippet
+ @snippet
+ end
+
+ def snippet=(value)
+ @snippet = value
+ end
+
+ def title
+ @title
+ end
+
+ def title=(value)
+ @title = value
+ end
+
+ def cachedSize
+ @cachedSize
+ end
+
+ def cachedSize=(value)
+ @cachedSize = value
+ end
+
+ def relatedInformationPresent
+ @relatedInformationPresent
+ end
+
+ def relatedInformationPresent=(value)
+ @relatedInformationPresent = value
+ end
+
+ def hostName
+ @hostName
+ end
+
+ def hostName=(value)
+ @hostName = value
+ end
+
+ def directoryCategory
+ @directoryCategory
+ end
+
+ def directoryCategory=(value)
+ @directoryCategory = value
+ end
+
+ def directoryTitle
+ @directoryTitle
+ end
+
+ def directoryTitle=(value)
+ @directoryTitle = value
+ end
+
+ def initialize(summary = nil,
+ uRL = nil,
+ snippet = nil,
+ title = nil,
+ cachedSize = nil,
+ relatedInformationPresent = nil,
+ hostName = nil,
+ directoryCategory = nil,
+ directoryTitle = nil)
+ @summary = summary
+ @uRL = uRL
+ @snippet = snippet
+ @title = title
+ @cachedSize = cachedSize
+ @relatedInformationPresent = relatedInformationPresent
+ @hostName = hostName
+ @directoryCategory = directoryCategory
+ @directoryTitle = directoryTitle
+ end
+end
+
+# urn:GoogleSearch
+class ResultElementArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "ResultElementArray"
+ @@schema_ns = "urn:GoogleSearch"
+end
+
+# urn:GoogleSearch
+class DirectoryCategoryArray < Array
+ # Contents type should be dumped here...
+ @@schema_type = "DirectoryCategoryArray"
+ @@schema_ns = "urn:GoogleSearch"
+end
+
+# urn:GoogleSearch
+class DirectoryCategory
+ @@schema_type = "DirectoryCategory"
+ @@schema_ns = "urn:GoogleSearch"
+
+ def fullViewableName
+ @fullViewableName
+ end
+
+ def fullViewableName=(value)
+ @fullViewableName = value
+ end
+
+ def specialEncoding
+ @specialEncoding
+ end
+
+ def specialEncoding=(value)
+ @specialEncoding = value
+ end
+
+ def initialize(fullViewableName = nil,
+ specialEncoding = nil)
+ @fullViewableName = fullViewableName
+ @specialEncoding = specialEncoding
+ end
+end
+
diff --git a/sample/wsdl/googleSearch/GoogleSearchDriver.rb b/sample/wsdl/googleSearch/GoogleSearchDriver.rb
new file mode 100644
index 0000000000..9901b89071
--- /dev/null
+++ b/sample/wsdl/googleSearch/GoogleSearchDriver.rb
@@ -0,0 +1,101 @@
+require 'GoogleSearch.rb'
+
+require 'soap/rpc/driver'
+
+class GoogleSearchPort < SOAP::RPC::Driver
+ MappingRegistry = ::SOAP::Mapping::Registry.new
+
+ MappingRegistry.set(
+ GoogleSearchResult,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("urn:GoogleSearch", "GoogleSearchResult") }
+ )
+ MappingRegistry.set(
+ ResultElementArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("urn:GoogleSearch", "ResultElement") }
+ )
+ MappingRegistry.set(
+ DirectoryCategoryArray,
+ ::SOAP::SOAPArray,
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
+ { :type => XSD::QName.new("urn:GoogleSearch", "DirectoryCategory") }
+ )
+ MappingRegistry.set(
+ ResultElement,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("urn:GoogleSearch", "ResultElement") }
+ )
+ MappingRegistry.set(
+ DirectoryCategory,
+ ::SOAP::SOAPStruct,
+ ::SOAP::Mapping::Registry::TypedStructFactory,
+ { :type => XSD::QName.new("urn:GoogleSearch", "DirectoryCategory") }
+ )
+
+ Methods = [
+ ["doGetCachedPage", "doGetCachedPage", [
+ ["in", "key",
+ [SOAP::SOAPString]],
+ ["in", "url",
+ [SOAP::SOAPString]],
+ ["retval", "return",
+ [SOAP::SOAPBase64]]],
+ "urn:GoogleSearchAction", "urn:GoogleSearch"],
+ ["doSpellingSuggestion", "doSpellingSuggestion", [
+ ["in", "key",
+ [SOAP::SOAPString]],
+ ["in", "phrase",
+ [SOAP::SOAPString]],
+ ["retval", "return",
+ [SOAP::SOAPString]]],
+ "urn:GoogleSearchAction", "urn:GoogleSearch"],
+ ["doGoogleSearch", "doGoogleSearch", [
+ ["in", "key",
+ [SOAP::SOAPString]],
+ ["in", "q",
+ [SOAP::SOAPString]],
+ ["in", "start",
+ [SOAP::SOAPInt]],
+ ["in", "maxResults",
+ [SOAP::SOAPInt]],
+ ["in", "filter",
+ [SOAP::SOAPBoolean]],
+ ["in", "restrict",
+ [SOAP::SOAPString]],
+ ["in", "safeSearch",
+ [SOAP::SOAPBoolean]],
+ ["in", "lr",
+ [SOAP::SOAPString]],
+ ["in", "ie",
+ [SOAP::SOAPString]],
+ ["in", "oe",
+ [SOAP::SOAPString]],
+ ["retval", "return",
+ [::SOAP::SOAPStruct, "urn:GoogleSearch", "GoogleSearchResult"]]],
+ "urn:GoogleSearchAction", "urn:GoogleSearch"]
+ ]
+
+ DefaultEndpointUrl = "http://api.google.com/search/beta2"
+
+ def initialize(endpoint_url = nil)
+ endpoint_url ||= DefaultEndpointUrl
+ super(endpoint_url, nil)
+ self.mapping_registry = MappingRegistry
+ init_methods
+ end
+
+private
+
+ def init_methods
+ Methods.each do |name_as, name, params, soapaction, namespace|
+ qname = XSD::QName.new(namespace, name_as)
+ @proxy.add_method(qname, soapaction, name, params)
+ add_rpc_method_interface(name, params)
+ end
+ end
+end
+
diff --git a/sample/wsdl/googleSearch/README b/sample/wsdl/googleSearch/README
new file mode 100644
index 0000000000..461a5634dc
--- /dev/null
+++ b/sample/wsdl/googleSearch/README
@@ -0,0 +1,6 @@
+wsdlDriver.rb: Do google search using WSDL.
+
+Whole files except wsdl.rb in this directory is created by wsdl2ruby.rb from
+GoogleSearch.wsdl with options;
+
+% wsdl2ruby.rb --wsdl http://api.google.com/GoogleSearch.wsdl --classdef --client_skelton --servant_skelton --cgi_stub --standalone_server_stub --driver --force
diff --git a/sample/wsdl/googleSearch/httpd.rb b/sample/wsdl/googleSearch/httpd.rb
new file mode 100644
index 0000000000..ee8ab09f50
--- /dev/null
+++ b/sample/wsdl/googleSearch/httpd.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'webrick'
+require 'getopts'
+
+getopts "", 'r:', 'p:8808'
+
+s = WEBrick::HTTPServer.new(
+ :BindAddress => "0.0.0.0",
+ :Port => $OPT_p.to_i,
+ :DocumentRoot => $OPT_r || ".",
+ :CGIPathEnv => ENV['PATH']
+)
+trap(:INT){ s.shutdown }
+s.start
diff --git a/sample/wsdl/googleSearch/sampleClient.rb b/sample/wsdl/googleSearch/sampleClient.rb
new file mode 100644
index 0000000000..38e7253ef5
--- /dev/null
+++ b/sample/wsdl/googleSearch/sampleClient.rb
@@ -0,0 +1,56 @@
+#!/usr/bin/env ruby
+
+# This file is a sample based on GoogleSearchClient.rb, which can be
+# generated by WSDL file and wsdl2ruby.rb.
+#
+# $ wsdl2ruby.rb --type client --force \
+# --wsdl http://api.google.com/GoogleSearch.wsdl
+#
+# See wsdlDriver.rb to use WSDL file directly (slow).
+require 'GoogleSearchDriver.rb'
+
+endpoint_url = ARGV.shift
+obj = GoogleSearchPort.new(endpoint_url)
+
+# Uncomment the below line to see SOAP wiredumps.
+# obj.wiredump_dev = STDERR
+
+# SYNOPSIS
+# doGoogleSearch(key, q, start, maxResults, filter, restrict, safeSearch, lr, ie, oe)
+#
+# ARGS
+# key - {http://www.w3.org/2001/XMLSchema}string
+# q - {http://www.w3.org/2001/XMLSchema}string
+# start - {http://www.w3.org/2001/XMLSchema}int
+# maxResults - {http://www.w3.org/2001/XMLSchema}int
+# filter - {http://www.w3.org/2001/XMLSchema}boolean
+# restrict - {http://www.w3.org/2001/XMLSchema}string
+# safeSearch - {http://www.w3.org/2001/XMLSchema}boolean
+# lr - {http://www.w3.org/2001/XMLSchema}string
+# ie - {http://www.w3.org/2001/XMLSchema}string
+# oe - {http://www.w3.org/2001/XMLSchema}string
+#
+# RETURNS
+# return GoogleSearchResult - {urn:GoogleSearch}GoogleSearchResult
+#
+# RAISES
+# N/A
+#
+key = q = start = maxResults = filter = restrict = safeSearch = lr = ie = oe = nil
+key = File.open(File.expand_path("~/.google_key")).read.chomp
+q = "Ruby"
+start = 0
+maxResults = 10
+filter = false
+restrict = ""
+safeSearch = false
+lr = ""
+ie = "utf-8"
+oe = "utf-8"
+result = obj.doGoogleSearch(key, q, start, maxResults, filter, restrict, safeSearch, lr, ie, oe)
+
+result.resultElements.each do |ele|
+ puts "== #{ele.title}: #{ele.URL}"
+ puts ele.snippet
+ puts
+end
diff --git a/sample/wsdl/googleSearch/sjissearch.sh b/sample/wsdl/googleSearch/sjissearch.sh
new file mode 100644
index 0000000000..b8efb20647
--- /dev/null
+++ b/sample/wsdl/googleSearch/sjissearch.sh
@@ -0,0 +1,3 @@
+#!/bin/sh -
+
+ruby -Ks wsdlDriver.rb 'Ruby ‚È‚Ð'
diff --git a/sample/wsdl/googleSearch/wsdlDriver.rb b/sample/wsdl/googleSearch/wsdlDriver.rb
new file mode 100644
index 0000000000..e8b91abfe2
--- /dev/null
+++ b/sample/wsdl/googleSearch/wsdlDriver.rb
@@ -0,0 +1,23 @@
+#require 'uconv'
+require 'soap/wsdlDriver'
+
+word = ARGV.shift
+# You must get key from http://www.google.com/apis/ to use Google Web APIs.
+key = File.open(File.expand_path("~/.google_key")).read.chomp
+
+GOOGLE_WSDL = 'http://api.google.com/GoogleSearch.wsdl'
+# GOOGLE_WSDL = 'GoogleSearch.wsdl'
+
+def html2rd(str)
+ str.gsub(%r(<b>(.*?)</b>), '((*\\1*))').strip
+end
+
+
+google = SOAP::WSDLDriverFactory.new(GOOGLE_WSDL).create_driver
+#google.wiredump_dev = STDERR
+result = google.doGoogleSearch( key, word, 0, 10, false, "", false, "", 'utf-8', 'utf-8' )
+result.resultElements.each do |ele|
+ puts "== #{html2rd(ele.title)}: #{ele.URL}"
+ puts html2rd(ele.snippet)
+ puts
+end
diff --git a/sample/wsdl/raa/raa.wsdl b/sample/wsdl/raa/raa.wsdl
new file mode 100644
index 0000000000..78376893dd
--- /dev/null
+++ b/sample/wsdl/raa/raa.wsdl
@@ -0,0 +1,264 @@
+<?xml version="1.0"?>
+<definitions
+ name="RAA"
+ targetNamespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"
+ xmlns:tns="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"
+ xmlns:txd="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:apachesoap="http://xml.apache.org/xml-soap">
+
+ <types>
+ <schema
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/">
+
+ <complexType name="Category">
+ <all>
+ <element name="major" type="string"/>
+ <element name="minor" type="string"/>
+ </all>
+ </complexType>
+
+ <complexType name="Product">
+ <all>
+ <element name="id" type="int"/>
+ <element name="name" type="string"/>
+ <element name="short_description" type="string"/>
+ <element name="version" type="string"/>
+ <element name="status" type="string"/>
+ <element name="homepage" type="anyURI"/>
+ <element name="download" type="anyURI"/>
+ <element name="license" type="string"/>
+ <element name="description" type="string"/>
+ </all>
+ </complexType>
+
+ <complexType name="Owner">
+ <all>
+ <element name="id" type="int"/>
+ <element name="email" type="anyURI"/>
+ <element name="name" type="string"/>
+ </all>
+ </complexType>
+
+ <complexType name="Info">
+ <all>
+ <element name="category" type="txd:Category"/>
+ <element name="product" type="txd:Product"/>
+ <element name="owner" type="txd:Owner"/>
+ <element name="created" type="xsd:dateTime"/>
+ <element name="updated" type="xsd:dateTime"/>
+ </all>
+ </complexType>
+
+ <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
+ <complexType name="InfoArray">
+ <complexContent>
+ <restriction base="soapenc:Array">
+ <attribute ref="soapenc:arrayType" wsdl:arrayType="txd:Info[]"/>
+ </restriction>
+ </complexContent>
+ </complexType>
+
+ <complexType name="StringArray">
+ <complexContent>
+ <restriction base="soapenc:Array">
+ <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
+ </restriction>
+ </complexContent>
+ </complexType>
+ </schema>
+
+ <!-- type definition for ApacheSOAP's Map -->
+ <schema
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://xml.apache.org/xml-soap">
+ <complexType name="Map">
+ <sequence>
+ <element name="item" minOccurs="0" maxOccurs="unbounded">
+ <complexType>
+ <sequence>
+ <element name="key" type="anyType" />
+ <element name="value" type="anyType" />
+ </sequence>
+ </complexType>
+ </element>
+ </sequence>
+ </complexType>
+ </schema>
+ </types>
+
+ <message name="getAllListingsRequest"/>
+ <message name="getAllListingsResponse">
+ <part name="return" type="txd:StringArray"/>
+ </message>
+
+ <message name="getProductTreeRequest"/>
+ <message name="getProductTreeResponse">
+ <part name="return" type="apachesoap:Map"/>
+ </message>
+
+ <message name="getInfoFromCategoryRequest">
+ <part name="category" type="txd:Category"/>
+ </message>
+ <message name="getInfoFromCategoryResponse">
+ <part name="return" type="txd:InfoArray"/>
+ </message>
+
+ <message name="getModifiedInfoSinceRequest">
+ <part name="timeInstant" type="xsd:dateTime"/>
+ </message>
+ <message name="getModifiedInfoSinceResponse">
+ <part name="return" type="txd:InfoArray"/>
+ </message>
+
+ <message name="getInfoFromNameRequest">
+ <part name="productName" type="xsd:string"/>
+ </message>
+ <message name="getInfoFromNameResponse">
+ <part name="return" type="txd:Info"/>
+ </message>
+
+ <message name="getInfoFromOwnerIdRequest">
+ <part name="ownerId" type="xsd:int"/>
+ </message>
+ <message name="getInfoFromOwnerIdResponse">
+ <part name="return" type="txd:InfoArray"/>
+ </message>
+
+ <portType name="RAABaseServicePortType">
+ <operation name="getAllListings"
+ parameterOrder="">
+ <input message="tns:getAllListingsRequest"/>
+ <output message="tns:getAllListingsResponse"/>
+ </operation>
+
+ <operation name="getProductTree"
+ parameterOrder="">
+ <input message="tns:getProductTreeRequest"/>
+ <output message="tns:getProductTreeResponse"/>
+ </operation>
+
+ <operation name="getInfoFromCategory"
+ parameterOrder="category">
+ <input message="tns:getInfoFromCategoryRequest"/>
+ <output message="tns:getInfoFromCategoryResponse"/>
+ </operation>
+
+ <operation name="getModifiedInfoSince"
+ parameterOrder="timeInstant">
+ <input message="tns:getModifiedInfoSinceRequest"/>
+ <output message="tns:getModifiedInfoSinceResponse"/>
+ </operation>
+
+ <operation name="getInfoFromName"
+ parameterOrder="productName">
+ <input message="tns:getInfoFromNameRequest"/>
+ <output message="tns:getInfoFromNameResponse"/>
+ </operation>
+
+ <operation name="getInfoFromOwnerId"
+ parameterOrder="ownerId">
+ <input message="tns:getInfoFromOwnerIdRequest"/>
+ <output message="tns:getInfoFromOwnerIdResponse"/>
+ </operation>
+ </portType>
+
+ <binding name="RAABaseServicePortBinding" type="tns:RAABaseServicePortType">
+ <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+
+ <operation name="getAllListings">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+
+ <operation name="getProductTree">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+
+ <operation name="getInfoFromCategory">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+
+ <operation name="getModifiedInfoSince">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+
+ <operation name="getInfoFromName">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+
+ <operation name="getInfoFromOwnerId">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </input>
+ <output>
+ <soap:body use="encoded"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ namespace="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"/>
+ </output>
+ </operation>
+ </binding>
+
+ <service name="RAAService">
+ <port name="RAABaseServicePort" binding="tns:RAABaseServicePortBinding">
+ <soap:address location="http://raa.ruby-lang.org/soap/1.0.2/"/>
+ </port>
+ </service>
+</definitions>
diff --git a/sample/wsdl/raa/soap4r.rb b/sample/wsdl/raa/soap4r.rb
new file mode 100644
index 0000000000..a70b3b5b21
--- /dev/null
+++ b/sample/wsdl/raa/soap4r.rb
@@ -0,0 +1,31 @@
+#!/usr/bin/env ruby
+
+require 'soap/wsdlDriver'
+wsdl = 'http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/'
+raa = SOAP::WSDLDriverFactory.new(wsdl).create_driver
+raa.generate_explicit_type = true
+p "WSDL loaded."
+
+class Category
+ def initialize(major, minor)
+ @major = major
+ @minor = minor
+ end
+end
+
+p raa.getAllListings().sort
+
+p raa.getProductTree()
+
+p raa.getInfoFromCategory(Category.new("Library", "XML"))
+
+t = Time.at(Time.now.to_i - 24 * 3600)
+p raa.getModifiedInfoSince(t)
+
+p raa.getModifiedInfoSince(DateTime.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec))
+
+o = raa.getInfoFromName("SOAP4R")
+p o.type
+p o.owner.name
+p o
+
diff --git a/test/soap/calc/calc.rb b/test/soap/calc/calc.rb
new file mode 100644
index 0000000000..6bc78803b3
--- /dev/null
+++ b/test/soap/calc/calc.rb
@@ -0,0 +1,17 @@
+module CalcService
+ def self.add(lhs, rhs)
+ lhs + rhs
+ end
+
+ def self.sub(lhs, rhs)
+ lhs - rhs
+ end
+
+ def self.multi(lhs, rhs)
+ lhs * rhs
+ end
+
+ def self.div(lhs, rhs)
+ lhs / rhs
+ end
+end
diff --git a/test/soap/calc/calc2.rb b/test/soap/calc/calc2.rb
new file mode 100644
index 0000000000..e9cf6bbca7
--- /dev/null
+++ b/test/soap/calc/calc2.rb
@@ -0,0 +1,29 @@
+class CalcService2
+ def initialize(value = 0)
+ @value = value
+ end
+
+ def set(value)
+ @value = value
+ end
+
+ def get
+ @value
+ end
+
+ def +(rhs)
+ @value + rhs
+ end
+
+ def -(rhs)
+ @value - rhs
+ end
+
+ def *(rhs)
+ @value * rhs
+ end
+
+ def /(rhs)
+ @value / rhs
+ end
+end
diff --git a/test/soap/calc/server.cgi b/test/soap/calc/server.cgi
new file mode 100644
index 0000000000..c4fa687550
--- /dev/null
+++ b/test/soap/calc/server.cgi
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/cgistub'
+
+class CalcServer < SOAP::RPC::CGIStub
+ def initialize(*arg)
+ super
+
+ require 'calc'
+ servant = CalcService
+ add_servant(servant, 'http://tempuri.org/calcService')
+ end
+end
+
+status = CalcServer.new('CalcServer', nil).start
diff --git a/test/soap/calc/server.rb b/test/soap/calc/server.rb
new file mode 100644
index 0000000000..12a3968b5a
--- /dev/null
+++ b/test/soap/calc/server.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'calc'
+
+class CalcServer < SOAP::RPC::StandaloneServer
+ def initialize(*arg)
+ super
+
+ servant = CalcService
+ add_servant(servant, 'http://tempuri.org/calcService')
+ end
+end
+
+if $0 == __FILE__
+ status = CalcServer.new('CalcServer', nil, '0.0.0.0', 7000).start
+end
diff --git a/test/soap/calc/server2.rb b/test/soap/calc/server2.rb
new file mode 100644
index 0000000000..735721de64
--- /dev/null
+++ b/test/soap/calc/server2.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require 'soap/rpc/standaloneServer'
+require 'calc2'
+
+class CalcServer2 < SOAP::RPC::StandaloneServer
+ def on_init
+ servant = CalcService2.new
+ add_method(servant, 'set', 'newValue')
+ add_method(servant, 'get')
+ add_method_as(servant, '+', 'add', 'lhs')
+ add_method_as(servant, '-', 'sub', 'lhs')
+ add_method_as(servant, '*', 'multi', 'lhs')
+ add_method_as(servant, '/', 'div', 'lhs')
+ end
+end
+
+if $0 == __FILE__
+ status = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 7000).start
+end
diff --git a/test/soap/calc/test_calc.rb b/test/soap/calc/test_calc.rb
new file mode 100644
index 0000000000..191295bac0
--- /dev/null
+++ b/test/soap/calc/test_calc.rb
@@ -0,0 +1,41 @@
+require 'test/unit'
+require 'soap/rpc/driver'
+
+dir = File.dirname(__FILE__)
+$:.push(dir)
+require 'server.rb'
+$:.delete(dir)
+
+class TestCalc < Test::Unit::TestCase
+ def setup
+ @server = CalcServer.new(self.class.name, nil, '0.0.0.0', 7000)
+ @t = Thread.new {
+ @server.start
+ }
+ while @server.server.status != :Running
+ sleep 0.1
+ end
+ @calc = SOAP::RPC::Driver.new('http://localhost:7000/', 'http://tempuri.org/calcService')
+ @calc.add_method('add', 'lhs', 'rhs')
+ @calc.add_method('sub', 'lhs', 'rhs')
+ @calc.add_method('multi', 'lhs', 'rhs')
+ @calc.add_method('div', 'lhs', 'rhs')
+ end
+
+ def teardown
+ @server.server.shutdown
+ @t.kill
+ end
+
+ def test_calc
+ assert_equal(3, @calc.add(1, 2))
+ assert_equal(-1.1, @calc.sub(1.1, 2.2))
+ assert_equal(2.42, @calc.multi(1.1, 2.2))
+ assert_equal(2, @calc.div(5, 2))
+ assert_equal(2.5, @calc.div(5.0, 2))
+ assert_equal(1.0/0.0, @calc.div(1.1, 0))
+ assert_raises(ZeroDivisionError) do
+ @calc.div(1, 0)
+ end
+ end
+end
diff --git a/test/soap/calc/test_calc2.rb b/test/soap/calc/test_calc2.rb
new file mode 100644
index 0000000000..05a43b60ec
--- /dev/null
+++ b/test/soap/calc/test_calc2.rb
@@ -0,0 +1,43 @@
+require 'test/unit'
+require 'soap/rpc/driver'
+
+dir = File.dirname(__FILE__)
+$:.push(dir)
+require 'server2.rb'
+$:.delete(dir)
+
+class TestCalc2 < Test::Unit::TestCase
+ def setup
+ @server = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 7000)
+ @t = Thread.new {
+ @server.start
+ }
+ while @server.server.status != :Running
+ sleep 0.1
+ end
+ @var = SOAP::RPC::Driver.new('http://localhost:7000/', 'http://tempuri.org/calcService')
+ @var.add_method('set', 'newValue')
+ @var.add_method('get')
+ @var.add_method_as('+', 'add', 'rhs')
+ @var.add_method_as('-', 'sub', 'rhs')
+ @var.add_method_as('*', 'multi', 'rhs')
+ @var.add_method_as('/', 'div', 'rhs')
+ end
+
+ def teardown
+ @server.server.shutdown
+ @t.kill
+ end
+
+ def test_calc2
+ assert_equal(1, @var.set(1))
+ assert_equal(3, @var + 2)
+ assert_equal(-1.2, @var - 2.2)
+ assert_equal(2.2, @var * 2.2)
+ assert_equal(0, @var / 2)
+ assert_equal(0.5, @var / 2.0)
+ assert_raises(ZeroDivisionError) do
+ @var / 0
+ end
+ end
+end
diff --git a/test/soap/calc/test_calc_cgi.rb b/test/soap/calc/test_calc_cgi.rb
new file mode 100644
index 0000000000..682356e525
--- /dev/null
+++ b/test/soap/calc/test_calc_cgi.rb
@@ -0,0 +1,42 @@
+require 'test/unit'
+require 'soap/rpc/driver'
+require 'webrick'
+
+class TestCalcCGI < Test::Unit::TestCase
+ def setup
+ @server = WEBrick::HTTPServer.new(
+ :BindAddress => "0.0.0.0",
+ :Port => 8808,
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__)),
+ :CGIPathEnv => ENV['PATH']
+ )
+ @t = Thread.new {
+ @server.start
+ }
+ while @server.status != :Running
+ sleep 0.1
+ end
+ @calc = SOAP::RPC::Driver.new('http://localhost:8808/server.cgi', 'http://tempuri.org/calcService')
+ @calc.add_method('add', 'lhs', 'rhs')
+ @calc.add_method('sub', 'lhs', 'rhs')
+ @calc.add_method('multi', 'lhs', 'rhs')
+ @calc.add_method('div', 'lhs', 'rhs')
+ end
+
+ def teardown
+ @server.shutdown
+ @t.kill
+ end
+
+ def test_calc
+ assert_equal(3, @calc.add(1, 2))
+ assert_equal(-1.1, @calc.sub(1.1, 2.2))
+ assert_equal(2.42, @calc.multi(1.1, 2.2))
+ assert_equal(2, @calc.div(5, 2))
+ assert_equal(2.5, @calc.div(5.0, 2))
+ assert_equal(1.0/0.0, @calc.div(1.1, 0))
+ assert_raises(ZeroDivisionError) do
+ @calc.div(1, 0)
+ end
+ end
+end
diff --git a/test/soap/helloworld/hw_s.rb b/test/soap/helloworld/hw_s.rb
new file mode 100644
index 0000000000..b917f72fc0
--- /dev/null
+++ b/test/soap/helloworld/hw_s.rb
@@ -0,0 +1,17 @@
+require 'soap/rpc/standaloneServer'
+
+class HelloWorldServer < SOAP::RPC::StandaloneServer
+ def on_init
+ @log.level = Logger::Severity::DEBUG
+ add_method(self, 'hello_world', 'from')
+ end
+
+ def hello_world(from)
+ "Hello World, from #{ from }"
+ end
+end
+
+if $0 == __FILE__
+ server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 2000)
+ server.start
+end
diff --git a/test/soap/helloworld/test_helloworld.rb b/test/soap/helloworld/test_helloworld.rb
new file mode 100644
index 0000000000..ccf77f9c1c
--- /dev/null
+++ b/test/soap/helloworld/test_helloworld.rb
@@ -0,0 +1,31 @@
+require 'test/unit'
+require 'soap/rpc/driver'
+
+dir = File.dirname(__FILE__)
+$:.push(dir)
+require 'hw_s.rb'
+$:.delete(dir)
+
+class TestHelloWorld < Test::Unit::TestCase
+ def setup
+ @server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 2000)
+ @t = Thread.new {
+ @server.start
+ }
+ while @server.server.status != :Running
+ sleep 0.1
+ end
+ @client = SOAP::RPC::Driver.new('http://localhost:2000/', 'urn:hws')
+ @client.add_method("hello_world", "from")
+ end
+
+ def teardown
+ @server.server.shutdown
+ @t.kill
+ end
+
+ def test_hello_world
+ assert_equal("Hello World, from NaHi", @client.hello_world("NaHi"))
+ assert_equal("Hello World, from <&>", @client.hello_world("<&>"))
+ end
+end
diff --git a/test/soap/marshal/cmarshal.rb b/test/soap/marshal/cmarshal.rb
new file mode 100644
index 0000000000..d1f66b5b1e
--- /dev/null
+++ b/test/soap/marshal/cmarshal.rb
@@ -0,0 +1,142 @@
+module CMarshal
+ class << self
+ public
+ def ruby
+ class << self
+ def dump(o)
+ Marshal.dump(o)
+ end
+
+ def load(o)
+ Marshal.load(o)
+ end
+ end
+ end
+
+ def amarshal
+ require 'amarshal'
+ class << self
+ def dump(o)
+ AMarshal.dump(o)
+ end
+
+ def load(o)
+ AMarshal.load(o)
+ end
+ end
+ end
+
+ def to_src
+ require 'to_src'
+ ToSrc.independent(false)
+ class << self
+ def dump(o)
+ ToSrc.reset
+ o.to_src
+ end
+
+ def load(o)
+ eval(o)
+ end
+ end
+ end
+
+ def to_source
+ require 'ToSource'
+ class << self
+ def dump(o)
+ o.to_source
+ end
+
+ def load(o)
+ eval(o)
+ end
+ end
+ end
+
+ class ClXmlSerialContainer
+ attr_accessor :var
+ end
+
+ def clxmlserial
+ require 'cl/xmlserial'
+ ClXmlSerialContainer.instance_eval { include XmlSerialization }
+ class << self
+ def dump(o)
+ c = ClXmlSerialContainer.new
+ c.var = o
+ c.to_xml
+ end
+
+ def load(o)
+ ClXmlSerialContainer.from_xml(o).var
+ end
+ end
+ end
+
+ def soap4r
+ require 'soap/marshal'
+ class << self
+ def dump(o)
+ SOAP::Marshal.dump(o)
+ end
+
+ def load(o)
+ SOAP::Marshal.load(o)
+ end
+ end
+ end
+
+ def xmarshal
+ require 'xmarshal'
+ class << self
+ def dump(o)
+ XMarshal.dump(o)
+ end
+
+ def load(o)
+ XMarshal.load(o)
+ end
+ end
+ end
+
+ def xmlrpc
+ require 'xmlrpc/marshal'
+ class << self
+ def dump(o)
+ XMLRPC::Marshal.dump(o)
+ end
+
+ def load(o)
+ XMLRPC::Marshal.load(o)
+ end
+ end
+ end
+
+ def tmarshal
+ require 'tmarshal'
+ class << self
+ def dump(o)
+ TMarshal.dump(o)
+ end
+
+ def load(o)
+ TMarshal.restore(o)
+ end
+ end
+ end
+
+ def yaml
+ require 'yaml'
+ class << self
+ def dump(o)
+ o.to_yaml
+ end
+
+ def load(o)
+ YAML.load(o)
+ end
+ end
+ end
+ end
+end
diff --git a/test/soap/marshal/test_digraph.rb b/test/soap/marshal/test_digraph.rb
new file mode 100644
index 0000000000..93f555ffc1
--- /dev/null
+++ b/test/soap/marshal/test_digraph.rb
@@ -0,0 +1,45 @@
+require 'test/unit'
+require 'soap/marshal'
+
+class Node; include SOAP::Marshallable
+ attr_reader :first, :second, :str
+
+ def initialize(*init_next)
+ @first = init_next[0]
+ @second = init_next[1]
+ end
+end
+
+class TestDigraph < Test::Unit::TestCase
+ def setup
+ @n9 = Node.new
+ @n81 = Node.new(@n9)
+ @n82 = Node.new(@n9)
+ @n7 = Node.new(@n81, @n82)
+ @n61 = Node.new(@n7)
+ @n62 = Node.new(@n7)
+ @n5 = Node.new(@n61, @n62)
+ @n41 = Node.new(@n5)
+ @n42 = Node.new(@n5)
+ @n3 = Node.new(@n41, @n42)
+ @n21 = Node.new(@n3)
+ @n22 = Node.new(@n3)
+ @n1 = Node.new(@n21, @n22)
+ end
+
+ def test_marshal
+ f = File.open("digraph_marshalled_string.soap", "wb")
+ SOAP::Marshal.dump(@n1, f)
+ f.close
+ str = File.open("digraph_marshalled_string.soap").read
+ newnode = SOAP::Marshal.unmarshal(str)
+ assert_equal(newnode.first.first.__id__, newnode.second.first.__id__)
+ assert_equal(newnode.first.first.first.first.__id__, newnode.second.first.second.first.__id__)
+ end
+
+ def teardown
+ if File.exist?("digraph_marshalled_string.soap")
+ File.unlink("digraph_marshalled_string.soap")
+ end
+ end
+end
diff --git a/test/soap/marshal/test_marshal.rb b/test/soap/marshal/test_marshal.rb
new file mode 100644
index 0000000000..8a1b82946f
--- /dev/null
+++ b/test/soap/marshal/test_marshal.rb
@@ -0,0 +1,301 @@
+require 'test/unit'
+
+dir = File.dirname(__FILE__)
+$:.push(dir)
+require 'cmarshal'
+$:.delete(dir)
+
+CMarshal.soap4r
+
+
+module MarshalTestLib
+ def encode(o)
+ #self.class::MarshalClass.dump(o)
+ CMarshal.dump(o)
+ end
+
+ def decode(s)
+ #self.class::MarshalClass.load(s)
+ CMarshal.load(s)
+ end
+
+ def marshaltest(o1)
+ #o1.instance_eval { remove_instance_variable '@v' if defined? @v }
+ str = encode(o1)
+ print str, "\n" if $DEBUG
+ o2 = decode(str)
+ o2
+ end
+
+ def marshal_equal(o1)
+ o2 = marshaltest(o1)
+ assert_equal(o1.class, o2.class, caller[0])
+ iv1 = o1.instance_variables.sort
+ iv2 = o2.instance_variables.sort
+ assert_equal(iv1, iv2)
+ val1 = iv1.map {|var| o1.instance_eval {eval var}}
+ val2 = iv1.map {|var| o2.instance_eval {eval var}}
+ assert_equal(val1, val2, caller[0])
+ if block_given?
+ assert_equal(yield(o1), yield(o2), caller[0])
+ else
+ assert_equal(o1, o2, caller[0])
+ end
+ end
+
+ class MyObject; def initialize(v) @v = v end; attr_reader :v; end
+ def test_object
+ o1 = Object.new
+ o1.instance_eval { @iv = 1 }
+ marshal_equal(o1) {|o| o.instance_eval { @iv }}
+ end
+
+ def test_object_subclass
+ marshal_equal(MyObject.new(2)) {|o| o.v}
+ end
+
+ class MyArray < Array; def initialize(v, *args) super args; @v = v; end end
+ def test_array
+ marshal_equal([1,2,3])
+ end
+
+ def test_array_subclass
+ marshal_equal(MyArray.new(0, 1,2,3))
+ end
+
+ class MyException < Exception; def initialize(v, *args) super(*args); @v = v; end; attr_reader :v; end
+ def test_exception
+ marshal_equal(Exception.new('foo')) {|o| o.message}
+ end
+
+ def test_exception_subclass
+ marshal_equal(MyException.new(20, "bar")) {|o| [o.message, o.v]}
+ end
+
+ def test_false
+ marshal_equal(false)
+ end
+
+ class MyHash < Hash; def initialize(v, *args) super(*args); @v = v; end end
+ def test_hash
+ marshal_equal({1=>2, 3=>4})
+ end
+
+ def test_hash_default
+ h = Hash.new(:default)
+ h[5] = 6
+ marshal_equal(h)
+ end
+
+ def test_hash_subclass
+ h = MyHash.new(7, 8)
+ h[4] = 5
+ marshal_equal(h)
+ end
+
+ def test_hash_default_proc
+ h = Hash.new {}
+ assert_raises(TypeError) { marshaltest(h) }
+ end
+
+ def test_bignum
+ marshal_equal(-0x4000_0000_0000_0001)
+ marshal_equal(-0x4000_0001)
+ marshal_equal(0x4000_0000)
+ marshal_equal(0x4000_0000_0000_0000)
+ end
+
+ def test_fixnum
+ marshal_equal(-0x4000_0000)
+ marshal_equal(-1)
+ marshal_equal(0)
+ marshal_equal(1)
+ marshal_equal(0x3fff_ffff)
+ end
+
+ def test_float
+ marshal_equal(-1.0)
+ marshal_equal(0.0)
+ marshal_equal(1.0)
+ end
+
+ def test_float_inf_nan
+ marshal_equal(1.0/0.0)
+ marshal_equal(-1.0/0.0)
+ marshal_equal(0.0/0.0) {|o| o.nan?}
+ marshal_equal(-0.0) {|o| 1.0/o}
+ end
+
+ class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end
+ def test_range
+ marshal_equal(1..2)
+ marshal_equal(1...3)
+ end
+
+ def test_range_subclass
+ STDERR.puts("test_range_subclass: known bug should be fixed.")
+ return
+ marshal_equal(MyRange.new(4,5,8, false))
+ end
+
+ class MyRegexp < Regexp; def initialize(v, *args) super(*args); @v = v; end end
+ def test_regexp
+ marshal_equal(/a/)
+ end
+
+ def test_regexp_subclass
+ STDERR.puts("test_regexp_subclass: known bug should be fixed.")
+ return
+ marshal_equal(MyRegexp.new(10, "a"))
+ end
+
+ class MyString < String; def initialize(v, *args) super(*args); @v = v; end end
+ def test_string
+ marshal_equal("abc")
+ end
+
+ def test_string_subclass
+ marshal_equal(MyString.new(10, "a"))
+ end
+
+ MyStruct = Struct.new("MyStruct", :a, :b)
+ class MySubStruct < MyStruct; def initialize(v, *args) super(*args); @v = v; end end
+ def test_struct
+ marshal_equal(MyStruct.new(1,2))
+ end
+
+ def test_struct_subclass
+ marshal_equal(MySubStruct.new(10,1,2))
+ end
+
+ def test_symbol
+ marshal_equal(:a)
+ marshal_equal(:a?)
+ marshal_equal(:a!)
+ marshal_equal(:a=)
+ marshal_equal(:|)
+ marshal_equal(:^)
+ marshal_equal(:&)
+ marshal_equal(:<=>)
+ marshal_equal(:==)
+ marshal_equal(:===)
+ marshal_equal(:=~)
+ marshal_equal(:>)
+ marshal_equal(:>=)
+ marshal_equal(:<)
+ marshal_equal(:<=)
+ marshal_equal(:<<)
+ marshal_equal(:>>)
+ marshal_equal(:+)
+ marshal_equal(:-)
+ marshal_equal(:*)
+ marshal_equal(:/)
+ marshal_equal(:%)
+ marshal_equal(:**)
+ marshal_equal(:~)
+ marshal_equal(:+@)
+ marshal_equal(:-@)
+ marshal_equal(:[])
+ marshal_equal(:[]=)
+ marshal_equal(:`) #`
+ marshal_equal("a b".intern)
+ end
+
+ class MyTime < Time; def initialize(v, *args) super(*args); @v = v; end end
+ def test_time
+ marshal_equal(Time.now)
+ end
+
+ def test_time_subclass
+ STDERR.puts("test_time_subclass: known bug should be fixed.")
+ return
+ marshal_equal(MyTime.new(10))
+ end
+
+ def test_true
+ marshal_equal(true)
+ end
+
+ def test_nil
+ marshal_equal(nil)
+ end
+
+ def test_share
+ o = [:share]
+ o1 = [o, o]
+ o2 = marshaltest(o1)
+ assert_same(o2.first, o2.last)
+ end
+
+ class CyclicRange < Range
+ def <=>(other); true; end
+ end
+ def test_range_cyclic
+ o1 = CyclicRange.allocate
+ o1.instance_eval { initialize(o1, o1) }
+ o2 = marshaltest(o1)
+ assert_same(o2, o2.begin)
+ assert_same(o2, o2.end)
+ end
+
+ def test_singleton
+ o = Object.new
+ def o.m() end
+ assert_raises(TypeError) { marshaltest(o) }
+ o = Object.new
+ class << o
+ @v = 1
+ end
+ assert_raises(TypeError) { marshaltest(o) }
+ assert_raises(TypeError) { marshaltest(ARGF) }
+ assert_raises(TypeError) { marshaltest(ENV) }
+ end
+
+ module Mod1 end
+ module Mod2 end
+ def test_extend
+ o = Object.new
+ o.extend Module.new
+ assert_raises(TypeError) { marshaltest(o) }
+
+ STDERR.puts("test_range_subclass: known bug should be fixed.")
+ return
+ o = Object.new
+ o.extend Mod1
+ marshal_equal(o) { |obj| obj.kind_of? Mod1 }
+ o = Object.new
+ o.extend Mod1
+ o.extend Mod2
+ marshal_equal(o) {|obj| class << obj; ancestors end}
+ end
+
+ def test_anonymous
+ c = Class.new
+ assert_raises(TypeError) { marshaltest(c) }
+ o = c.new
+ assert_raises(TypeError) { marshaltest(o) }
+ m = Module.new
+ assert_raises(TypeError) { marshaltest(m) }
+ end
+
+ def test_string_empty
+ marshal_equal("")
+ end
+
+ def test_string_crlf
+ marshal_equal("\r\n")
+ end
+
+ def test_string_escape
+ marshal_equal("\0<;;>\1;;")
+ end
+
+ MyStruct2 = Struct.new(:a, :b)
+ def test_struct_toplevel
+ marshal_equal(MyStruct2.new(1,2))
+ end
+end
+
+class TestMarshal < Test::Unit::TestCase
+ include MarshalTestLib
+end
diff --git a/test/soap/marshal/test_struct.rb b/test/soap/marshal/test_struct.rb
new file mode 100644
index 0000000000..6596fb7a33
--- /dev/null
+++ b/test/soap/marshal/test_struct.rb
@@ -0,0 +1,38 @@
+require 'test/unit'
+require 'soap/marshal'
+
+Foo1 = Struct.new("Foo1", :m)
+Foo2 = Struct.new(:m)
+class Foo3
+ attr_accessor :m
+end
+
+class TestStruct < Test::Unit::TestCase
+ def test_foo1
+ org = Foo1.new
+ org.m = org
+ obj = convert(org)
+ assert_equal(Foo1, obj.class)
+ assert_equal(obj.m, obj)
+ end
+
+ def test_foo2
+ org = Foo2.new
+ org.m = org
+ obj = convert(org)
+ assert_equal(Foo2, obj.class)
+ assert_equal(obj.m, obj)
+ end
+
+ def test_foo3
+ org = Foo3.new
+ org.m = org
+ obj = convert(org)
+ assert_equal(Foo3, obj.class)
+ assert_equal(obj.m, obj)
+ end
+
+ def convert(obj)
+ SOAP::Marshal.unmarshal(SOAP::Marshal.marshal(obj))
+ end
+end
diff --git a/test/soap/test_basetype.rb b/test/soap/test_basetype.rb
new file mode 100644
index 0000000000..80903633b1
--- /dev/null
+++ b/test/soap/test_basetype.rb
@@ -0,0 +1,951 @@
+require 'test/unit'
+require 'soap/baseData'
+
+class TestSOAP < Test::Unit::TestCase
+ def setup
+ # Nothing to do.
+ end
+
+ def teardown
+ # Nothing to do.
+ end
+
+ def assert_parsed_result(klass, str)
+ o = klass.new(str)
+ assert_equal(str, o.to_s)
+ end
+
+ def test_SOAPNil
+ o = SOAP::SOAPNil.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::NilLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ o = SOAP::SOAPNil.new(nil)
+ assert_equal(true, o.is_nil)
+ assert_equal(nil, o.data)
+ assert_equal("", o.to_s)
+ o = SOAP::SOAPNil.new('var')
+ assert_equal(false, o.is_nil)
+ assert_equal('var', o.data)
+ assert_equal('var', o.to_s)
+ end
+
+ def test_SOAPString
+ o = SOAP::SOAPString.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::StringLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ str = "abc"
+ assert_equal(str, SOAP::SOAPString.new(str).data)
+ assert_equal(str, SOAP::SOAPString.new(str).to_s)
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPString.new("\0")
+ end
+ assert_raises(XSD::ValueSpaceError) do
+ p SOAP::SOAPString.new("\xC0\xC0").to_s
+ end
+ end
+
+ def test_SOAPBoolean
+ o = SOAP::SOAPBoolean.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::BooleanLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ ["true", true],
+ ["1", true],
+ ["false", false],
+ ["0", false],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPBoolean.new(data).data)
+ assert_equal(expected.to_s, SOAP::SOAPBoolean.new(data).to_s)
+ end
+
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPBoolean.new("nil").to_s
+ end
+ end
+
+ def test_SOAPDecimal
+ o = SOAP::SOAPDecimal.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DecimalLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 1000000000,
+ -9999999999,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789,
+ ]
+ targets.each do |dec|
+ assert_equal(dec.to_s, SOAP::SOAPDecimal.new(dec).data)
+ end
+
+ targets = [
+ "0",
+ "0.00000001",
+ "1000000000",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPDecimal.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["0.0", "0"],
+ ["-0.0", "0"],
+ ["+0.0", "0"],
+ ["0.", "0"],
+ [".0", "0"],
+ [
+ "+0.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ ],
+ [
+ ".0000012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "0.000001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ ],
+ [
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.",
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ ],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPDecimal.new(data).to_s)
+ end
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPDecimal.new(d)
+ end
+ end
+ end
+
+ def test_SOAPFloat
+ o = SOAP::SOAPFloat.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::FloatLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 3.14159265358979,
+ 12.34e36,
+ 1.4e-45,
+ -1.4e-45,
+ ]
+ targets.each do |f|
+ assert_equal(f, SOAP::SOAPFloat.new(f).data)
+ end
+
+ targets = [
+ "3.141592654",
+ "1.234e+37",
+ "1.4e-45",
+ "-1.4e-45",
+ ]
+ targets.each do |f|
+ assert_equal(f, SOAP::SOAPFloat.new(f).to_s)
+ end
+
+ targets = [
+ [3, "3"], # should be 3.0?
+ [-2, "-2"], # ditto
+ [3.14159265358979, "3.141592654"],
+ [12.34e36, "1.234e+37"],
+ [1.4e-45, "1.4e-45"],
+ [-1.4e-45, "-1.4e-45"],
+ ["1.4e", "1.4"],
+ ["12.34E36", "1.234e+37"],
+ ["1.4E-45", "1.4e-45"],
+ ["-1.4E-45", "-1.4e-45"],
+ ["1.4E", "1.4"],
+ ]
+ targets.each do |f, str|
+ assert_equal(str, SOAP::SOAPFloat.new(f).to_s)
+ end
+
+ assert_equal("0", SOAP::SOAPFloat.new(+0.0).to_s)
+ assert_equal("-0", SOAP::SOAPFloat.new(-0.0).to_s)
+ assert(SOAP::SOAPFloat.new(0.0/0.0).data.nan?)
+ assert_equal("INF", SOAP::SOAPFloat.new(1.0/0.0).to_s)
+ assert_equal(1, SOAP::SOAPFloat.new(1.0/0.0).data.infinite?)
+ assert_equal("-INF", SOAP::SOAPFloat.new(-1.0/0.0).to_s)
+ assert_equal(-1, SOAP::SOAPFloat.new(-1.0/0.0).data.infinite?)
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ "5_0",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPFloat.new(d)
+ end
+ end
+ end
+
+ def test_SOAPDouble
+ o = SOAP::SOAPDouble.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DoubleLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 3.14159265358979,
+ 12.34e36,
+ 1.4e-45,
+ -1.4e-45,
+ ]
+ targets.each do |f|
+ assert_equal(f, SOAP::SOAPDouble.new(f).data)
+ end
+
+ targets = [
+ "3.14159265358979",
+ "1.234e+37",
+ "1.4e-45",
+ "-1.4e-45",
+ ]
+ targets.each do |f|
+ assert_equal(f, SOAP::SOAPDouble.new(f).to_s)
+ end
+
+ targets = [
+ [3, "3"], # should be 3.0?
+ [-2, "-2"], # ditto.
+ [3.14159265358979, "3.14159265358979"],
+ [12.34e36, "1.234e+37"],
+ [1.4e-45, "1.4e-45"],
+ [-1.4e-45, "-1.4e-45"],
+ ["1.4e", "1.4"],
+ ["12.34E36", "1.234e+37"],
+ ["1.4E-45", "1.4e-45"],
+ ["-1.4E-45", "-1.4e-45"],
+ ["1.4E", "1.4"],
+ ]
+ targets.each do |f, str|
+ assert_equal(str, SOAP::SOAPDouble.new(f).to_s)
+ end
+
+ assert_equal("0", SOAP::SOAPFloat.new(+0.0).to_s)
+ assert_equal("-0", SOAP::SOAPFloat.new(-0.0).to_s)
+ assert_equal("NaN", SOAP::SOAPDouble.new(0.0/0.0).to_s)
+ assert(SOAP::SOAPDouble.new(0.0/0.0).data.nan?)
+ assert_equal("INF", SOAP::SOAPDouble.new(1.0/0.0).to_s)
+ assert_equal(1, SOAP::SOAPDouble.new(1.0/0.0).data.infinite?)
+ assert_equal("-INF", SOAP::SOAPDouble.new(-1.0/0.0).to_s)
+ assert_equal(-1, SOAP::SOAPDouble.new(-1.0/0.0).data.infinite?)
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPDouble.new(d)
+ end
+ end
+ end
+
+ def test_SOAPDuration
+ o = SOAP::SOAPDuration.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DurationLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "P1Y2M3DT4H5M6S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S",
+ "P0DT3456H7890M1234.5678S",
+ "P1234Y5678M9012D",
+ "-P1234Y5678M9012DT3456H7890M1234.5678S",
+ "P5678M9012DT3456H7890M1234.5678S",
+ "-P1234Y9012DT3456H7890M1234.5678S",
+ "+P1234Y5678MT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT7890M1234.5678S",
+ "-P1234Y5678M9012DT3456H1234.5678S",
+ "+P1234Y5678M9012DT3456H7890M",
+ "P123400000000000Y",
+ "-P567800000000000M",
+ "+P901200000000000D",
+ "P0DT345600000000000H",
+ "-P0DT789000000000000M",
+ "+P0DT123400000000000.000000000005678S",
+ "P1234YT1234.5678S",
+ "-P5678MT7890M",
+ "+P9012DT3456H",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPDuration, str)
+ end
+
+ targets = [
+ ["P0Y0M0DT0H0M0S",
+ "P0D"],
+ ["-P0DT0S",
+ "-P0D"],
+ ["P01234Y5678M9012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y005678M9012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M0009012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT00003456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT3456H000007890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT3456H7890M0000001234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPDuration.new(data).to_s)
+ end
+ end
+
+ def test_SOAPDateTime
+ o = SOAP::SOAPDateTime.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DateTimeLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05-18T16:52:20Z",
+ "0001-01-01T00:00:00Z",
+ "9999-12-31T23:59:59Z",
+ "19999-12-31T23:59:59Z",
+ "2002-12-31T23:59:59.999Z",
+ "2002-12-31T23:59:59.001Z",
+ "2002-12-31T23:59:59.99999999999999999999Z",
+ "2002-12-31T23:59:59.00000000000000000001Z",
+ "2002-12-31T23:59:59+09:00",
+ "2002-12-31T23:59:59+00:01",
+ "2002-12-31T23:59:59-00:01",
+ "2002-12-31T23:59:59-23:59",
+ "2002-12-31T23:59:59.00000000000000000001+13:30",
+ "-2002-05-18T16:52:20Z",
+ "-4711-12-31T23:59:59Z",
+ "-4713-01-01T12:00:00Z",
+ "-19999-12-31T23:59:59Z",
+ "-2002-12-31T23:59:59+00:01",
+ "-0001-12-31T23:59:59.00000000000000000001+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPDateTime, str)
+ end
+
+ targets = [
+ ["2002-12-31T23:59:59.00",
+ "2002-12-31T23:59:59Z"],
+ ["2002-12-31T23:59:59+00:00",
+ "2002-12-31T23:59:59Z"],
+ ["2002-12-31T23:59:59-00:00",
+ "2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59.00",
+ "-2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59+00:00",
+ "-2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59-00:00",
+ "-2002-12-31T23:59:59Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPDateTime.new(data).to_s)
+ end
+
+ targets = [
+ "1-05-18T16:52:20Z",
+ "05-18T16:52:20Z",
+ "2002-05T16:52:20Z",
+ "2002-05-18T16:52Z",
+ "",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ SOAP::SOAPDateTime.new(d)
+ end
+ end
+ end
+
+ def test_SOAPTime
+ o = SOAP::SOAPTime.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::TimeLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "16:52:20Z",
+ "00:00:00Z",
+ "23:59:59Z",
+ "23:59:59.999Z",
+ "23:59:59.001Z",
+ "23:59:59.99999999999999999999Z",
+ "23:59:59.00000000000000000001Z",
+ "23:59:59+09:00",
+ "23:59:59+00:01",
+ "23:59:59-00:01",
+ "23:59:59-23:59",
+ "23:59:59.00000000000000000001+13:30",
+ "23:59:59+00:01",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPTime, str)
+ end
+
+ targets = [
+ ["23:59:59.00",
+ "23:59:59Z"],
+ ["23:59:59+00:00",
+ "23:59:59Z"],
+ ["23:59:59-00:00",
+ "23:59:59Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPTime.new(data).to_s)
+ end
+ end
+
+ def test_SOAPDate
+ o = SOAP::SOAPDate.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DateLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05-18Z",
+ "0001-01-01Z",
+ "9999-12-31Z",
+ "19999-12-31Z",
+ "2002-12-31+09:00",
+ "2002-12-31+00:01",
+ "2002-12-31-00:01",
+ "2002-12-31-23:59",
+ "2002-12-31+13:30",
+ "-2002-05-18Z",
+ "-19999-12-31Z",
+ "-2002-12-31+00:01",
+ "-0001-12-31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPDate, str)
+ end
+
+ targets = [
+ ["2002-12-31",
+ "2002-12-31Z"],
+ ["2002-12-31+00:00",
+ "2002-12-31Z"],
+ ["2002-12-31-00:00",
+ "2002-12-31Z"],
+ ["-2002-12-31",
+ "-2002-12-31Z"],
+ ["-2002-12-31+00:00",
+ "-2002-12-31Z"],
+ ["-2002-12-31-00:00",
+ "-2002-12-31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPDate.new(data).to_s)
+ end
+ end
+
+ def test_SOAPGYearMonth
+ o = SOAP::SOAPGYearMonth.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GYearMonthLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05Z",
+ "0001-01Z",
+ "9999-12Z",
+ "19999-12Z",
+ "2002-12+09:00",
+ "2002-12+00:01",
+ "2002-12-00:01",
+ "2002-12-23:59",
+ "2002-12+13:30",
+ "-2002-05Z",
+ "-19999-12Z",
+ "-2002-12+00:01",
+ "-0001-12+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPGYearMonth, str)
+ end
+
+ targets = [
+ ["2002-12",
+ "2002-12Z"],
+ ["2002-12+00:00",
+ "2002-12Z"],
+ ["2002-12-00:00",
+ "2002-12Z"],
+ ["-2002-12",
+ "-2002-12Z"],
+ ["-2002-12+00:00",
+ "-2002-12Z"],
+ ["-2002-12-00:00",
+ "-2002-12Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPGYearMonth.new(data).to_s)
+ end
+ end
+
+ def test_SOAPGYear
+ o = SOAP::SOAPGYear.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GYearLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002Z",
+ "0001Z",
+ "9999Z",
+ "19999Z",
+ "2002+09:00",
+ "2002+00:01",
+ "2002-00:01",
+ "2002-23:59",
+ "2002+13:30",
+ "-2002Z",
+ "-19999Z",
+ "-2002+00:01",
+ "-0001+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPGYear, str)
+ end
+
+ targets = [
+ ["2002",
+ "2002Z"],
+ ["2002+00:00",
+ "2002Z"],
+ ["2002-00:00",
+ "2002Z"],
+ ["-2002",
+ "-2002Z"],
+ ["-2002+00:00",
+ "-2002Z"],
+ ["-2002-00:00",
+ "-2002Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPGYear.new(data).to_s)
+ end
+ end
+
+ def test_SOAPGMonthDay
+ o = SOAP::SOAPGMonthDay.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GMonthDayLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "05-18Z",
+ "01-01Z",
+ "12-31Z",
+ "12-31+09:00",
+ "12-31+00:01",
+ "12-31-00:01",
+ "12-31-23:59",
+ "12-31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPGMonthDay, str)
+ end
+
+ targets = [
+ ["12-31",
+ "12-31Z"],
+ ["12-31+00:00",
+ "12-31Z"],
+ ["12-31-00:00",
+ "12-31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPGMonthDay.new(data).to_s)
+ end
+ end
+
+ def test_SOAPGDay
+ o = SOAP::SOAPGDay.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GDayLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "18Z",
+ "01Z",
+ "31Z",
+ "31+09:00",
+ "31+00:01",
+ "31-00:01",
+ "31-23:59",
+ "31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPGDay, str)
+ end
+
+ targets = [
+ ["31",
+ "31Z"],
+ ["31+00:00",
+ "31Z"],
+ ["31-00:00",
+ "31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPGDay.new(data).to_s)
+ end
+ end
+
+ def test_SOAPGMonth
+ o = SOAP::SOAPGMonth.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GMonthLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "05Z",
+ "01Z",
+ "12Z",
+ "12+09:00",
+ "12+00:01",
+ "12-00:01",
+ "12-23:59",
+ "12+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPGMonth, str)
+ end
+
+ targets = [
+ ["12",
+ "12Z"],
+ ["12+00:00",
+ "12Z"],
+ ["12-00:00",
+ "12Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPGMonth.new(data).to_s)
+ end
+ end
+
+ def test_SOAPHexBinary
+ o = SOAP::SOAPHexBinary.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::HexBinaryLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "abcdef",
+ "\xe3\x81\xaa\xe3\x81\xb2",
+ "\0",
+ "",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPHexBinary.new(str).string)
+ assert_equal(str.unpack("H*")[0].tr('a-f', 'A-F'),
+ SOAP::SOAPHexBinary.new(str).data)
+ o = SOAP::SOAPHexBinary.new
+ o.set_encoded(str.unpack("H*")[0].tr('a-f', 'A-F'))
+ assert_equal(str, o.string)
+ o.set_encoded(str.unpack("H*")[0].tr('A-F', 'a-f'))
+ assert_equal(str, o.string)
+ end
+
+ targets = [
+ "0FG7",
+ "0fg7",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ o = SOAP::SOAPHexBinary.new
+ o.set_encoded(d)
+ p o.string
+ end
+ end
+ end
+
+ def test_SOAPBase64Binary
+ o = SOAP::SOAPBase64.new
+ assert_equal(SOAP::EncodingNamespace, o.type.namespace)
+ assert_equal(SOAP::Base64Literal, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "abcdef",
+ "\xe3\x81\xaa\xe3\x81\xb2",
+ "\0",
+ "",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPBase64.new(str).string)
+ assert_equal([str].pack("m").chomp, SOAP::SOAPBase64.new(str).data)
+ o = SOAP::SOAPBase64.new
+ o.set_encoded([str].pack("m").chomp)
+ assert_equal(str, o.string)
+ end
+
+ targets = [
+ "-",
+ "*",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ o = SOAP::SOAPBase64.new
+ o.set_encoded(d)
+ p o.string
+ end
+ end
+ end
+
+ def test_SOAPAnyURI
+ o = SOAP::SOAPAnyURI.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::AnyURILiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ # Too few tests here I know. Believe uri module. :)
+ targets = [
+ "foo",
+ "http://foo",
+ "http://foo/bar/baz",
+ "http://foo/bar#baz",
+ "http://foo/bar%20%20?a+b",
+ "HTTP://FOO/BAR%20%20?A+B",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPAnyURI, str)
+ end
+ end
+
+ def test_SOAPQName
+ o = SOAP::SOAPQName.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::QNameLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ # More strict test is needed but current implementation allows all non-':'
+ # chars like ' ', C0 or C1...
+ targets = [
+ "foo",
+ "foo:bar",
+ "a:b",
+ ]
+ targets.each do |str|
+ assert_parsed_result(SOAP::SOAPQName, str)
+ end
+ end
+
+
+ ###
+ ## Derived types
+ #
+
+ def test_SOAPInteger
+ o = SOAP::SOAPInteger.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::IntegerLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 1000000000,
+ -9999999999,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789,
+ ]
+ targets.each do |int|
+ assert_equal(int, SOAP::SOAPInteger.new(int).data)
+ end
+
+ targets = [
+ "0",
+ "1000000000",
+ "-9999999999",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPInteger.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ [
+ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ ],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPInteger.new(data).to_s)
+ end
+
+ targets = [
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890."
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPInteger.new(d)
+ end
+ end
+ end
+
+ def test_SOAPLong
+ o = SOAP::SOAPLong.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::LongLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 123,
+ -123,
+ 9223372036854775807,
+ -9223372036854775808,
+ ]
+ targets.each do |lng|
+ assert_equal(lng, SOAP::SOAPLong.new(lng).data)
+ end
+
+ targets = [
+ "0",
+ "123",
+ "-123",
+ "9223372036854775807",
+ "-9223372036854775808",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPLong.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPLong.new(data).to_s)
+ end
+
+ targets = [
+ 9223372036854775808,
+ -9223372036854775809,
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPLong.new(d)
+ end
+ end
+ end
+
+ def test_SOAPInt
+ o = SOAP::SOAPInt.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::IntLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 123,
+ -123,
+ 2147483647,
+ -2147483648,
+ ]
+ targets.each do |lng|
+ assert_equal(lng, SOAP::SOAPInt.new(lng).data)
+ end
+
+ targets = [
+ "0",
+ "123",
+ "-123",
+ "2147483647",
+ "-2147483648",
+ ]
+ targets.each do |str|
+ assert_equal(str, SOAP::SOAPInt.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, SOAP::SOAPInt.new(data).to_s)
+ end
+
+ targets = [
+ 2147483648,
+ -2147483649,
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ SOAP::SOAPInt.new(d)
+ end
+ end
+ end
+end
diff --git a/test/soap/test_soapelement.rb b/test/soap/test_soapelement.rb
new file mode 100644
index 0000000000..b45ebd9bb0
--- /dev/null
+++ b/test/soap/test_soapelement.rb
@@ -0,0 +1,114 @@
+require 'test/unit'
+require '../lib/soap/baseData'
+
+class TestSOAPElement < Test::Unit::TestCase
+ include SOAP
+
+ def setup
+ # Nothing to do.
+ end
+
+ def teardown
+ # Nothing to do.
+ end
+
+ def d(elename = nil, text = nil)
+ elename ||= n(nil, nil)
+ if text
+ SOAPElement.new(elename, text)
+ else
+ SOAPElement.new(elename) # do not merge.
+ end
+ end
+
+ def n(namespace, name)
+ XSD::QName.new(namespace, name)
+ end
+
+ def test_initialize
+ elename = n(nil, nil)
+ obj = d(elename)
+ assert_equal(elename, obj.elename)
+ assert_equal(LiteralNamespace, obj.encodingstyle)
+ assert_equal({}, obj.extraattr)
+ assert_equal([], obj.precedents)
+ assert_equal(false, obj.qualified)
+ assert_equal(nil, obj.text)
+ assert(obj.members.empty?)
+
+ obj = d("foo", "text")
+ assert_equal(n(nil, "foo"), obj.elename)
+ assert_equal("text", obj.text)
+ end
+
+ def test_add
+ obj = d()
+ child = d("abc")
+ obj.add(child)
+ assert(obj.key?("abc"))
+ assert_same(child, obj["abc"])
+ assert_same(child, obj.abc)
+ def obj.foo; 1; end
+ child = d("foo")
+ obj.add(child)
+ assert_equal(1, obj.foo)
+ assert_equal(child, obj.var_foo)
+ child = d("_?a?b_")
+ obj.add(child)
+ assert_equal(child, obj.var__ab_)
+ end
+
+ def test_member
+ obj = d()
+ c1 = d("c1")
+ obj.add(c1)
+ c2 = d("c2")
+ obj.add(c2)
+ assert(obj.key?("c1"))
+ assert(obj.key?("c2"))
+ assert_equal(c1, obj["c1"])
+ assert_equal(c2, obj["c2"])
+ c22 = d("c22")
+ obj["c2"] = c22
+ assert(obj.key?("c2"))
+ assert_equal(c22, obj["c2"])
+ assert_equal(["c1", "c2"], obj.members.sort)
+ #
+ k_expect = ["c1", "c2"]
+ v_expect = [c1, c22]
+ obj.each do |k, v|
+ assert(k_expect.include?(k))
+ assert(v_expect.include?(v))
+ k_expect.delete(k)
+ v_expect.delete(v)
+ end
+ assert(k_expect.empty?)
+ assert(v_expect.empty?)
+ end
+
+ def test_to_obj
+ obj = d("root")
+ ct1 = d("ct1", "t1")
+ obj.add(ct1)
+ c2 = d("c2")
+ ct2 = d("ct2", "t2")
+ c2.add(ct2)
+ obj.add(c2)
+ assert_equal({ "ct1" => "t1", "c2" => { "ct2" => "t2" }}, obj.to_obj)
+ #
+ assert_equal(nil, d().to_obj)
+ assert_equal("abc", d(nil, "abc").to_obj)
+ assert_equal(nil, d("abc", nil).to_obj)
+ end
+
+ def test_from_obj
+ source = { "ct1" => "t1", "c2" => { "ct2" => "t2" }}
+ assert_equal(source, SOAPElement.from_obj(source).to_obj)
+ source = { "1" => nil }
+ assert_equal(source, SOAPElement.from_obj(source).to_obj)
+ source = {}
+ assert_equal(nil, SOAPElement.from_obj(source).to_obj) # not {}
+ source = nil
+ assert_equal(nil, SOAPElement.from_obj(source).to_obj)
+ end
+end
diff --git a/test/wsdl/emptycomplextype.wsdl b/test/wsdl/emptycomplextype.wsdl
new file mode 100644
index 0000000000..a4504c95ba
--- /dev/null
+++ b/test/wsdl/emptycomplextype.wsdl
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<definitions
+ xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:i1="http://www.winfessor.com/SoapBoxWebService/RosterDataSet.xsd"
+ xmlns:s="http://www.w3.org/2001/XMLSchema"
+ xmlns:s0="http://www.winfessor.com/SoapBoxWebService/SoapBoxWebService"
+ xmlns:i2="http://www.winfessor.com/SoapBoxWebService/ExceptionDataSet.xsd"
+ xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:i0="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd"
+ xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
+ xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
+ targetNamespace="http://www.winfessor.com/SoapBoxWebService/SoapBoxWebService"
+ xmlns="http://schemas.xmlsoap.org/wsdl/">
+
+ <types>
+ <s:schema
+ elementFormDefault="qualified"
+ targetNamespace="http://www.winfessor.com/SoapBoxWebService/SoapBoxWebService">
+ <s:element name="typeIn">
+ <s:complexType />
+ </s:element>
+
+ <s:element name="typeOut">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="str1" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="str2" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="seq">
+ <s:complexType>
+ <s:sequence>
+ <s:any />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ </s:schema>
+ </types>
+
+ <message name="doIn">
+ <part name="parameters" element="s0:typeIn" />
+ </message>
+ <message name="doOut">
+ <part name="parameters" element="s0:typeOut" />
+ </message>
+
+ <portType name="DotNetPortType">
+ <operation name="do">
+ <input message="s0:doIn" />
+ <output message="s0:doOut" />
+ </operation>
+ </portType>
+
+ <binding name="DotNetBinding" type="s0:DotNetPortType">
+ <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
+ <operation name="do">
+ <soap:operation soapAction="http://www.winfessor.com/SoapBoxWebService/SoapBoxWebService/SessionClose" style="document" />
+ <input>
+ <soap:body use="literal" />
+ <soap:header message="s0:SessionCloseSoapBoxHeader" part="SoapBoxHeader" use="literal" />
+ </input>
+ <output>
+ <soap:body use="literal" />
+ <soap:header message="s0:SessionCloseSoapBoxHeader" part="SoapBoxHeader" use="literal" />
+ </output>
+ </operation>
+ </binding>
+
+ <service name="DotNetService">
+ <documentation>doc doc doc.</documentation>
+ <port name="DotNetPort" binding="s0:DotNetBinding">
+ <soap:address location="http://localhost:8808" />
+ <!-- <soap:address location="http://www.winfessor.com/SoapBoxWebservice/SoapBoxWebService.asmx" /> -->
+ </port>
+ </service>
+</definitions>
diff --git a/test/wsdl/test_emptycomplextype.rb b/test/wsdl/test_emptycomplextype.rb
new file mode 100644
index 0000000000..f44c72f840
--- /dev/null
+++ b/test/wsdl/test_emptycomplextype.rb
@@ -0,0 +1,14 @@
+require 'test/unit'
+require 'wsdl/parser'
+
+class TestWSDL < Test::Unit::TestCase
+ def self.setup(filename)
+ @@filename = filename
+ end
+
+ def test_wsdl
+ @wsdl = WSDL::Parser.new.parse(File.open(@@filename).read)
+ end
+end
+
+TestWSDL.setup(File.join(File.dirname(__FILE__), 'emptycomplextype.wsdl'))
diff --git a/test/xsd/test_xmlschemaparser.rb b/test/xsd/test_xmlschemaparser.rb
new file mode 100644
index 0000000000..6e3839a0d2
--- /dev/null
+++ b/test/xsd/test_xmlschemaparser.rb
@@ -0,0 +1,14 @@
+require 'test/unit'
+require 'wsdl/xmlSchema/parser'
+
+class TestXMLSchemaParser < Test::Unit::TestCase
+ def self.setup(filename)
+ @@filename = filename
+ end
+
+ def test_wsdl
+ @wsdl = WSDL::XMLSchema::Parser.new.parse(File.open(@@filename).read)
+ end
+end
+
+TestXMLSchemaParser.setup(File.join(File.dirname(__FILE__), 'xmlschema.xml'))
diff --git a/test/xsd/test_xsd.rb b/test/xsd/test_xsd.rb
new file mode 100644
index 0000000000..7fb5052f43
--- /dev/null
+++ b/test/xsd/test_xsd.rb
@@ -0,0 +1,976 @@
+require 'test/unit'
+require 'xsd/datatypes'
+
+class TestXSD < Test::Unit::TestCase
+ def setup
+ # Nothing to do.
+ end
+
+ def teardown
+ # Nothing to do.
+ end
+
+ def assert_parsed_result(klass, str)
+ o = klass.new(str)
+ assert_equal(str, o.to_s)
+ end
+
+ def test_NSDBase
+ o = XSD::NSDBase.new
+ assert_equal(nil, o.type)
+ end
+
+ def test_XSDBase
+ o = XSD::XSDAnySimpleType.new
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+ assert_equal('', o.to_s)
+ end
+
+ def test_XSDNil
+ o = XSD::XSDNil.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::NilLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ o = XSD::XSDNil.new(nil)
+ assert_equal(true, o.is_nil)
+ assert_equal(nil, o.data)
+ assert_equal("", o.to_s)
+ o = XSD::XSDNil.new('var')
+ assert_equal(false, o.is_nil)
+ assert_equal('var', o.data)
+ assert_equal('var', o.to_s)
+ end
+
+ def test_XSDString
+ o = XSD::XSDString.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::StringLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ str = "abc"
+ assert_equal(str, XSD::XSDString.new(str).data)
+ assert_equal(str, XSD::XSDString.new(str).to_s)
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDString.new("\0")
+ end
+ assert_raises(XSD::ValueSpaceError) do
+ p XSD::XSDString.new("\xC0\xC0").to_s
+ end
+ end
+
+ def test_XSDBoolean
+ o = XSD::XSDBoolean.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::BooleanLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ ["true", true],
+ ["1", true],
+ ["false", false],
+ ["0", false],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDBoolean.new(data).data)
+ assert_equal(expected.to_s, XSD::XSDBoolean.new(data).to_s)
+ end
+
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDBoolean.new("nil").to_s
+ end
+ end
+
+ def test_XSDDecimal
+ o = XSD::XSDDecimal.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DecimalLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 1000000000,
+ -9999999999,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789,
+ ]
+ targets.each do |dec|
+ assert_equal(dec.to_s, XSD::XSDDecimal.new(dec).data)
+ end
+
+ targets = [
+ "0",
+ "0.00000001",
+ "1000000000",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDDecimal.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["0.0", "0"],
+ ["-0.0", "0"],
+ ["+0.0", "0"],
+ ["0.", "0"],
+ [".0", "0"],
+ [
+ "+0.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ ],
+ [
+ ".0000012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "0.000001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ ],
+ [
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.",
+ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ ],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDDecimal.new(data).to_s)
+ end
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDDecimal.new(d)
+ end
+ end
+ end
+
+ def test_XSDFloat
+ o = XSD::XSDFloat.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::FloatLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 3.14159265358979,
+ 12.34e36,
+ 1.4e-45,
+ -1.4e-45,
+ ]
+ targets.each do |f|
+ assert_equal(f, XSD::XSDFloat.new(f).data)
+ end
+
+ targets = [
+ "3.141592654",
+ "1.234e+37",
+ "1.4e-45",
+ "-1.4e-45",
+ ]
+ targets.each do |f|
+ assert_equal(f, XSD::XSDFloat.new(f).to_s)
+ end
+
+ targets = [
+ [3, "3"], # should be 3.0?
+ [-2, "-2"], # ditto
+ [3.14159265358979, "3.141592654"],
+ [12.34e36, "1.234e+37"],
+ [1.4e-45, "1.4e-45"],
+ [-1.4e-45, "-1.4e-45"],
+ ["1.4e", "1.4"],
+ ["12.34E36", "1.234e+37"],
+ ["1.4E-45", "1.4e-45"],
+ ["-1.4E-45", "-1.4e-45"],
+ ["1.4E", "1.4"],
+ ]
+ targets.each do |f, str|
+ assert_equal(str, XSD::XSDFloat.new(f).to_s)
+ end
+
+ assert_equal("0", XSD::XSDFloat.new(+0.0).to_s)
+ assert_equal("-0", XSD::XSDFloat.new(-0.0).to_s)
+ assert(XSD::XSDFloat.new(0.0/0.0).data.nan?)
+ assert_equal("INF", XSD::XSDFloat.new(1.0/0.0).to_s)
+ assert_equal(1, XSD::XSDFloat.new(1.0/0.0).data.infinite?)
+ assert_equal("-INF", XSD::XSDFloat.new(-1.0/0.0).to_s)
+ assert_equal(-1, XSD::XSDFloat.new(-1.0/0.0).data.infinite?)
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ "5_0",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDFloat.new(d)
+ end
+ end
+ end
+
+ def test_XSDDouble
+ o = XSD::XSDDouble.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DoubleLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 3.14159265358979,
+ 12.34e36,
+ 1.4e-45,
+ -1.4e-45,
+ ]
+ targets.each do |f|
+ assert_equal(f, XSD::XSDDouble.new(f).data)
+ end
+
+ targets = [
+ "3.14159265358979",
+ "1.234e+37",
+ "1.4e-45",
+ "-1.4e-45",
+ ]
+ targets.each do |f|
+ assert_equal(f, XSD::XSDDouble.new(f).to_s)
+ end
+
+ targets = [
+ [3, "3"], # should be 3.0?
+ [-2, "-2"], # ditto.
+ [3.14159265358979, "3.14159265358979"],
+ [12.34e36, "1.234e+37"],
+ [1.4e-45, "1.4e-45"],
+ [-1.4e-45, "-1.4e-45"],
+ ["1.4e", "1.4"],
+ ["12.34E36", "1.234e+37"],
+ ["1.4E-45", "1.4e-45"],
+ ["-1.4E-45", "-1.4e-45"],
+ ["1.4E", "1.4"],
+ ]
+ targets.each do |f, str|
+ assert_equal(str, XSD::XSDDouble.new(f).to_s)
+ end
+
+ assert_equal("0", XSD::XSDFloat.new(+0.0).to_s)
+ assert_equal("-0", XSD::XSDFloat.new(-0.0).to_s)
+ assert_equal("NaN", XSD::XSDDouble.new(0.0/0.0).to_s)
+ assert(XSD::XSDDouble.new(0.0/0.0).data.nan?)
+ assert_equal("INF", XSD::XSDDouble.new(1.0/0.0).to_s)
+ assert_equal(1, XSD::XSDDouble.new(1.0/0.0).data.infinite?)
+ assert_equal("-INF", XSD::XSDDouble.new(-1.0/0.0).to_s)
+ assert_equal(-1, XSD::XSDDouble.new(-1.0/0.0).data.infinite?)
+
+ targets = [
+ "0.000000000000a",
+ "00a.0000000000001",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDDouble.new(d)
+ end
+ end
+ end
+
+ def test_XSDDuration
+ o = XSD::XSDDuration.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DurationLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "P1Y2M3DT4H5M6S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S",
+ "P0DT3456H7890M1234.5678S",
+ "P1234Y5678M9012D",
+ "-P1234Y5678M9012DT3456H7890M1234.5678S",
+ "P5678M9012DT3456H7890M1234.5678S",
+ "-P1234Y9012DT3456H7890M1234.5678S",
+ "+P1234Y5678MT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT7890M1234.5678S",
+ "-P1234Y5678M9012DT3456H1234.5678S",
+ "+P1234Y5678M9012DT3456H7890M",
+ "P123400000000000Y",
+ "-P567800000000000M",
+ "+P901200000000000D",
+ "P0DT345600000000000H",
+ "-P0DT789000000000000M",
+ "+P0DT123400000000000.000000000005678S",
+ "P1234YT1234.5678S",
+ "-P5678MT7890M",
+ "+P9012DT3456H",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDDuration, str)
+ end
+
+ targets = [
+ ["P0Y0M0DT0H0M0S",
+ "P0D"],
+ ["-P0DT0S",
+ "-P0D"],
+ ["P01234Y5678M9012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y005678M9012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M0009012DT3456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT00003456H7890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT3456H000007890M1234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ["P1234Y5678M9012DT3456H7890M0000001234.5678S",
+ "P1234Y5678M9012DT3456H7890M1234.5678S"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDDuration.new(data).to_s)
+ end
+ end
+
+ def test_XSDDateTime
+ o = XSD::XSDDateTime.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DateTimeLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05-18T16:52:20Z",
+ "0001-01-01T00:00:00Z",
+ "9999-12-31T23:59:59Z",
+ "19999-12-31T23:59:59Z",
+ "2002-12-31T23:59:59.999Z",
+ "2002-12-31T23:59:59.001Z",
+ "2002-12-31T23:59:59.99999999999999999999Z",
+ "2002-12-31T23:59:59.00000000000000000001Z",
+ "2002-12-31T23:59:59+09:00",
+ "2002-12-31T23:59:59+00:01",
+ "2002-12-31T23:59:59-00:01",
+ "2002-12-31T23:59:59-23:59",
+ "2002-12-31T23:59:59.00000000000000000001+13:30",
+ "-2002-05-18T16:52:20Z",
+ "-4713-01-01T12:00:00Z",
+ "-2002-12-31T23:59:59+00:01",
+ "-0001-12-31T23:59:59.00000000000000000001+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDDateTime, str)
+ end
+
+ targets = [
+ ["2002-12-31T23:59:59.00",
+ "2002-12-31T23:59:59Z"],
+ ["2002-12-31T23:59:59+00:00",
+ "2002-12-31T23:59:59Z"],
+ ["2002-12-31T23:59:59-00:00",
+ "2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59.00",
+ "-2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59+00:00",
+ "-2002-12-31T23:59:59Z"],
+ ["-2002-12-31T23:59:59-00:00",
+ "-2002-12-31T23:59:59Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDDateTime.new(data).to_s)
+ end
+
+ targets = [
+ "0000-05-18T16:52:20Z",
+ "05-18T16:52:20Z",
+ "2002-05T16:52:20Z",
+ "2002-05-18T16:52Z",
+ "",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ XSD::XSDDateTime.new(d)
+ end
+ end
+ end
+
+ def test_XSDTime
+ o = XSD::XSDTime.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::TimeLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "16:52:20Z",
+ "00:00:00Z",
+ "23:59:59Z",
+ "23:59:59.999Z",
+ "23:59:59.001Z",
+ "23:59:59.99999999999999999999Z",
+ "23:59:59.00000000000000000001Z",
+ "23:59:59+09:00",
+ "23:59:59+00:01",
+ "23:59:59-00:01",
+ "23:59:59-23:59",
+ "23:59:59.00000000000000000001+13:30",
+ "23:59:59+00:01",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDTime, str)
+ end
+
+ targets = [
+ ["23:59:59.00",
+ "23:59:59Z"],
+ ["23:59:59+00:00",
+ "23:59:59Z"],
+ ["23:59:59-00:00",
+ "23:59:59Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDTime.new(data).to_s)
+ end
+ end
+
+ def test_XSDDate
+ o = XSD::XSDDate.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::DateLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05-18Z",
+ "0001-01-01Z",
+ "9999-12-31Z",
+ "19999-12-31Z",
+ "2002-12-31+09:00",
+ "2002-12-31+00:01",
+ "2002-12-31-00:01",
+ "2002-12-31-23:59",
+ "2002-12-31+13:30",
+ "-2002-05-18Z",
+ "-19999-12-31Z",
+ "-2002-12-31+00:01",
+ "-0001-12-31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDDate, str)
+ end
+
+ targets = [
+ ["2002-12-31",
+ "2002-12-31Z"],
+ ["2002-12-31+00:00",
+ "2002-12-31Z"],
+ ["2002-12-31-00:00",
+ "2002-12-31Z"],
+ ["-2002-12-31",
+ "-2002-12-31Z"],
+ ["-2002-12-31+00:00",
+ "-2002-12-31Z"],
+ ["-2002-12-31-00:00",
+ "-2002-12-31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDDate.new(data).to_s)
+ end
+ end
+end
+
+class TestXSD2 < Test::Unit::TestCase
+ def setup
+ # Nothing to do.
+ end
+
+ def teardown
+ # Nothing to do.
+ end
+
+ def assert_parsed_result(klass, str)
+ o = klass.new(str)
+ assert_equal(str, o.to_s)
+ end
+
+ def test_XSDGYearMonth
+ o = XSD::XSDGYearMonth.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GYearMonthLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002-05Z",
+ "0001-01Z",
+ "9999-12Z",
+ "19999-12Z",
+ "2002-12+09:00",
+ "2002-12+00:01",
+ "2002-12-00:01",
+ "2002-12-23:59",
+ "2002-12+13:30",
+ "-2002-05Z",
+ "-19999-12Z",
+ "-2002-12+00:01",
+ "-0001-12+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDGYearMonth, str)
+ end
+
+ targets = [
+ ["2002-12",
+ "2002-12Z"],
+ ["2002-12+00:00",
+ "2002-12Z"],
+ ["2002-12-00:00",
+ "2002-12Z"],
+ ["-2002-12",
+ "-2002-12Z"],
+ ["-2002-12+00:00",
+ "-2002-12Z"],
+ ["-2002-12-00:00",
+ "-2002-12Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDGYearMonth.new(data).to_s)
+ end
+ end
+
+ def test_XSDGYear
+ o = XSD::XSDGYear.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GYearLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "2002Z",
+ "0001Z",
+ "9999Z",
+ "19999Z",
+ "2002+09:00",
+ "2002+00:01",
+ "2002-00:01",
+ "2002-23:59",
+ "2002+13:30",
+ "-2002Z",
+ "-19999Z",
+ "-2002+00:01",
+ "-0001+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDGYear, str)
+ end
+
+ targets = [
+ ["2002",
+ "2002Z"],
+ ["2002+00:00",
+ "2002Z"],
+ ["2002-00:00",
+ "2002Z"],
+ ["-2002",
+ "-2002Z"],
+ ["-2002+00:00",
+ "-2002Z"],
+ ["-2002-00:00",
+ "-2002Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDGYear.new(data).to_s)
+ end
+ end
+
+ def test_XSDGMonthDay
+ o = XSD::XSDGMonthDay.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GMonthDayLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "05-18Z",
+ "01-01Z",
+ "12-31Z",
+ "12-31+09:00",
+ "12-31+00:01",
+ "12-31-00:01",
+ "12-31-23:59",
+ "12-31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDGMonthDay, str)
+ end
+
+ targets = [
+ ["12-31",
+ "12-31Z"],
+ ["12-31+00:00",
+ "12-31Z"],
+ ["12-31-00:00",
+ "12-31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDGMonthDay.new(data).to_s)
+ end
+ end
+
+ def test_XSDGDay
+ o = XSD::XSDGDay.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GDayLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "18Z",
+ "01Z",
+ "31Z",
+ "31+09:00",
+ "31+00:01",
+ "31-00:01",
+ "31-23:59",
+ "31+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDGDay, str)
+ end
+
+ targets = [
+ ["31",
+ "31Z"],
+ ["31+00:00",
+ "31Z"],
+ ["31-00:00",
+ "31Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDGDay.new(data).to_s)
+ end
+ end
+
+ def test_XSDGMonth
+ o = XSD::XSDGMonth.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::GMonthLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "05Z",
+ "01Z",
+ "12Z",
+ "12+09:00",
+ "12+00:01",
+ "12-00:01",
+ "12-23:59",
+ "12+13:30",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDGMonth, str)
+ end
+
+ targets = [
+ ["12",
+ "12Z"],
+ ["12+00:00",
+ "12Z"],
+ ["12-00:00",
+ "12Z"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDGMonth.new(data).to_s)
+ end
+ end
+
+ def test_XSDHexBinary
+ o = XSD::XSDHexBinary.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::HexBinaryLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "abcdef",
+ "\xe3\x81\xaa\xe3\x81\xb2",
+ %Q(\0),
+ "",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDHexBinary.new(str).string)
+ assert_equal(str.unpack("H*")[0 ].tr('a-f', 'A-F'),
+ XSD::XSDHexBinary.new(str).data)
+ o = XSD::XSDHexBinary.new
+ o.set_encoded(str.unpack("H*")[0 ].tr('a-f', 'A-F'))
+ assert_equal(str, o.string)
+ o.set_encoded(str.unpack("H*")[0 ].tr('A-F', 'a-f'))
+ assert_equal(str, o.string)
+ end
+
+ targets = [
+ "0FG7",
+ "0fg7",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ o = XSD::XSDHexBinary.new
+ o.set_encoded(d)
+ p o.string
+ end
+ end
+ end
+
+ def test_XSDBase64Binary
+ o = XSD::XSDBase64Binary.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::Base64BinaryLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ "abcdef",
+ "\xe3\x81\xaa\xe3\x81\xb2",
+ %Q(\0),
+ "",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDBase64Binary.new(str).string)
+ assert_equal([str ].pack("m").chomp, XSD::XSDBase64Binary.new(str).data)
+ o = XSD::XSDBase64Binary.new
+ o.set_encoded([str ].pack("m").chomp)
+ assert_equal(str, o.string)
+ end
+
+ targets = [
+ "-",
+ "*",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError, d.to_s) do
+ o = XSD::XSDBase64Binary.new
+ o.set_encoded(d)
+ p o.string
+ end
+ end
+ end
+
+ def test_XSDAnyURI
+ o = XSD::XSDAnyURI.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::AnyURILiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ # Too few tests here I know. Believe uri module. :)
+ targets = [
+ "foo",
+ "http://foo",
+ "http://foo/bar/baz",
+ "http://foo/bar#baz",
+ "http://foo/bar%20%20?a+b",
+ "HTTP://FOO/BAR%20%20?A+B",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDAnyURI, str)
+ end
+ end
+
+ def test_XSDQName
+ o = XSD::XSDQName.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::QNameLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ # More strict test is needed but current implementation allows all non-':'
+ # chars like ' ', C0 or C1...
+ targets = [
+ "foo",
+ "foo:bar",
+ "a:b",
+ ]
+ targets.each do |str|
+ assert_parsed_result(XSD::XSDQName, str)
+ end
+ end
+
+
+ ###
+ ## Derived types
+ #
+
+ def test_XSDInteger
+ o = XSD::XSDInteger.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::IntegerLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 1000000000,
+ -9999999999,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
+ -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789,
+ ]
+ targets.each do |int|
+ assert_equal(int, XSD::XSDInteger.new(int).data)
+ end
+
+ targets = [
+ "0",
+ "1000000000",
+ "-9999999999",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDInteger.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ [
+ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ ],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDInteger.new(data).to_s)
+ end
+
+ targets = [
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890."
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDInteger.new(d)
+ end
+ end
+ end
+
+ def test_XSDLong
+ o = XSD::XSDLong.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::LongLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 123,
+ -123,
+ 9223372036854775807,
+ -9223372036854775808,
+ ]
+ targets.each do |lng|
+ assert_equal(lng, XSD::XSDLong.new(lng).data)
+ end
+
+ targets = [
+ "0",
+ "123",
+ "-123",
+ "9223372036854775807",
+ "-9223372036854775808",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDLong.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDLong.new(data).to_s)
+ end
+
+ targets = [
+ 9223372036854775808,
+ -9223372036854775809,
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDLong.new(d)
+ end
+ end
+ end
+
+ def test_XSDInt
+ o = XSD::XSDInt.new
+ assert_equal(XSD::Namespace, o.type.namespace)
+ assert_equal(XSD::IntLiteral, o.type.name)
+ assert_equal(nil, o.data)
+ assert_equal(true, o.is_nil)
+
+ targets = [
+ 0,
+ 123,
+ -123,
+ 2147483647,
+ -2147483648,
+ ]
+ targets.each do |lng|
+ assert_equal(lng, XSD::XSDInt.new(lng).data)
+ end
+
+ targets = [
+ "0",
+ "123",
+ "-123",
+ "2147483647",
+ "-2147483648",
+ ]
+ targets.each do |str|
+ assert_equal(str, XSD::XSDInt.new(str).to_s)
+ end
+
+ targets = [
+ ["-0", "0"],
+ ["+0", "0"],
+ ["000123", "123"],
+ ["-000123", "-123"],
+ ]
+ targets.each do |data, expected|
+ assert_equal(expected, XSD::XSDInt.new(data).to_s)
+ end
+
+ targets = [
+ 2147483648,
+ -2147483649,
+ "0.0",
+ "-5.2",
+ "0.000000000000a",
+ "+-5",
+ ]
+ targets.each do |d|
+ assert_raises(XSD::ValueSpaceError) do
+ XSD::XSDInt.new(d)
+ end
+ end
+ end
+end
diff --git a/test/xsd/xmlschema.xml b/test/xsd/xmlschema.xml
new file mode 100644
index 0000000000..f532e2934e
--- /dev/null
+++ b/test/xsd/xmlschema.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema xmlns:mstns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" id="MessageDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element msdata:IsDataSet="true" name="MessageDataSet">
+ <xs:complexType>
+ <xs:choice maxOccurs="unbounded" />
+ </xs:complexType>
+ </xs:element>
+</xs:schema> \ No newline at end of file