mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 533c24268e
			
		
	
	
		533c24268e
		
	
	
	
	
		
			
			#nnn is a ticket number at http://dev.ctor.org/soap4r * SOAP * allow to configure an envelope namespace of SOAP request. (#124) TemporaryNamespace = 'http://www.w3.org/2003/05/soap-envelope' @client.options["soap.envelope.requestnamespace"] = TemporaryNamespace @client.options["soap.envelope.responsenamespace"] = TemporaryNamespace @client.do_proc(...) * let SOAP request XML indent space configuable. see "soap.envelope.no_indent" option. (#130) * let external CES configuable. ex. client["soap.mapping.external_ces"] = 'SJIS'. $KCODE is used by default. (#133) external CES ::= CES used in Ruby object of client and server internal CES ::= CES used in SOAP/OM * add iso-8859-1 external CES support. (#106) * fixed illegal 'qualified' handling of elements. it caused ASP.NET inteoperability problem. (#144) * added 'soap.envelope.use_numeric_character_reference' (boolean) option to let query XML use numeric character reference in XML, not plain UTF-8 character. !GoogleSearch server seems to not allow plain UTF-8 character since 2005-08-15 update. (#147) * SOAP::Header::SimpleHeader (de)serialization throws an exception on !SimpleHeader.on_(in|out)bound when header is a String. so we could not use a simple single element headerItem. fixed. thanks to emil. (#129) * out parameter of rpc operation did not work. (#132) * follow HTTP redirect only if using http-access2. (#125) (#145) * add a workaround for importing an WSDL whose path begins with drive letter. (#115) * WSDL * SOAP Data which is defined as a simpletype was not mapped correctly to Ruby obj when using wsdl2ruby.rb generated classdef file. (#123) * rpc/literal support. (#118) * re-implemented local element qualify/unqualify control. handles elementFormDefault and form in WSDL. (#119) * Array of an element which has simpleType causes a crash. (#128) * prarmeterOrder may not contain return part so it can be shorter than parts size. Thanks to Hugh. (#139) * Samples * added !BasicAuth client sample. (#117) * added Base64 client/server sample. * added Flickr SOAP interface client sample. (#122) * added !SalesForce client sample. (#135) * updated Thawte CA certificate for !GoogleAdWords sample. * updated a client script with the newer version made by Johan. thanks! * shortened long file names. (#120) * fixed typo in authheader sample. (#129) * updated deprecated method usage. (#138) git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@9171 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			942 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			942 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # soap/baseData.rb: SOAP4R - Base type library
 | |
| # Copyright (C) 2000, 2001, 2003-2005  NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
 | |
| 
 | |
| # This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
 | |
| # redistribute it and/or modify it under the same terms of Ruby's license;
 | |
| # either the dual license version in 2003, or any later version.
 | |
| 
 | |
| 
 | |
| 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
 | |
| 
 | |
| 
 | |
| ###
 | |
| ## for SOAP type(base and compound)
 | |
| #
 | |
| module SOAPType
 | |
|   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
 | |
| 
 | |
|   def initialize(*arg)
 | |
|     super
 | |
|     @encodingstyle = nil
 | |
|     @elename = XSD::QName::EMPTY
 | |
|     @id = nil
 | |
|     @precedents = []
 | |
|     @root = false
 | |
|     @parent = nil
 | |
|     @position = nil
 | |
|     @definedtype = nil
 | |
|     @extraattr = {}
 | |
|   end
 | |
| 
 | |
|   def inspect
 | |
|     if self.is_a?(XSD::NSDBase)
 | |
|       sprintf("#<%s:0x%x %s %s>", self.class.name, __id__, self.elename, self.type)
 | |
|     else
 | |
|       sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def rootnode
 | |
|     node = self
 | |
|     while node = node.parent
 | |
|       break if SOAPEnvelope === node
 | |
|     end
 | |
|     node
 | |
|   end
 | |
| end
 | |
| 
 | |
| 
 | |
| ###
 | |
| ## for SOAP base type
 | |
| #
 | |
| module SOAPBasetype
 | |
|   include SOAPType
 | |
|   include SOAP
 | |
| 
 | |
|   def initialize(*arg)
 | |
|     super
 | |
|   end
 | |
| end
 | |
| 
 | |
| 
 | |
