NAME
XMLRPC::Fast - fast XML-RPC encoder/decoder
SYNOPSIS
use XMLRPC::Fast;
my $xml = encode_xmlrpc_request("auth.login" => {
username => "cjohnson", password => "tier3"
});
my $rpc = decode_xmlrpc($xml);
DESCRIPTION
XMLRPC::Fast
, as its name suggests, tries to be a fast XML-RPC encoder & decoder. Contrary to most other XML-RPC modules on the CPAN, it doesn't offer a RPC-oriented framework, and instead behaves more like a serialization module with a purely functional interface. The other main difference is that, contrary to other XML-RPC modules, which all use regexps to detect scalar types, XMLRPC::Fast uses Perl's internal flags. See "MAPPING" for more details. This choice was made because there are many kinds of data which can defeat the regexps, and a string can be confused with an integer. This module should DWIM most of the time, but it might not correspond to your own use cases.
RATIONALE
This module was born because in my current $work, we heavily use XML-RPC messages over a pure TCP socket, not over HTTP like most modules assume. As such, the RPC framework provided by the other modules is of no use, and we simply use their serialization methods (which are not always well documented). The module we use the most (because yes, we use more than one; don't ask) is XMLRPC::Lite, and basically only in one of these ways:
encoding a XML-RPC message:
my $xml = XMLRPC::Serializer->envelope($type, @message);
decoding a XML-RPC message:
my $rpc = XMLRPC::Deserializer->deserialize($xml)->root
XMLRPC::Fast
API was therefore made to follow these use cases, all the while being faster.
MAPPING
This section describes how XMLRPC::Fast
maps types between Perl and XML-RPC. It tries to do the right thing, but probably fails in some corner cases.
XML-RPC to Perl
array
A XML-RPC array
becomes a Perl array reference.
base64
A XML-RPC base64
is decoded with MIME::Base64 and provided as a Perl string value.
boolean
A XML-RPC boolean
becomes a Perl integer value (IV). Note that the value is coerced to become an integer, which can lead to surprises if the value was incorrectly typed.
date/time
A XML-RPC dateTime.iso8601
becomes a Perl string value
double
A XML-RPC double
becomes a Perl float value (NV). Note that the value is coerced to become a float, which can lead to surprises if the value was incorrectly typed.
integer
A XML-RPC integer
becomes a Perl integer value (IV). Note that the value is coerced to become an integer, which can lead to surprises if the value was incorrectly typed.
nil
A XML-RPC nil
becomes the undefined value (undef
).
string
A XML-RPC string
becomes a Perl string value (PV). The string is not decoded, and is therefore provided as octets.
struct
A XML-RPC struct
becomes a Perl array reference.
Perl to XML-RPC
scalar
There is unfortunately no way in Perl to know the type of a scalar value as we humans expect it. Perl has its own set of internal types, not exposed at language level, and some can overlap with others. The following heuristic(*) is applied, in this order:
if the scalar is
undef
, it is converted to a XML-RPCnil
;if the scalar has the
SVf_NOK
flag (NV, PVNV), it is assumed to be a float value, and converted to a XML-RPCdouble
;if the scalar has the
SVf_IOK
flag (IV, PVIV), it is assumed to be an integer, and converted to a XML-RPCint
;otherwise, the scalar is assumed to be a string (PV); if it a string of Perl characters, it is first encoded to UTF-8 (this may change in the future if it appears to create more problems than it tries to solve); if control characters are detected, the value is encoded to Base64 and sent as a XML-RPC
base64
; otherwise, XML specific characters (&
,<
,>
) are protected and the value is sent as a XML-RPCstring
.
(*) To quote Mark Jason Dominus, "this is a fancy way of saying that it doesn't work," yet my guess (and experience) is that this one is less buggy at guessing types than regexps. Obviously, your mileage may vary.
array reference
Array references are converted to XML-RPC array
structures.
hash reference
Hash references are converted to XML-RPC struct
structures.
object
DateTime and DateTime::Tiny objects are mapped to dateTime.iso8601
values, and formatted accordingly. Other types of objects are ignored.
EXPORTS
XMLRPC::Fast
by default exports all its public functions: decode_xmlrpc
, encode_xmlrpc
, encode_xmlrpc_request
, encode_xmlrpc_response
, encode_xmlrpc_fault
.
FUNCTIONS
decode_xmlrpc
Parse a XML-RPC message and return a structure representing the message.
Argument: XML octets
Return: structure
Examples:
# parsing a request message
my $xml = <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>fluttergency.set_level</methodName>
<params>
<param>
<value>
<struct>
<member><name>level</name><value><int>3</int></value></member>
</struct>
</value>
</param>
</params>
</methodCall>
XML
my $rpc = decode_xmlrpc($xml);
# $rpc = {
# type => "request",
# methodName => "fluttergency.set_level",
# params => [{ level => 3 }],
# }
# parsing a response message
my $xml = <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>angel.alert</name>
<value> <string>missing Fluttershy</string> </value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>
XML
my $rpc = decode_xmlrpc($xml);
# $rpc = {
# type => "response",
# params => [{ "angel.alert" => "missing Fluttershy" }],
# }
# parsing a fault message
my $xml = <<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value> <int>20</int> </value>
</member>
<member>
<name>faultString</name>
<value> <string>needs to be 20% cooler</string> </value>
</member>
</struct>
</value>
</fault>
</methodResponse>
XML
my $rpc = decode_xmlrpc($xml);
# $rpc = {
# type => "fault",
# fault => {
# faultCode => 20, faultString => "it needs to be 20% cooler"
# },
# }
encode_xmlrpc
Create a XML-RPC method message and return the corresponding XML document. Type is "method"
for a request message, "response"
for a normal response message, "fault"
for a fault response message. Method name is only used for request messages.
Arguments: type of message, method name, parameters
Return: XML octets
Examples:
# create a request message
my $xml = encode_xmlrpc(request =>
"fluttergency.set_level", { level => 3 });
# create a normal response message
my $xml = encode_xmlrpc(response => "",
{"angel.alert" => "missing Fluttershy"});
# create a fault response message
my $xml = encode_xmlrpc(fault => 20, "it needs to be 20% cooler");
encode_xmlrpc_request
Create a XML-RPC method request message and return the corresponding XML document. Calls encode_xmlrpc()
with the type "method"
and the rest of the arguments.
Arguments: method name, parameters
Return: XML octets
Example:
my $xml = encode_xmlrpc_request("fluttergency.set_level", { level => 3 });
# <?xml version="1.0" encoding="UTF-8"?>
# <methodCall>
# <methodName>fluttergency.set_level</methodName>
# <params>
# <param>
# <value>
# <struct>
# <member>
# <name>level</name>
# <value> <int>3</int> </value>
# </member>
# </struct>
# </value>
# </param>
# </params>
# </methodCall>
encode_xmlrpc_response
Create a XML-RPC method response message and return the corresponding XML document. Calls encode_xmlrpc()
with the type "response"
and the rest of the arguments.
Arguments: parameters
Return: XML octets
Example:
my $xml = encode_xmlrpc_response({"angel.alert" => "missing Fluttershy"});
# <?xml version="1.0" encoding="UTF-8"?>
# <methodResponse>
# <params>
# <param>
# <value>
# <struct>
# <member>
# <name>angel.alert</name>
# <value> <string>missing Fluttershy</string> </value>
# </member>
# </struct>
# </value>
# </param>
# </params>
# </methodResponse>
encode_xmlrpc_fault
Create a XML-RPC method fault message and return the corresponding XML document. Calls encode_xmlrpc()
with the type "response"
and the appropriate structure filled with the given arguments.
Arguments: fault code, fault string
Return: XML octets
Example:
my $xml = encode_xmlrpc_fault(20, "it needs to be 20% cooler");
# <?xml version="1.0" encoding="UTF-8"?>
# <methodResponse>
# <fault>
# <value>
# <struct>
# <member>
# <name>faultCode</name>
# <value> <int>20</int> </value>
# </member>
# <member>
# <name>faultString</name>
# <value> <string>needs to be 20% cooler</string> </value>
# </member>
# </struct>
# </value>
# </fault>
# </methodResponse>
SIMILAR MODULES
This section describes the author's impressions about the other XML-RPC modules available on the CPAN. You can find scripts to runs bench tests, with both Benchmark and Dumbbench, in the tools/ directory of the distribution.
Frontier::RPC2 -- As I understand it, the grandparent of all XML-RPC modules on the CPAN, made by the people who proposed the XML-RPC spec in the first place, back in 1998. Very old (last release in 2002 or 2004). Documented. Very fast; actually the fastest XML-RPC module on the CPAN until
XMLRPC::Fast
, and still is for decoding.Encoding is very fast, but relies on regexps to detect scalar types.
my $xml = Frontier::RPC2->new->encode_call(@message);
Decoding is very fast, based on XML::Parser, but returns a structure with objects, making it less practical than a pure Perl structure.
my $rpc = Frontier::RPC2->new->decode($xml);
RPC::XML -- Developped since a long time (2001-today). Very well documented.
Encoding is pretty fast, but relies on regexps to detect scalar types.
my $xml = RPC::XML::request->new(@message)->as_string;
Decoding is pretty fast, using either XML::Parser or XML::LibXML.
my $rpc = RPC::XML::ParserFactory->new->parse($xml);
XML::Compile::RPC -- Recent (2009-2013). Heavily object oriented, complex to use. Strangely documented. Completely RPC/HTTP oriented, client-side only, can't be used for generic encoding/decoding.
Encoding is slow, and a bit tedious given the complex structure you need to give it in order to specify everything.
XML::RPC -- Old (2008), basic documentation. Does not handle the
base64
type.Encoding is slow and relies on regexps to detect scalar types
my $xml = XML::RPC->new("")->create_call_xml(@message);
Decoding uses XML::TreePP, and is therefore very slow.
my $client = XML::RPC->new(""); my ($method, @params) = $client->unparse_call($client->{tpp}->parse($xml));
XMLRPC::Lite -- Barely documented, based on SOAP::Lite, therefore very object oriented and more than a bit heavy. On the positive side, this allows you to override how the values are guessed.
Encoding is slow and relies on regexps to detect scalar types.
my $xml = XMLRPC::Serializer->envelope(method => @message);
Decoding is quite slow.
my $rpc = XMLRPC::Deserializer->deserialize($xml)->root;
If XMLRPC::Fast
doesn't fit your needs, RPC::XML is probably your best bet.
CREDITS
The XML-RPC standard is Copyright 1998-2004 UserLand Software, Inc. See http://www.xmlrpc.com/ for more information about the XML-RPC specification.
AUTHOR
Sébastien Aperghis-Tramoni <saper@cpan.org>