| 1 | package RPC::XML::Parser::LibXML; |
|---|
| 2 | use strict; |
|---|
| 3 | use warnings; |
|---|
| 4 | use 5.00800; |
|---|
| 5 | our $VERSION = '0.02'; |
|---|
| 6 | use base qw/Exporter/; |
|---|
| 7 | use RPC::XML; |
|---|
| 8 | use XML::LibXML; |
|---|
| 9 | use MIME::Base64; |
|---|
| 10 | use Carp; |
|---|
| 11 | |
|---|
| 12 | our @EXPORT = qw/parse_rpc_xml/; |
|---|
| 13 | |
|---|
| 14 | our $TYPE_MAP = +{ |
|---|
| 15 | int => 'RPC::XML::int', |
|---|
| 16 | i4 => 'RPC::XML::int', |
|---|
| 17 | boolean => 'RPC::XML::boolean', |
|---|
| 18 | string => 'RPC::XML::string', |
|---|
| 19 | double => 'RPC::XML::double', |
|---|
| 20 | 'dateTime.iso8601' => 'RPC::XML::datetime_iso8601', |
|---|
| 21 | }; |
|---|
| 22 | |
|---|
| 23 | sub parse_rpc_xml { |
|---|
| 24 | my $xml = shift; |
|---|
| 25 | |
|---|
| 26 | my $x = XML::LibXML->new; |
|---|
| 27 | my $doc = $x->parse_string($xml)->documentElement; |
|---|
| 28 | |
|---|
| 29 | if ($doc->findnodes('/methodCall')) { |
|---|
| 30 | return RPC::XML::request->new( |
|---|
| 31 | $doc->findvalue('/methodCall/methodName'), |
|---|
| 32 | _extract($doc->findnodes('//params/param/value/*')) |
|---|
| 33 | ); |
|---|
| 34 | } elsif ($doc->findnodes('/methodResponse/params')) { |
|---|
| 35 | return RPC::XML::response->new( |
|---|
| 36 | _extract($doc->findnodes('//params/param/value/*')) |
|---|
| 37 | ); |
|---|
| 38 | } elsif ($doc->findnodes('/methodResponse/fault')) { |
|---|
| 39 | return RPC::XML::response->new( |
|---|
| 40 | RPC::XML::fault->new( |
|---|
| 41 | $doc->findvalue('/methodResponse/fault/value/struct/member/value/int'), |
|---|
| 42 | $doc->findvalue('/methodResponse/fault/value/struct/member/value/string'), |
|---|
| 43 | ), |
|---|
| 44 | ); |
|---|
| 45 | } else { |
|---|
| 46 | croak "invalid xml: $xml"; |
|---|
| 47 | } |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | sub _extract { |
|---|
| 51 | my @nodes = @_; |
|---|
| 52 | |
|---|
| 53 | my @args; |
|---|
| 54 | |
|---|
| 55 | for my $node (@nodes) { |
|---|
| 56 | my $nodename = $node->nodeName; |
|---|
| 57 | my $val = $node->textContent; |
|---|
| 58 | |
|---|
| 59 | if ($nodename eq 'base64') { |
|---|
| 60 | push @args, RPC::XML::base64->new(decode_base64($val)); |
|---|
| 61 | } elsif ($nodename eq 'struct') { |
|---|
| 62 | my @members = $node->findnodes('./member'); # XXX |
|---|
| 63 | my $result = {}; |
|---|
| 64 | for my $member (@members) { |
|---|
| 65 | my($name) = $member->findnodes('./name'); |
|---|
| 66 | my($value) = $member->findnodes('./value/*'); |
|---|
| 67 | ($result->{$name->textContent}, ) = _extract($value); |
|---|
| 68 | } |
|---|
| 69 | push @args, RPC::XML::struct->new($result); |
|---|
| 70 | } elsif ($nodename eq 'array') { |
|---|
| 71 | push @args, RPC::XML::array->new(_extract($node->findnodes($node->nodePath . '/data/value/*'))); |
|---|
| 72 | } else { |
|---|
| 73 | my $class = $TYPE_MAP->{ $nodename } or next; |
|---|
| 74 | push @args, $class->new($val); |
|---|
| 75 | } |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | return @args; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | 1; |
|---|
| 82 | __END__ |
|---|
| 83 | |
|---|
| 84 | =encoding utf8 |
|---|
| 85 | |
|---|
| 86 | =head1 NAME |
|---|
| 87 | |
|---|
| 88 | RPC::XML::Parser::LibXML - Fast XML-RPC parser with libxml |
|---|
| 89 | |
|---|
| 90 | =head1 SYNOPSIS |
|---|
| 91 | |
|---|
| 92 | use RPC::XML::Parser::LibXML; |
|---|
| 93 | |
|---|
| 94 | my $req = parse_rpc_xml(qq{ |
|---|
| 95 | <methodCall> |
|---|
| 96 | <methodName>foo.bar</methodName> |
|---|
| 97 | <params> |
|---|
| 98 | <param><value><string>Hello, world!</string></value></param> |
|---|
| 99 | </params> |
|---|
| 100 | </methodCall> |
|---|
| 101 | }); |
|---|
| 102 | # $req is a RPC::XML::request |
|---|
| 103 | |
|---|
| 104 | =head1 DESCRIPTION |
|---|
| 105 | |
|---|
| 106 | RPC::XML::Parser::LibXML is fast XML-RPC parser written with XML::LibXML. |
|---|
| 107 | |
|---|
| 108 | =head1 AUTHOR |
|---|
| 109 | |
|---|
| 110 | Tokuhiro Matsuno E<lt>tokuhirom AAJKLFJEF GMAIL COME<gt> |
|---|
| 111 | |
|---|
| 112 | Tatsuhiko Miyagawa |
|---|
| 113 | |
|---|
| 114 | =head1 SEE ALSO |
|---|
| 115 | |
|---|
| 116 | L<RPC::XML::Parser>, L<RPC::XML::Parser::XS>, L<XML::LibXML> |
|---|
| 117 | |
|---|
| 118 | =head1 LICENSE |
|---|
| 119 | |
|---|
| 120 | This library is free software; you can redistribute it and/or modify |
|---|
| 121 | it under the same terms as Perl itself. |
|---|
| 122 | |
|---|
| 123 | =cut |
|---|