| ###
 | |
| ## for SOAP compound type
 | |
| #
 | |
| module SOAPCompoundtype
 | |
|   include SOAPType
 | |
|   include SOAP
 | |
| 
 | |
|   def initialize(*arg)
 | |
|     super
 | |
|   end
 | |
| end
 | |
| 
 | |
| 
 | |
| ###
 | |
| ## Convenience datatypes.
 | |
| #
 | |
| class SOAPReference < XSD::NSDBase
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| 
 | |
| public
 | |
| 
 | |
|   attr_accessor :refid
 | |
| 
 | |
|   # Override the definition in SOAPBasetype.
 | |
|   def initialize(obj = nil)
 | |
|     super()
 | |
|     @type = XSD::QName::EMPTY
 | |
|     @refid = nil
 | |
|     @obj = nil
 | |
|     __setobj__(obj) if obj
 | |
|   end
 | |
| 
 | |
|   def __getobj__
 | |
|     @obj
 | |
|   end
 | |
| 
 | |
|   def __setobj__(obj)
 | |
|     @obj = obj
 | |
|     @refid = @obj.id || 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 refidstr
 | |
|     '#' + @refid
 | |
|   end
 | |
| 
 | |
|   def self.create_refid(obj)
 | |
|     'id' + obj.__id__.to_s
 | |
|   end
 | |
| 
 | |
|   def self.decode(elename, refidstr)
 | |
|     if /\A#(.*)\z/ =~ refidstr
 | |
|       refid = $1
 | |
|     elsif /\Acid:(.*)\z/ =~ refidstr
 | |
|       refid = $1
 | |
|     else
 | |
|       raise ArgumentError.new("illegal refid #{refidstr}")
 | |
|     end
 | |
|     d = super(elename)
 | |
|     d.refid = refid
 | |
|     d
 | |
|   end
 | |
| end
 | |
| 
 | |
| 
 | |
| class SOAPExternalReference < XSD::NSDBase
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| 
 | |
|   def initialize
 | |
|     super()
 | |
|     @type = XSD::QName::EMPTY
 | |
|   end
 | |
| 
 | |
|   def referred
 | |
|     rootnode.external_content[external_contentid] = self
 | |
|   end
 | |
| 
 | |
|   def refidstr
 | |
|     'cid:' + external_contentid
 | |
|   end
 | |
| 
 | |
| private
 | |
| 
 | |
|   def external_contentid
 | |
|     raise NotImplementedError.new
 | |
|   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 SOAPNonPositiveInteger < XSD::XSDNonPositiveInteger
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPNegativeInteger < XSD::XSDNegativeInteger
 | |
|   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
 | |
| 
 | |
| class SOAPByte < XSD::XSDByte
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPNonNegativeInteger < XSD::XSDNonNegativeInteger
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPUnsignedLong < XSD::XSDUnsignedLong
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPUnsignedInt < XSD::XSDUnsignedInt
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPUnsignedShort < XSD::XSDUnsignedShort
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPUnsignedByte < XSD::XSDUnsignedByte
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| class SOAPPositiveInteger < XSD::XSDPositiveInteger
 | |
|   include SOAPBasetype
 | |
|   extend SOAPModuleUtils
 | |
| end
 | |
| 
 | |
| 
 | |
| ###
 | |
| ## Compound datatypes.
 | |
| #
 | |
| class SOAPStruct < XSD::NSDBase
 | |
|   include SOAPCompoundtype
 | |
|   include Enumerable
 | |
| 
 | |
| public
 | |
| 
 | |
|   def initialize(type = nil)
 | |
|     super()
 | |
|     @type = type || XSD::QName::EMPTY
 | |
|     @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.parent = self if data.respond_to?(:parent=)
 | |
|       @data[@array.index(idx)] = data
 | |
|     else
 | |
|       add(idx, data)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def key?(name)
 | |
|     @array.include?(name)
 | |
|   end
 | |
| 
 | |
|   def members
 | |
|     @array
 | |
|   end
 | |
| 
 | |
|   def to_obj
 | |
|     hash = {}
 | |
|     proptype = {}
 | |
|     each do |k, v|
 | |
|       value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s
 | |
|       case proptype[k]
 | |
|       when :single
 | |
|         hash[k] = [hash[k], value]
 | |
