1# ====================================================================== 2# 3# Copyright (C) 2000-2004 Paul Kulchenko (paulclinger@yahoo.com) 4# SOAP::Lite is free software; you can redistribute it 5# and/or modify it under the same terms as Perl itself. 6# 7# $Id: Serializer.pod 381 2011-08-15 19:28:43Z kutterma $ 8# 9# ====================================================================== 10 11=pod 12 13=head1 NAME 14 15SOAP::Serializer - the means by which the toolkit manages the expression of data as XML 16 17=head1 DESCRIPTION 18 19The SOAP::Serializer class is the means by which the toolkit manages the expression of data as XML. The object that a SOAP::Lite instance uses by default is generally enough for the task, with no need for the application to create its own. The main purpose of this class is to provide a place for applications to extend the serializer by defining additional methods for handling new datatypes. 20 21=head1 METHODS 22 23=over 24 25=item new(optional key/value pairs) 26 27 $serialize = SOAP::Serializer->new( ); 28 29This is the constructor method for the class. In addition to creating a basic object and initializing it with default values, the constructor can also take names and values for most of the accessor methods that the class supports. 30 31=item envelope(method, data arguments) 32 33 $serialize->envelope(fault => $fault_obj); 34 35Provides the core purpose for the SOAP::Serializer class. It creates the full SOAP envelope based on the input passed in to it. The data arguments passed in the list of parameters to the method are divided into two sublists: any parameters that are L<SOAP::Header> objects or derivatives of go into one list, while the remainder go into the other. The nonheader objects are used as the content for the message body, with the body itself being largely dependent on the value of the first argument in the list. This argument is expected to be a string and should be one of the following: 36 37=item context 38 39 $serialize->context->packager(); 40 41This provides access to the calling context of C<SOAP::Serializer>. In a client side context the often means a reference to an instance of SOAP::Lite. In a server side context this means a reference to a SOAP::Server instance. 42 43=over 44 45=item method 46 47The envelope is being created to encapsulate a RPC-style method call. 48 49=item response 50 51The message being created is that of a response stemming from a RPC-style method call. 52 53=item fault 54 55For this specifier, the envelope being created is to transmit a fault. 56 57=item freeform 58 59This identifier is used as a general-case encoding style for messages that 60don't fit into any of the previous cases. The arguments are encoded into the 61envelope's Body tag without any sort of context sensitivity. 62 63=back 64 65Any value other than these four results in an error. 66 67=item envprefix(optional value) 68 69 $serialize->envprefix('env'); 70 71Gets or sets the prefix that labels the SOAP envelope namespace. This defaults to SOAP-ENV. 72 73=item encprefix(optional value) 74 75 $serialize->envprefix('enc'); 76 77Gets or sets the prefix that labels the SOAP encoding namespace. Defaults to SOAP-ENC. 78 79=item soapversion(optional value) 80 81 $serialize->soapversion('1.2'); 82 83If no parameter is given, returns the current version of SOAP that is being used as the basis for serializing messages. If a parameter is given, attempts to set that as the version of SOAP being used. The value should be either 1.1 or 1.2. When the SOAP version is being set, the package selects new URNs for envelope and encoding spaces and also calls the xmlschema method to set the appropriate schema definition. 84 85=item xmlschema(optional value) 86 87 $serialize->xmlschema($xml_schema_1999); 88 89Gets or sets the URN for the schema being used to express the structure of the XML generated by the serializer. If setting the value, the input must be the full URN for the new schema and is checked against the list of known SOAP schemas. 90 91=item register_ns 92 93The register_ns subroutine allows users to register a global namespace 94with the SOAP Envelope. The first parameter is the namespace, the second 95parameter to this subroutine is an optional prefix. If a prefix is not 96provided, one will be generated automatically for you. All namespaces 97registered with the serializer get declared in the <soap:Envelope /> 98element. 99 100=item find_prefix 101 102The find_prefix subroutine takes a namespace as a parameter and returns 103the assigned prefix to that namespace. This eliminates the need to declare 104and redeclare namespaces within an envelope. This subroutine is especially 105helpful in determining the proper prefix when assigning a type to a 106SOAP::Data element. A good example of how this might be used is as follows: 107 108 SOAP::Data->name("foo" => $inputParams{'foo'}) 109 ->type($client->serializer->find_prefix('urn:Foo').':Foo'); 110 111=back 112 113=head1 CUSTOM DATA TYPES 114 115When serializing an object, or blessed hash reference, into XML, C<SOAP::Serializer> first checks to see if a subroutine has been defined for the corresponding class name. For example, in the code below, C<SOAP::Serializer> will check to see if a subroutine called C<as_MyModule__MyPackage> has been defined. If so, then it will pass C<$foo> to that subroutine along with other data known about the C<SOAP::Data> element being encoded. 116 117 $foo = MyModule::MyPackage->new; 118 my $client = SOAP::Lite 119 ->uri($NS) 120 ->proxy($HOST); 121 $som = $client->someMethod(SOAP::Data->name("foo" => $foo)); 122 123=head1 as_TypeName SUBROUTINE REQUIREMENTS 124 125=over 126 127=item Naming Convention 128 129The subroutine should always be prepended with C<as_> followed by the type's name. The type's name must have all colons (':') substituded with an underscore ('_'). 130 131=item Input 132 133The input to C<as_TypeName> will have at least one parameter, and at most four parameters. The first parameter will always be the value or the object to be encoded. The following three parameters depend upon the context of the value/object being encoded. 134 135If the value/object being encoded was part of a C<SOAP::Data> object (as in the above example), then the second, third and fourth parameter will be the C<SOAP::Data> element's name, type, and attribute set respectively. If on the other hand, the value/object being encoded is I<not> part of a C<SOAP::Data> object, as in the code below: 136 137 $foo = MyModule::MyPackage->new; 138 my $client = SOAP::Lite 139 ->uri($NS) 140 ->proxy($HOST); 141 $som = $client->someMethod($foo); 142 143Then the second and third parameters will be the class name of the value/object being encoded (e.g. "MyModule::MyPackage" in the example above), and the fourth parameter will be an empty hash. 144 145=item Output 146 147The encoding subroutine must return an array containing three elements: 1) the name of the XML element, 2) a hash containing the attributes to be placed into the element, and 3) the value of the element. 148 149=back 150 151=head1 AUTOTYPING 152 153When the type of an element has not been declared explicitly, SOAP::Lite must "guess" at the object's type. That is due to the fact that the only form of introspection that Perl provides (through the use of the C<ref> subroutine) does not provide enough information to C<SOAP::Serializer> to allow SOAP::Lite to determine the exact type of an element being serialized. 154 155To work around this limitation, the C<SOAP::Serializer::typelookup> hash was created. This hash is populated with all the data types that the current C<SOAP::Serializer> can auto detect. Users and developers are free to modify the contents of this hash allowing them to register new data types with the system. 156 157When C<SOAP::Serializer> is asked to encode an object into XML, it goes through the following steps. First, C<SOAP::Serializer> checks to see if a type has been explicitly stated for the current object. If a type has been provided C<SOAP::Serializer> checks to see if an C<as_TypeName> subroutine as been defined for that type. If such a subroutine exists, then C<SOAP::Serializer> passes the object to it to be encoded. If the subroutine does not exist, or the type has not been provided, then C<SOAP::Serializer> must attempt to "guess" the type of the object being serialized. 158 159To do so, C<SOAP::Serializer> runs in sequence a set of tests stored in the C<SOAP::Serializer::typelookup> hash. C<SOAP::Serializer> continues to run each test until one of the tests returns true, indicating that the type of the object has been detected. When the type of the object has been detected, then C<SOAP::Serializer> passes the object to the encoding subroutine that corresponds with the test that was passed. If all the tests fail, and the type was not determined, then C<SOAP::Serializer> will as a last resort encode the object based on one of the four basic data types known to Perl: REF, SCALAR, ARRAY and HASH. 160 161The following table contains the set of data types detectable by C<SOAP::Lite> by default and the order in which their corresponding test subroutine will be run, according to their precedence value. 162 163 Table 1 - Autotyping Precedence 164 165 TYPENAME PRECEDENCE VALUE 166 ---------------------------- 167 base64 10 168 int 20 169 long 25 170 float 30 171 gMonth 35 172 gDay 40 173 gYear 45 174 gMonthDay 50 175 gYearMonth 55 176 date 60 177 time 70 178 dateTime 75 179 duration 80 180 boolean 90 181 anyURI 95 182 string 100 183 184 185=head2 REGISTERING A NEW DATA TYPE 186 187To register a new data type that can be automatically detected by C<SOAP::Lite> and then serialized into XML, the developer must provide the following four things: 188 189=over 190 191=item * 192 193The name of the new data type. 194 195=item * 196 197A subroutine that is capable of detecting whether a value passed to it is of the corresponding data type. 198 199=item * 200 201A number representing the test subroutine's precedence relative to all the other types' test subroutinestypes. See I<Table 1 - Autotyping Precedence>. 202 203=item * 204 205A subroutine that is capable of providing C<SOAP::Serializer> with the information necessary to serialize an object of the corresponding data type into XML. 206 207=back 208 209=head3 EXAMPLE 1 210 211If, for example, you wish to create a new datatype called C<uriReference> for which you would like Perl values to be automatically detected and serialized into, then you follow these steps. 212 213B<Step 1: Write a Test Subroutine> 214 215The test subroutine will have passed to it by C<SOAP::Serializer> a value to be tested. The test subroutine must return 1 if the value passed to it is of the corresponding type, or else it must return 0. 216 217 sub SOAP::Serializer::uriReferenceTest { 218 my ($value) = @_; 219 return 1 if ($value =~ m!^http://!); 220 return 0; 221 } 222 223B<Step 2: Write an Encoding Subroutine> 224 225The encoding subroutine provides C<SOAP::Serializer> with the data necessary to encode the value passed to it into XML. The encoding subroutine name's should be of the following format: C<as_><Type Name>. 226 227The encoding subroutine will have passed to it by C<SOAP::Serializer> four parameters: the value to be encoded, the name of the element being encoded, the assumed type of the element being encoded, and a reference to a hash containing the attributes of the element being encoded. The encoding subroutine must return an array representing the encoded datatype. C<SOAP::Serializer> will use the contents of this array to generate the corresponding XML of the value being encoded, or serialized. This array contains the following 3 elements: the name of the XML element, a hash containing the attributes to be placed into the element, and the value of the element. 228 229 sub SOAP::Serializer::as_uriReference { 230 my $self = shift; 231 my($value, $name, $type, $attr) = @_; 232 return [$name, {'xsi:type' => 'xsd:uriReference', %$attr}, $value]; 233 } 234 235B<Step 3: Register the New Data Type> 236 237To register the new data type, simply add the type to the C<SOAP::Serializer::typelookup> hash using the type name as the key, and an array containing the precedence value, the test subroutine, and the encoding subroutine. 238 239 $s->typelookup->{uriReference} 240 = [11, \&uriReferenceTest, 'as_uriReference']; 241 242I<Tip: As a short hand, you could just as easily use an anonymous test subroutine when registering the new datatype in place of the C<urlReferenceTest> subroutine above. For example:> 243 244 $s->typelookup->{uriReference} 245 = [11, sub { $_[0] =~ m!^http://! }, 'as_uriReference']; 246 247Once complete, C<SOAP::Serializer> will be able to serialize the following C<SOAP::Data> object into XML: 248 249 $elem = SOAP::Data->name("someUri" => 'http://yahoo.com')->type('uriReference'); 250 251C<SOAP::Serializer> will also be able to automatically determine and serialize the following untyped C<SOAP::Data> object into XML: 252 253 $elem = SOAP::Data->name("someUri" => 'http://yahoo.com'); 254 255=head1 ACKNOWLEDGEMENTS 256 257Special thanks to O'Reilly publishing which has graciously allowed SOAP::Lite to republish and redistribute large excerpts from I<Programming Web Services with Perl>, mainly the SOAP::Lite reference found in Appendix B. 258 259=head1 COPYRIGHT 260 261Copyright (C) 2000-2004 Paul Kulchenko. All rights reserved. 262 263This library is free software; you can redistribute it and/or modify 264it under the same terms as Perl itself. 265 266=head1 AUTHORS 267 268Paul Kulchenko (paulclinger@yahoo.com) 269 270Randy J. Ray (rjray@blackperl.com) 271 272Byrne Reese (byrne@majordojo.com) 273 274=cut 275