wddx(3)
NAME
WDDX.pm - a module for reading and writing WDDX packets
SYNOPSIS
use WDDX;
my $wddx = new WDDX;
##########################
## Serialization example
my $wddx_hash = $wddx->hash( {
str => $wddx->string( "Welcome to WDDX!0 ),
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;
DESCRIPTION
About WDDX
This is from the WDDX.org web site: "The Web Distributed
Data Exchange, or WDDX, is a free, open XML-based technol
ogy that allows Web applications created with any platform
to easily exchange data with one another over the Web."
For more information about WDDX, visit
http://www.wddx.org/. For information about using Perl
with WDDX (including examples) you can also visit
http://www.scripted.com/wddx/.
WDDX and Perl
- 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 repre
sented 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.
Requirements
This module requires XML::Parser and MIME::Base64, which
are both available on CPAN at http://www.cpan.org/. Win
dows users note: These modules use compiled code, but I
have been told that they are both included with recent
distributions of ActiveState Perl.
METHODS
- new This creates a new WDDX object. You need one of these
- to do pretty much anything else. It doesn't take any
arguments. - $wddx->deserialize( $string_or_filehandle )
- 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( ANDLE ); - If WDDX.pm or the underlying XML::Parser 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". - $wddx->serialize( $wddx_obj )
- 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 doc
ument without the header, see below. - $wddx->header
- This returns a header that should accompany every
serialized packet you send.
WDDX DATA OBJECTS
Common Methods
All of the WDDX data objects share the following common
methods:
- $wddx_obj->type
- This returns the data type of the object. It is lower
case 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 tem
porary 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 readabil
ity):
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
- $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
- $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
- $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 repre
sented by an empty string. - WDDX::Datetime
- $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 off
set 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
- $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
- $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->array( [ $wddx_obj1, $wddx_obj2, ... ] )
- This creates a WDDX::Array object. It takes a refer
ence 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 gen
erate 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 struc
tures, refer to "array2wddx" in the UTILITY METHODS
section. - $wddx_array->as_arrayref()
- This returns a reference to a Perl array. Every ele
ment 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
- $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 associa
tive 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 struc
tures, 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
- $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 refer
ence 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 deserial
ize 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 record
set 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 dese
rializing 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 contain
ing 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_ele_
ment() 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_ele_
ment() and will be removed in a future version.
Utility Methods
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 gen
erate 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 con
struct (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
"die"s 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 pre
vious 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 depend
ing on each particular data structure.
EXAMPLES
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/.
BUGS
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.
CREDITS
Nate Weiss, the man behind the WDDX SDK, has been an espe
cially 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
AUTHOR
- Scott Guelich <scott@scripted.com>