|         proptype[k] = :multi
 | |
|       when :multi
 | |
|         hash[k] << value
 | |
|       else
 | |
|         hash[k] = value
 | |
|         proptype[k] = :single
 | |
|       end
 | |
|     end
 | |
|     hash
 | |
|   end
 | |
| 
 | |
|   def each
 | |
|     idx = 0
 | |
|     while idx < @array.length
 | |
|       yield(@array[idx], @data[idx])
 | |
|       idx += 1
 | |
|     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() if value.nil?
 | |
|     @array.push(name)
 | |
|     value.elename = value.elename.dup_name(name)
 | |
|     @data.push(value)
 | |
|     value.parent = self if value.respond_to?(:parent=)
 | |
|     value
 | |
|   end
 | |
| end
 | |
| 
 | |
| 
 | |
| # SOAPElement is not typed so it is not derived from NSDBase.
 | |
| class SOAPElement
 | |
|   include Enumerable
 | |
| 
 | |
|   attr_accessor :encodingstyle
 | |
| 
 | |
|   attr_accessor :elename
 | |
|   attr_accessor :id
 | |
|   attr_reader :precedents
 | |
|   attr_accessor :root
 | |
|   attr_accessor :parent
 | |
|   attr_accessor :position
 | |
|   attr_accessor :extraattr
 | |
| 
 | |
|   attr_accessor :qualified
 | |
| 
 | |
|   def initialize(elename, text = nil)
 | |
|     if !elename.is_a?(XSD::QName)
 | |
|       elename = XSD::QName.new(nil, elename)
 | |
|     end
 | |
|     @encodingstyle = LiteralNamespace
 | |
|     @elename = elename
 | |
|     @id = nil
 | |
|     @precedents = []
 | |
|     @root = false
 | |
|     @parent = nil
 | |
|     @position = nil
 | |
|     @extraattr = {}
 | |
| 
 | |
|     @qualified = nil
 | |
| 
 | |
|     @array = []
 | |
|     @data = []
 | |
|     @text = text
 | |
|   end
 | |
| 
 | |
|   def inspect
 | |
|     sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename)
 | |
|   end
 | |
| 
 | |
|   # Text interface.
 | |
|   attr_accessor :text
 | |
|   alias data 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.parent = self if data.respond_to?(:parent=)
 | |
|       @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 = {}
 | |
|       proptype = {}
 | |
|       each do |k, v|
 | |
|         value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s
 | |
|         case proptype[k]
 | |
|         when :single
 | |
|           hash[k] = [hash[k], value]
 | |
|           proptype[k] = :multi
 | |
|         when :multi
 | |
|           hash[k] << value
 | |
|         else
 | |
|           hash[k] = value
 | |
|           proptype[k] = :single
 | |
|         end
 | |
|       end
 | |
|       hash
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def each
 | |
|     idx = 0
 | |
|     while idx < @array.length
 | |
|       yield(@array[idx], @data[idx])
 | |
|       idx += 1
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def self.decode(elename)
 | |
|     o = SOAPElement.new(elename)
 | |
|     o
 | |
|   end
 | |
| 
 | |
|   def self.from_obj(obj, namespace = nil)
 | |
|     o = SOAPElement.new(nil)
 | |
|     case obj
 | |
|     when nil
 | |
|       o.text = nil
 | |
|     when Hash
 | |
|       obj.each do |elename, value|
 | |
|         if value.is_a?(Array)
 | |
|           value.each do |subvalue|
 | |
|             child = from_obj(subvalue, namespace)
 | |
|             child.elename = to_elename(elename, namespace)
 | |
|             o.add(child)
 | |
|           end
 | |
|         else
 | |
|           child = from_obj(value, namespace)
 | |
|           child.elename = to_elename(elename, namespace)
 | |
|           o.add(child)
 | |
|         end
 | |
|       end
 | |
|     else
 | |
|       o.text = obj.to_s
 | |
|     end
 | |
|     o
 | |
|   end
 | |
| 
 | |
|   def self.to_elename(obj, namespace = nil)
 | |
|     if obj.is_a?(XSD::QName)
 | |
|       obj
 | |
|     elsif /\A(.+):([^:]+)\z/ =~ obj.to_s
 | |
|       XSD::QName.new($1, $2)
 | |
