package XMLRPC::Fast::DecodeWith::XMLLibXML;
use strict;
use warnings;
use MIME::Base64;
use XML::LibXML;
#
# decode_xmlrpc()
# -------------
sub decode_xmlrpc {
my ($xml) = shift;
# parse the XML document
my $parser = XML::LibXML->new(
no_network => 1,
expand_xinclude => 0,
expand_entities => 1,
load_ext_dtd => 0,
no_blanks => 1
);
my $doc = $parser->parse_string($xml);
my $root = $doc->documentElement;
my %struct;
# detect the message type
if ($root->nodeName eq "methodCall") {
$struct{type} = "request";
$struct{methodName}
= ($root->getChildrenByTagName("methodName"))[0]->textContent;
}
elsif ($root->nodeName eq "methodResponse") {
$struct{type} = "response";
my $fault = ($root->getChildrenByTagName("fault"))[0];
if ($fault) {
$struct{type} = "fault";
$struct{fault} = decode_value($fault->firstChild);
}
}
else {
die "unknown type of message";
}
# handle parameters
my $params = ($root->getChildrenByTagName("params"))[0];
if ($params) {
$struct{params} = [
map decode_value($_->firstChild),
$params->getChildrenByTagName("param")
];
}
return \%struct
}
#
# decode_value()
# ------------
sub decode_value {
my ($value) = shift;
my $v = $value->firstChild or return undef;
my $type = $v->nodeName;
if ($type eq "array") {
return [
map { decode_value($_->getChildrenByTagName("value")) }
$v->getChildrenByTagName("data")
]
}
elsif ($type eq "struct") {
return {
map { ($_->getChildrenByTagName("name"))[0]->textContent,
decode_value($_->getChildrenByTagName("value")) }
$v->getChildrenByTagName("member")
}
}
elsif ($type eq "int" or $type eq "i4" or $type eq "boolean") {
return int $v->textContent
}
elsif ($type eq "double") {
return $v->textContent / 1.0
}
elsif ($type eq "base64") {
return decode_base64($v->textContent)
}
else { # string, datetime
return $v->textContent
}
}
__PACKAGE__
__END__
=head1 NAME
XMLRPC::Fast::DecodeWith::XMLLibXML - XML-RPC decoder based on XML::LibXML
=head1 DESCRIPTION
This is an alternate decoding function for L<XMLRPC::Fast>, using L<XML::LibXML>
as the XML engine. Based on L<RPC::XML::Parser::XMLLibXML>, heavily simplified.
Performs pretty well, but a bit less than L<XML::Parser>.
=head1 AUTHOR
SE<eacute>bastien Aperghis-Tramoni E<lt>[email protected]<gt>