Search
Categories
Documents
README
WDDX.pm - Module for reading and writing WDDX packets (Displayed)
|
WDDX.pm - Module for reading and writing WDDX packets
WDDX.pm - Module for reading and writing WDDX packets
Version 1.02
$Header: /home/cvs/wddx/WDDX.pm,v 1.4 2003/12/02 03:41:10 andy Exp $
use WDDX;
my $wddx = new WDDX;
# Serialization example
my $wddx_hash = $wddx->hash( {
str => $wddx->string( "Welcome to WDDX!\n" ),
num => $wddx->number( -12.456 ),
date => $wddx->datetime( date ),
bool => $wddx->boolean( 1 ),
arr => $wddx->array( [
$wddx->boolean( 0 ),
$wddx->number( 10 ),
$wddx->string( "third element" ),
] ),
rec => $wddx->recordset(
[ "NAME", "AGE" ],
[ "string", "number" ],
[
[ "John Doe", 34 ],
[ "Jane Doe", 25 ],
[ "Fred Doe", 90 ],
]
),
obj => $wddx->hash( {
str => $wddx->string( "a string" ),
num => $wddx->number( 3.14159 ),
} ),
bin => $wddx->binary( $img_data ),
null => $wddx->null(),
} );
print $wddx->header;
print $wddx->serialize( $wddx_hash );
# Deserialization example
my $wddx_request = $wddx->deserialize( $packet );
# Assume that our code expects an array
$wddx_request->type eq "array" or die "Invalid request";
my $array_ref = $wddx_request->as_arrayref;
From http://www.wddx.org/:
The Web Distributed Data Exchange, or WDDX, is a free, open XML-based
technology that allows Web applications created with any platform to
easily exchange data with one another over the Web.
WDDX defines basic data types that mirror the data types available in
other common programming languages. Many of these data types don't
have corresponding data types in Perl. To Perl, strings, numbers,
booleans, and dates are just scalars. However, in order to communicate
effectively with other languages (and this is the point of WDDX), you
do have to learn the basic WDDX data types. Here is a table that maps
the WDDX data type to Perl, along with the intermediate object WDDX.pm
represents it as:
WDDX Type WDDX.pm Data Object Perl Type
--------- ------------------- ---------
String WDDX::String Scalar
Number WDDX::Number Scalar
Boolean WDDX::Boolean Scalar (1 or "")
Datetime WDDX::Datetime Scalar (seconds since epoch)
Null WDDX::Null Scalar (undef)
Binary WDDX::Binary Scalar
Array WDDX::Array Array
Struct WDDX::Struct Hash
Recordset WDDX::Recordset WDDX::Recordset
In languages that have data types similar to the WDDX data types, the
WDDX modules allow you to convert directly from a variable to a WDDX
packet and vice versa. This Perl implementation is different; here you
must always go through an intermediate stage where the data is
represented by an object with a corresponding data type. These objects
can be converted to a WDDX packet, converted to a basic Perl type, or
converted to JavaScript code (which will recreate the data for you in
JavaScript). We will refer to these objects as data objects
throughout this documentation.
This module requires the XML::Parser manpage and the MIME::Base64 manpage, which are
both available on CPAN at http://www.cpan.org/. Windows users note:
These modules use compiled code, but I have been told that they are both
included with recent distributions of ActiveState Perl.
This creates a new WDDX object. You need one of these to do pretty much
anything else. It doesn't take any arguments.
This method deserializes a WDDX packet and returns a data object. Note
that you can pass either a string or a reference to an open filehandle
containing a packet (XML::Parser is flexible this way):
$wddx_obj = $wddx->deserialize( $packet ); # OR
$wddx_obj = $wddx->deserialize( \*HANDLE );
If WDDX.pm or the underlying the XML::Parser manpage finds any errors with the
structure of the WDDX packet, then it will die with an error
message that identifies the problem. If you don't want this to terminate
your script, you will have to place this call within an eval block
to trap the die.
This accepts a data object as an argument and returns a WDDX packet.
This method calls the as_packet() method on the data object
it receives. However, this method does provide one feature that
as_packet() does not. If $WDDX::INDENT is set to a defined value,
then the generated WDDX packet is indented using $WDDX::INDENT
as the unit of indentation. Otherwise packets are generated without
extra whitespace.
Note that the generated packet is not a valid XML document without the
header, see below.
This returns a header that should accompany every serialized packet you
send.
All of the WDDX data objects share the following common methods:
- $wddx_obj->type
-
This returns the data type of the object. It is lowercase and maps
to the package name without the WDDX prefix. For example, type will
return ``string'' for WDDX::String objects, ``datetime'' for WDDX::Datetime
objects, etc.
- $wddx_obj->as_packet
-
This returns a WDDX packet for the object. You can also do this by
passing the object to the
$wddx-serialize> method. See the warning
in $wddx-header>.
- $wddx_obj->as_javascript( $js_varname )
-
This method takes the name of a JavaScript variable and returns the
actual JavaScript code to assign this data object to the given
JavaScript variable. No temporary variables are created to avoid
any danger of variable name collisions.
-
Example:
-
$options[0] = $wddx->string( "First Choice" );
$options[1] = $wddx->string( "Second Choice" );
$options[2] = $wddx->string( "Third Choice" );
$w_array = $wddx->array( \@options );
print $w_array->as_javascript( "myArray" );
-
This prints the text (new lines added for readability):
-
myArray=new Array();
myArray[0]="First Choice";
myArray[1]="Second Choice";
myArray[2]="Third Choice";
-
All data types are supported, and arrays and hashes (structs) can nest
to any level. Recordset and binary objects require the JavaScript
WddxRecordset and WddxBinary constructors. The easiest way to include
these is to add a reference to the wddx.js file:
-
<SCRIPT NAME="javascript" SRC="wddx.js"></SCRIPT>
-
wddx.js is the WDDX library for JavaScript. It is available as part of
the WDDX SDK at http://www.wddx.org/.
- $wddx->string( 'Just a bunch of text...' )
-
This creates a WDDX string object. Strings contain 8 bit characters,
can be any length, and should not include embedded nulls. However,
control characters and characters that have special meaning for XML
(like <, >, and &) are safely encoded for you.
- $w_string->as_scalar
-
This returns the value of the WDDX::String as a Perl scalar.
- $wddx->number( 3.14159 )
-
This creates a WDDX number object. Numbers are restricted to
+/-1.7e308 and if you exceed these bounds this method dies with an
error. Floating point numbers are restricted to 15 digits of accuracy
past the decimal. If you exceed this then the number is truncated to
15 digits with a warning. If you pass a non-numeric scalar to this,
then it is simply treated as a number: Perl will attempt to translate
it, will probably use zero, and will issue a warning.
- $w_number->as_scalar
-
This returns the value of the WDDX::Number as a Perl scalar.
- $wddx->boolean( 1 )
-
This creates a WDDX boolean object. It simply tests the argument in a
boolean context, so ``0'' and ``'' are false and anything else is true.
- $w_boolean->as_scalar
-
This returns the value of the WDDX::Boolean as a Perl scalar. True
is represented by 1 and false is represented by an empty string.
- $wddx->datetime
-
This creates a WDDX Datetime object.
- $w_datetime->use_timezone_info( 1 )
-
This sets or reads the flag that says whether to include the
timezone info (local hour and minute offset from UTC) in WDDX
packets created from this object. By default this is turned on
for new objects. You can turn it off by passing a false (but not
undef) argument to this method.
-
When a WDDX::Datetime object is deserialized from a packet, this
method will indicate whether timezone information was present in that
packet.
- $w_datetime->as_scalar
-
This returns the value of the WDDX::Datetime as a Perl scalar. It
contains the number of seconds since the epoch localized for the
current machine (like Perl's built-in
time function). This number
can be passed into Perl's localtime function.
- $wddx->
null()
-
This creates a WDDX null object. This is roughly the equivalent of
undef in Perl. It takes no arguments.
- $w_datetime->as_scalar
-
This simply returns
undef (this was a hard one to code :).
- $wddx->binary( $binary_data )
-
This creates a WDDX binary object. It takes a scalar containing any
data, which will be base64 encoded before being serialized into the
packet.
- $wddx->array( [ $wddx_obj1, $wddx_obj2, ... ] )
-
This creates a WDDX::Array object. It takes a reference to an array
containing data objects. You must construct a WDDX data object for
each element of an array before adding them to the array. WDDX::Arrays
can contain any other WDDX data type and do not need to be of a uniform
type, so one array can contain a WDDX::String, a WDDX::Number, and
a WDDX::Struct, for example.
-
If you need to create an array of uniform types, Perl's built-in
map function makes this easy. If you have a standard Perl array
called @array, you can generate a WDDX::Array of WDDX::String
objects like this:
-
my @obj_array = map $wddx->number( $_ ), @array;
my $wddx_array = $wddx->array( \@obj_array );
-
If you need to serialize more complicated array structures, refer to
array2wddx in the UTILITY METHODS section.
- $wddx_array->
as_arrayref()
-
This returns a reference to a Perl array. Every element in the
WDDX::Array is recursively deserialized to Perl data structures. Only
WDDX::Recordsets remain as WDDX data objects.
- $wddx_array->get_element( $i )
- $wddx_array->get( $i )
-
This allows you to get an element of a WDDX::Array as a data object
instead of having it deserialized to Perl.
- $wddx_array->set( $i => $wddx_obj );
-
This allows you to set an element in a WDDX::Array. Note that
$wddx_obj
should be a WDDX data object of some type.
- $wddx_array->splice( $offset, $length, $wddx_obj1, $wddx_obj2, ... );
- $wddx_array->splice( $offset, $length );
- $wddx_array->splice( $offset );
-
This allows you to insert or delete elements in a WDDX::Array using
the syntax of Perl's built-in
splice function.
- $wddx_array->length();
-
This returns the number of elements in the WDDX::Array object.
- $wddx_array->push( $wddx_obj1, $wddx_obj2, ... );
-
This will push the given elements onto the WDDX::Array object.
- $wddx_array->pop();
-
This will pop the last element off the WDDX::Array object and return it.
- $wddx_array->unshift( $wddx_obj1, $wddx_obj2, ... );
-
This will unshift the given elements onto the WDDX::Array object.
- $wddx_array->shift();
-
This will shift the first element off the WDDX::Array object and return it.
- $wddx->struct( { key1 => $wddx_obj1, key2 => $wddx_obj2, ... } )
- $wddx->hash ( { key1 => $wddx_obj1, key2 => $wddx_obj2, ... } )
-
This creates a WDDX::Struct object. To WDDX, a struct is simply what
Perl refers to as a hash (or associative array). These two methods are
aliases so you can use whichever name you prefer.
-
There are no restrictions on keys, but values must be WDDX data types.
Just like with WDDX::Arrays, you have to create a WDDX data type for
each value you want to insert into a WDDX::Struct.
-
Here's how to use Perl's built-in map function to generate a
WDDX::Struct if all of your values have the same data type.
If you have a standard Perl hash called %hash, you can generate a
WDDX::Struct of WDDX::String objects like this:
-
my %obj_hash = map { $_ => $wddx->number( $hash{$_} } keys %hash;
my $wddx_hash = $wddx->hash( \@obj_hash );
-
If you need to serialize more complicated hash structures, refer to
hash2wddx in the UTILITY METHODS section.
- $wddx_array->
as_hashref()
-
This returns a reference to a Perl hash. Every element in the hash
is recursively deserialized to Perl data structures. Only
WDDX::Recordsets remain as data objects.
- $wddx_hash->get_element( $key );
- $wddx_hash->get( $key );
-
This allows you to get an element of a WDDX::Struct as a data object
instead of having it deserialized to Perl.
- $wddx_hash->set( $key => $wddx_obj );
-
This allows you to set a key/value pair in a WDDX::Struct. Note that
$wddx_obj should be a WDDX data object of some type.
- $wddx_hash->delete( $key );
-
This allows you to delete a key from a WDDX::Struct.
- $wddx_hash->keys();
-
This will return a list of keys for the WDDX::Struct object or the number
of keys (if called in a scalar context).
- $wddx_hash->values();
-
This will return a list of values for the WDDX::Struct object or the number
of values (if called in a scalar context). Note that each one of these
values should be a WDDX data object of some type.
- $wddx->recordset( [ NAME_A, NAME_B, ... ], [ TYPE_A, TYPE_B, ... ],
[ DATA ] )
-
This creates a WDDX::Recordset object. Recordsets hold tabular data.
There is no corresponding data type in Perl, but it corresponds
with the type of output you would receive from a SQL query.
-
The first argument when constructing a recordset should be a reference
to an array containing the names of each of the fields. The second
argument an reference to an array containing the types of each of the
fields. Field types must be simple, so the valid types are ``string'',
``number'', ``boolean'', or ``datetime''. The last argument is an optional
reference to an array of arrays -- in other words a table of data.
Note that this table of data contains plain old Perl scalars; you
should not create WDDX objects for each value as you would for an
array or a hash.
-
$wddx_rec = $wddx->recordset( [ NAME_A, NAME_B, ... ],
[ TYPE_A, TYPE_B, ... ],
[ [ $val_a1, $val_b1, ... ],
[ $val_b1, $val_b2, ... ],
...
] )
-
This is simple to use with DBI:
-
$data = $dbh->selectall_arrayref( "SELECT NAME, AGE FROM TABLE" ) or
die $dbh->errstr;
$wddx_rec = $wddx->recordset( [ "NAME", "AGE" ],
[ "string", "number" ],
$data );
-
Recordsets that are within arrays or hashes are not automatically
deserialized for you when you deserialize the array or hash. They remain
as recordset objects. You can use the methods below to access the data.
-
Note: It is possible to receive a packet for a recordset that does not
contain any records. In WDDX, the data type for each field is determined
by looking at how the data in the field has been tagged; so if there is
no data, then there is no data type information. Thus if you deserialize
an empty recordset packet, add data to the resulting recordset object,
and attempt to serialize it back into a packet, you will get an error
because WDDX.pm will not know what data type to assign to the data you
added. To avoid this, you should call the types() method to set the data
types before you serialize a recordset object that was created by
deserializing a packet. (If this explanation makes no sense, reread it
a few times; if it still doesn't make sense, email me and let me know. :)
- $wddx_rec->names
-
Returns a reference to an array of the field names. You can also pass
a reference to an array to set the names.
- $wddx_rec->types
-
Returns a reference to an array of the field data types. You can also pass
a reference to an array to set the data types.
- $wddx_rec->table
-
Returns a reference to an array of rows, each containing an array of fields.
You can also pass a reference to an array to set all the data at once.
- $wddx_rec->num_rows
-
Returns the number of rows.
- $wddx_rec->num_columns
-
Returns the number of columns (or fields in a row).
- $wddx_rec->get_row( $row_num )
-
Takes an row index (0 base) and returns a reference to an array for that row.
- $wddx_rec->add_row( [ ARRAY ] )
-
Takes a reference to an array and adds this row to the bottom of the rows.
- $wddx_rec->del_row( $row_num )
-
Takes a row index and deletes that row.
- $wddx_rec->set_row( $row_num, [ ARRAY ] )
-
Takes a row index and a reference to an array. It replaces that row with
this new array.
- $wddx_rec->get_column( $col_name )
-
Takes a column name or index (0 base) and returns a reference to an
array for that column.
- $wddx_rec->add_column( 'NAME', 'TYPE', [ ARRAY ] )
-
Takes a column name, type, and a reference to an array and adds the column
to the end of the columns.
- $wddx_rec->set_column( 'NAME', [ ARRAY ] )
-
Takes a column name or index (0 base) and a reference to an array.
Replaces the column with the values from this array.
- $wddx_rec->del_column( $name )
-
Takes a column name or index (0 base) and deletes the column.
- $wddx_rec->get_element( $col_name, $row_num )
-
Takes a column name or index (0 base) and row number and returns the
value of the intersecting cell.
- $wddx_rec->set_element( $col_name, $row_num, 'New value' )
-
Takes a row number, a column number, and a value and sets the value of
the intersecting cell.
- $wddx_rec->get_field( $row_num, $col_num )
-
DEPRECATED! Takes a row number and column number and returns the value
of the intersecting cell.
-
This method is deprecated. Because WDDX often refers to columns in a
recordset as fields, this method name may be confusing. It has been
replaced by get_element() and will be removed in a future version.
- $wddx_rec->set_field( $row_num, $col_num, 'New value' )
-
DEPRECATED! Takes a row number, a column number, and a value and sets
the value of the intersecting cell.
-
This method is deprecated. Because WDDX often refers to columns in a
recordset as fields, this method name may be confusing. It has been
replaced by set_element() and will be removed in a future version.
These methods make it easier to go from Perl to WDDX data objects and
vice versa.
- $wddx->wddx2perl( $wddx_obj );
-
This takes a WDDX data object and returns a scalar if it is a simple
data type, an array reference if it is an array, a hash reference if
it is a struct, and a WDDX::Recordset object if it is a recordset.
- $wddx->scalar2wddx( $scalar, [ $type ] );
-
This method takes a scalar and a data type and returns the scalar as a
WDDX data object of the given type. Type should be one of the simple
WDDX data types (i.e. string, number, boolean, datetime, null, or
binary), and if it is not supplied, then string is assumed.
-
This method is convenient if you have the type stored in a variable,
since it avoids you having to do a bunch of if/else statements to
call the corresponding data object constructor.
- $wddx->array2wddx( $arrayref, [ $coderef ] );
- $wddx->hash2wddx( $hashref, [ $coderef ] );
-
These methods attempt to provide a way for you to generate complex
WDDX data types from complicated Perl structures. In their simplest
form, they will generate a corresponding WDDX data object by
serializing all scalars as strings. This may be sufficient for your
needs, but it likely will not. Thus, these methods also allow you to
determine the type for each scalar. To do so, you must provide a
reference to a sub.
-
Your sub will be called for each value within the array or a hash
you supply, as well as each value within any nested arrays or
hashes. Thus your sub may need to support both hashes and arrays.
-
If your sub is called within an array, it will receive the following
arguments:
-
1. the index of the current element
2. the value of the current element
3. the text "ARRAY"
If your sub is called within a hash, it will receive the following
arguments:
-
1. the key of the current pair
2. the value of the current pair
3. the text "HASH"
-
You must return the type of the data object to construct (e.g.
``number'') or a false value if you want to let the element continue to
the next rule. The rules for converting elements into WDDX data
objects are as follows:
1. If the element is already a WDDX data object, then it is left
alone.
2. Your subroutine is called (if provided). If a true value is not
returned, then we skip to rule 3. If you return an invalid data type,
then this method dies with an error. If you return a valid data
type then:
a. If the current element is a scalar then this element is
converted to a WDDX data object of the type you specified.
b. If the current element is a reference to a hash or an array,
then this hash or array is converted to a WDDX data object with
each element having the type you specified (this applies to
all nested arrays and hashes too).
3. If the current element is a reference to a hash or an array
then wddx2array or wddx2hash is called on it and your sub
(if provided) propagates.
4. Any scalars that have not been handled by a previous rule
are treated as strings.
Here is an example. Assume that you have the following data
structure in Perl:
$weather_data = {
title => "Weather Conditions",
region => "San Francisco Bay Area",
current => {
temp => 72,
sky => "mostly clear",
precip => undef,
wind => 12
},
tomorrow => {
temps => [ 62 => 75 ],
sky => "partly cloudy",
precip => undef,
winds => [ 5 => 10 ]
}
};
To convert this to a WDDX object you could create a handler and
use it to create a WDDX object like this:
$type_sub = sub {
my( $name, $val, $mode ) = @_;
! defined( $val ) and return ``null'';
$name =~ /temp/ and return ``number'';
$name =~ /wind/ and return ``number'';
};
my $wddx_weather = $wddx->hash2wddx( $weather_data, $type_sub );
Then you can easily serialize the WDDX object to a packet:
$WDDX::INDENT = `` '';
print $wddx->serialize( $wddx_weather );
This prints:
<wddxPacket version='1.0'>
<header/>
<data>
<struct>
<var name='tomorrow'>
<struct>
<var name='temps'>
<array length='2'>
<number>0</number>
<number>1</number>
</array>
</var>
<var name='precip'>
<null/>
</var>
<var name='winds'>
<array length='2'>
<number>0</number>
<number>1</number>
</array>
</var>
<var name='sky'>
<string>partly cloudy</string>
</var>
</struct>
</var>
<var name='title'>
<string>Weather Conditions</string>
</var>
<var name='current'>
<struct>
<var name='wind'>
<number>12</number>
</var>
<var name='precip'>
<null/>
</var>
<var name='temp'>
<number>72</number>
</var>
<var name='sky'>
<string>mostly clear</string>
</var>
</struct>
</var>
<var name='region'>
<string>San Francisco Bay Area</string>
</var>
</struct>
</data>
</wddxPacket>
Of course, the handler you construct will vary depending on each
particular data structure.
I pulled the examples out of here when I realized that this POD was
over 50 screenfuls on a standard term! For more lengthy examples,
please visit http://www.scripted.com/wddx/ or http://www.wddx.org/.
WDDX does not support 16 bit character sets (at least not without
encoding them as binary objects).
Every element of data must be encoded as an object. This increases
memory usage somewhat, and it also means any data you transfer must
fit in memory.
This is actually a non-bug: XML::Parser untaints data as it parses it.
This is dangerous. WDDX.pm retaints the data it receives from XML::Parser
so you should be safe if you are running in taint mode. Note: WDDX.pm
uses $0 to retaint data, so if you untaint $0 then any subsequent
WDDX.pm data will be untainted too. Taint is explained perlsec.
Nate Weiss, the man behind the WDDX SDK, has been an especially huge
help.
David Medinets started an earlier version of a Perl and WDDX module
available at http://www.codebits.com/wddx/.
The following people have helped provide feedback, bug reports, etc.
for this module:
Thomas R. Hall
David J. MacKenzie
Jon Sala
Wolfgang ???
James Ritter
Miguel Marques
Vadim Geshel
Adolfo Garcia
Sean McGeever
Allie Rogers
Ziying Sherwin
Origianally by Scott Guelich <scott@scripted.com>, now maintained
by Andy Lester <andy@petdance.com>.
Information
|
This site is currently in testing, it is not yet operating using the full database. Until it is officially launched you may wish to visit Help-Site Computer Manuals. After launch, this site (HelpSpy) will replace Help-Site. Information about the spider which is currently trawling the Internet looking for links to add to this directory can be found here. |
|
|