|     else
 | |
|       XSD::QName.new(namespace, obj.to_s)
 | |
|     end
 | |
|   end
 | |
| 
 | |
| private
 | |
| 
 | |
|   def add_member(name, value)
 | |
|     add_accessor(name)
 | |
|     @array.push(name)
 | |
|     @data.push(value)
 | |
|     value.parent = self if value.respond_to?(:parent=)
 | |
|     value
 | |
|   end
 | |
| 
 | |
|   if RUBY_VERSION > "1.7.0"
 | |
|     def add_accessor(name)
 | |
|       methodname = name
 | |
|       if self.respond_to?(methodname)
 | |
|         methodname = safe_accessor_name(methodname)
 | |
|       end
 | |
|       Mapping.define_singleton_method(self, methodname) do
 | |
|         @data[@array.index(name)]
 | |
|       end
 | |
|       Mapping.define_singleton_method(self, methodname + '=') do |value|
 | |
|         @data[@array.index(name)] = value
 | |
|       end
 | |
|     end
 | |
|   else
 | |
|     def add_accessor(name)
 | |
|       methodname = safe_accessor_name(name)
 | |
|       instance_eval <<-EOS
 | |
|         def #{methodname}
 | |
|           @data[@array.index(#{name.dump})]
 | |
|         end
 | |
| 
 | |
|         def #{methodname}=(value)
 | |
|           @data[@array.index(#{name.dump})] = value
 | |
|         end
 | |
|       EOS
 | |
|     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 = type || ValueArrayName
 | |
|     @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
 | |
| 
 | |
|     idx = 0
 | |
|     while idx < idxary.size
 | |
|       if idxary[idx] + 1 > @size[idx]
 | |
| 	@size[idx] = idxary[idx] + 1
 | |
|       end
 | |
|       idx += 1
 | |
|     end
 | |
| 
 | |
|     data = retrieve(idxary[0, idxary.size - 1])
 | |
|     data[idxary.last] = value
 | |
| 
 | |
|     if value.is_a?(SOAPType)
 | |
|       value.elename = ITEM_NAME
 | |
|       # Sync type
 | |
|       unless @type.name
 | |
| 	@type = XSD::QName.new(value.type.namespace,
 | |
| 	  SOAPArray.create_arytype(value.type.name, @rank))
 | |
|       end
 | |
|       value.type ||= @type
 | |
|     end
 | |
| 
 | |
|     @offset = idxary
 | |
|     value.parent = self if value.respond_to?(:parent=)
 | |
|     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 = ITEM_NAME
 | |
| 	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
 | |
|       rank = 1
 | |
|       while rank < position.size
 | |
| 	idx = position[rank - 1]
 | |
| 	if iteary[idx].nil?
 | |
| 	  iteary = iteary[idx] = Array.new
 | |
| 	else
 | |
| 	  iteary = iteary[idx]
 | |
| 	end
 | |
|         rank += 1
 | |
|       end
 | |
|       if block_given?
 | |
| 	iteary[position.last] = yield(v)
 | |
|       else
 | |
| 	iteary[position.last] = v
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def position
 | |
|     @position
 | |
|   end
 | |
| 
 | |
| private
 | |
| 
 | |
|   ITEM_NAME = XSD::QName.new(nil, 'item')
 | |
| 
 | |
|   def retrieve(idxary)
 | |
|     data = @data
 | |
|     rank = 1
 | |
|     while rank <= idxary.size
 | |
|       idx = idxary[rank - 1]
 | |
|       if data[idx].nil?
 | |
| 	data = data[idx] = Array.new
 | |
|       else
 | |
| 	data = data[idx]
 | |
|       end
 | |
|       rank += 1
 | |
|     end
 | |
|     data
 | |
|   end
 | |
| 
 | |
|   def traverse_data(data, rank = 1)
 | |
|     idx = 0
 | |
|     while idx < ranksize(rank)
 | |
|       if rank < @rank
 | |
| 	traverse_data(data[idx], rank + 1) do |*v|
 | |
| 	  v[1, 0] = idx
 | |
|        	  yield(*v)
 | |
| 	end
 | |
|       else
 | |
| 	yield(data[idx], idx)
 | |
|       end
 | |
|       idx += 1
 | |
|     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
 |