Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

root/tags/RELEASE_1_0_0/lib/SOAPData.rb

Revision 2, 10.4 kB (checked in by nakahiro, 8 years ago)

SOAP4R initial release.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to author date id revision
Line 
1 =begin
2 SOAP4R
3 Copyright (C) 2000 NAKAMURA Hiroshi.
4
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 PRATICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass
16 Ave, Cambridge, MA 02139, USA.
17 =end
18
19 require 'SOAP'
20 require 'XMLSchemaDatatypes'
21 require 'xmltreebuilder'
22
23
24 ###
25 ## SOAP utility module for classes( not instances! )
26 #
27 class SOAPNS
28   public
29
30   attr_reader :defaultNamespace
31   attr_reader :namespaceTag
32
33   def initialize( initNamespace = {} )
34     @namespaceTag = initNamespace
35     @defaultNamespace = nil
36   end
37
38   def assign( namespace, name = nil )
39     if ( @namespaceTag.has_key?( namespace ))
40       false
41     elsif ( name == '' )
42       @defaultNamespace = namespace
43     else
44       name ||= SOAPNS.assign( namespace )
45       @namespaceTag[ namespace ] = name
46       name
47     end
48   end
49
50   def []( namespace )
51     if ( @namespaceTag.has_key?( namespace ))
52       @namespaceTag[ namespace ]
53     else
54       nil
55     end
56   end
57
58   def clone()
59     SOAPNS.new( @namespaceTag.dup )
60   end
61
62   def name( namespace, name )
63     if ( namespace == @defaultNamespace )
64       name
65     elsif @namespaceTag.has_key?( namespace )
66       @namespaceTag[ namespace ] + ':' << name
67     else
68       raise FormatDecodeError.new( 'Namespace: ' << namespace << ' not defined yet.' )
69     end
70   end
71
72   def compare( namespace, name, rhs )
73     if ( namespace == @defaultNamespace )
74       return true if ( name == rhs )
75     end
76
77     if @namespaceTag.has_key?( namespace )
78       return (( @namespaceTag[ namespace ] + ':' << name ) == rhs )
79     end
80
81     return false
82   end
83
84   # $1 and $2 are necessary.
85   ParseRegexp = Regexp.new( '^([^:]+)(?::(.+))?$' )
86
87   def parse( elem )
88     namespace = nil
89     name = nil
90     ParseRegexp =~ elem
91     if $2
92       namespace = @namespaceTag.index( $1 )
93       name = $2
94       if !namespace
95         raise FormatDecodeError.new( 'Unknown namespace qualifier: ' << $1 )
96       end
97     elsif $1
98       namespace = @defaultNamespace
99       name = $1
100     end
101     if !name
102       raise FormatDecodeError.new( 'Illegal element format: ' << elem )
103     end
104     return namespace, name
105   end
106
107   private
108
109   AssigningName = [ 0 ]
110
111   def SOAPNS.assign( namespace )
112     AssigningName[ 0 ] += 1
113     'n' << AssigningName[ 0 ].to_s
114   end
115
116   def SOAPNS.reset()
117     AssigningName[ 0 ] = 0
118   end
119 end
120
121
122 ###
123 ## SOAP related datatypes.
124 #
125 module SOAPModuleUtils
126   include SOAP
127   include XML::SimpleTree
128
129   public
130
131   def decode( ns, elem )
132     elem.normalize
133     value = if elem.childNodes[0]
134         elem.childNodes[0].nodeValue
135       else
136         ''
137       end
138     d = self.new( value )
139     d.namespace, = ns.parse( elem.nodeName )
140     d
141   end
142
143   private
144
145   def decodeChild( ns, elem )
146     if isNull( ns, elem )
147       return SOAPNull.decode( ns, elem )
148     end
149
150     case getType( ns, elem )
151     when 'boolean'
152       SOAPBoolean.decode( ns, elem )
153     when 'string'
154       SOAPString.decode( ns, elem )
155     when 'timeInstant'
156       SOAPTimeInstant.decode( ns, elem )
157     when 'integer'
158       SOAPInteger.decode( ns, elem )
159     when /\[\d*\]$/
160       SOAPArray.decode( ns, elem )
161     else
162       bOnlyText = true
163       elem.childNodes.each do | child |
164         next if ( isEmptyText( child ))
165         bOnlyText = false
166         break
167       end
168       if bOnlyText
169         # No type is set. Decode as SOAPString by default.
170         SOAPString.decode( ns, elem )
171       else
172         SOAPStruct.decode( ns, elem )
173       end
174     end
175   end
176
177   EmptyTextRegexp = Regexp.new( '\s*(?:\n\s*)*' )
178
179   def isEmptyText( node )
180     (( node.nodeName == '#text' ) and ( EmptyTextRegexp =~ node.nodeValue ))
181   end
182
183   def isNull( ns, elem )
184     elem.attributes.each do | attr |
185       if ( ns.compare( XSD::InstanceNamespace, 'null', '1' ))
186         return true
187       end
188     end
189     false
190   end
191
192   def getType( ns, elem )
193     elem.attributes.each do | attr |
194       if ( ns.compare( XSD::InstanceNamespace, 'type', attr.nodeName ))
195         return attr.nodeValue
196       end
197     end
198     nil
199   end
200
201   # $1 is necessary.
202   NSParseRegexp = Regexp.new( '^xmlns:?(.*)$' )
203
204   def parseNS( ns, elem )
205     return unless elem.attributes
206     elem.attributes.each do | attr |
207       next unless ( NSParseRegexp =~ attr.nodeName )
208       # '' means 'default namespace'.
209       tag = $1 || ''
210       ns.assign( attr.nodeValue, tag )
211     end
212   end
213 end
214
215 module SOAPBasetypeUtils
216   include SOAP
217   include XML::SimpleTree
218
219   public
220
221   attr_reader :attrs
222
223   def initialize( *vars )
224     super( *vars )
225
226 # SOAP Basetype is a XSD type.  No need to reset @namespace.
227 #    @namespace = EnvelopeNamespace
228
229   end
230
231   def encode( ns, namespace, name )
232     attrs = []
233     unless ns[ XSD::Namespace ]
234       tag = ns.assign( XSD::Namespace )
235       attrs.push( Attr.new( 'xmlns:' << tag, XSD::Namespace ))
236     end
237
238     # @typeName is in XSDBase
239     attrs.push( datatypeAttr( ns ))
240
241     if ( self.to_s.empty? )
242       #Element.new( ns.name( namespace, name ), attrs )
243       Element.new( name, attrs )
244     else
245       #Element.new( ns.name( namespace, name ), attrs, Text.new( self.to_s ))
246       Element.new( name, attrs, Text.new( self.to_s ))
247     end
248   end
249
250   def ==( rhs )
251     self.data == rhs
252   end
253
254   private
255
256   def datatypeAttr( ns )
257     Attr.new( ns.name( XSD::InstanceNamespace, 'type' ), ns.name( @namespace, @typeName ))
258   end
259 end
260
261
262 ###
263 ## Basic datatypes.
264 #
265 class SOAPNull < XSDNull
266   extend SOAPModuleUtils
267   include SOAPBasetypeUtils
268
269   private
270
271   # Override the definition in SOAPBasetypeUtils.
272   def datatypeAttr( ns )
273     Attr.new( ns.name( XSD::Namespace, 'null' ), '1' )
274   end
275
276   # Override the definition in SOAPModuleUtils
277   def decode( ns, elem )
278     d = self.new()
279     d.namespace, = ns.parse( elem.nodeName )
280     d
281   end
282 end
283
284 class SOAPBoolean < XSDBoolean
285   extend SOAPModuleUtils
286   include SOAPBasetypeUtils
287 end
288
289 class SOAPString < XSDString
290   extend SOAPModuleUtils
291   include SOAPBasetypeUtils
292 end
293
294 class SOAPInteger < XSDInteger
295   extend SOAPModuleUtils
296   include SOAPBasetypeUtils
297 end
298
299 class SOAPTimeInstant < XSDTimeInstant
300   extend SOAPModuleUtils
301   include SOAPBasetypeUtils
302 end
303
304
305 ###
306 ## Compound datatypes.
307 #
308 class SOAPCompoundBase < NSDBase
309   extend SOAPModuleUtils
310
311   public
312
313   def initialize( typeName )
314     super( typeName, EnvelopeNamespace )
315   end
316 end
317
318
319 class SOAPStruct < SOAPCompoundBase
320   include Enumerable
321
322   public
323
324   attr_reader :array
325   attr_reader :data
326
327   def initialize( typeName )
328     super( typeName )
329     @array = []
330     @data = {}
331   end
332
333   def to_s()
334     str = ''
335     self.each do | key, data |
336       str << "#{ key }: #{ data }\n"
337     end
338     str
339   end
340
341   def add( name, newMember )
342     addMember( name, newMember )
343   end
344
345   def []( idx )
346     if ( idx > array.size )
347       raise ArrayIndexOutOfBoundsError.new( 'In ' << @typeName )
348     end
349     @array[ idx ]
350   end
351
352   def has_key?( name )
353     @data.has_key?( name )
354   end
355
356   def each
357     @array.each do | key |
358       yield( key, @data[ key ] )
359     end
360   end
361
362   def encode( ns, namespace, name )
363     attrs = []
364     unless ns[ @namespace ]
365       tag = ns.assign( @namespace )
366       attrs.push( Attr.new( 'xmlns:' << tag, @namespace ))
367     end
368
369     attrs.push( Attr.new( ns.name( XSD::InstanceNamespace, 'type' ), ns.name( @namespace, @typeName )))
370
371     children = @array.collect { | child |
372       @data[ child ].encode( ns.clone, namespace, child )
373     }
374
375     #Element.new( ns.name( namespace, name ), attrs, children )
376     Element.new( name, attrs, children )
377   end
378
379   def decode( ns, elem )
380     namespace, name = ns.parse( elem.nodeName )
381     s = SOAPStruct.new( name )
382     s.namespace = namespace
383
384     elem.childNodes.each do | child |
385       childNS = ns.clone
386       parseNS( childNS, child )
387       next if ( isEmptyText( child ))
388       childName = ns.parse( child.nodeName )[1]
389       s.add( childName, decodeChild( childNS, child ))
390     end
391     s
392   end
393   module_function :decode
394
395   private
396
397   def addMember( name, initMember = nil )
398     initMember = SOAPNull.new() unless initMember
399
400     instance_eval <<-EOS
401       def #{ name }()
402         @data[ '#{ name }' ]
403       end
404
405       def #{ name }=( newMember )
406         @data[ '#{ name }' ] = newMember
407       end
408     EOS
409
410     @array.push( name )
411     @data[ name ] = initMember
412   end
413 end
414
415 class SOAPArray < SOAPCompoundBase
416   include Enumerable
417
418   public
419
420   attr_reader :data
421
422   def initialize( typeName = nil )
423     super( typeName )
424     @data = []
425     @variant = false
426   end
427
428   def set( newArray )
429     raise NotImplementError.new( 'Partially transmittion does not supported' )
430   end
431
432   def add( newMember )
433     if ( @data.empty? and !@typeName )
434       @typeName = newMember.typeName
435     end
436     if ( @typeName != newMember.typeName )
437       @variant = true
438     end
439     @data << newMember
440   end
441
442   def []( idx )
443     if ( idx > @data.size )
444       raise ArrayIndexOutOfBoundsError.new( 'In ' << @typeName )
445     end
446     @data[ idx ]
447   end
448
449   def each
450     @data.each do | datum |
451       yield( datum )
452     end
453   end
454
455   def encode( ns, namespace, name )
456     children = @data.collect { | child |
457       child.encode( ns.clone, namespace, @typeName )
458     }
459     attr = Attr.new( ns.name( XSD::InstanceNamespace, 'type' ),
460       ns.name( namespace, createType( @typeName, @data.size )))
461     #Element.new( ns.name( namespace, name ), attr, children )
462     Element.new( name, attr, children )
463   end
464
465   def isVariant?
466     @variant
467   end
468
469   # Module function
470
471   public
472
473   def decode( ns, elem )
474     typeNamespace, typeNameString = ns.parse( getType( ns, elem ))
475     typeName, nofArray = parseType( typeNameString )
476     s = SOAPArray.new( typeName )
477     s.namespace, = ns.parse( elem.nodeName )
478
479     i = 0
480     elem.childNodes.each do | child |
481       childNS = ns.clone
482       parseNS( childNS, child )
483       next if ( isEmptyText( child ))
484       s.add( decodeChild( childNS, child ))
485       i += 1
486       if ( nofArray and ( i > nofArray.to_i ))
487         raise ArrayIndexOutOfBoundsError.new( 'In ' << elem.nodeName )
488       end
489     end
490     s
491   end
492   module_function :decode
493
494   private
495
496   def createType( typeName, length = nil )
497     "#{ typeName }[#{ length }]"
498   end
499   module_function :createType
500
501   TypeParseRegexp = Regexp.new( '^(.+)\[(\d*)\]$' )
502
503   def parseType( string )
504     TypeParseRegexp =~ string
505     return $1, $2
506   end
507   module_function :parseType
508 end
Note: See TracBrowser for help on using the browser.