line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RPC::XML::Parser::LibXML; |
2
|
2
|
|
|
2
|
|
46104
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
72
|
|
3
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
49
|
|
4
|
2
|
|
|
2
|
|
45
|
use 5.00800; |
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
131
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.08'; |
6
|
2
|
|
|
2
|
|
22
|
use base qw/Exporter/; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
203
|
|
7
|
2
|
|
|
2
|
|
917
|
use RPC::XML; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
my $value_xpath = join "|", map "./$_", qw( int i4 boolean string double dateTime.iso8601 base64 struct array ); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub parse_rpc_xml { |
26
|
|
|
|
|
|
|
my $xml = shift; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $x = XML::LibXML->new({ |
29
|
|
|
|
|
|
|
no_network => 1, |
30
|
|
|
|
|
|
|
expand_xinclude => 0, |
31
|
|
|
|
|
|
|
expand_entities => 1, |
32
|
|
|
|
|
|
|
load_ext_dtd => 0, |
33
|
|
|
|
|
|
|
ext_ent_handler => sub { warn "External entities disabled."; '' }, |
34
|
|
|
|
|
|
|
}); |
35
|
|
|
|
|
|
|
my $doc = $x->parse_string($xml)->documentElement; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
if ($doc->findnodes('/methodCall')) { |
38
|
|
|
|
|
|
|
return RPC::XML::request->new( |
39
|
|
|
|
|
|
|
$doc->findvalue('/methodCall/methodName'), |
40
|
|
|
|
|
|
|
_extract_values($doc->findnodes('//params/param/value')) |
41
|
|
|
|
|
|
|
); |
42
|
|
|
|
|
|
|
} elsif ($doc->findnodes('/methodResponse/params')) { |
43
|
|
|
|
|
|
|
return RPC::XML::response->new( |
44
|
|
|
|
|
|
|
_extract_values($doc->findnodes('//params/param/value')) |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
} elsif ($doc->findnodes('/methodResponse/fault')) { |
47
|
|
|
|
|
|
|
return RPC::XML::response->new( |
48
|
|
|
|
|
|
|
RPC::XML::fault->new( |
49
|
|
|
|
|
|
|
$doc->findvalue('/methodResponse/fault/value/struct/member/value/int'), |
50
|
|
|
|
|
|
|
$doc->findvalue('/methodResponse/fault/value/struct/member/value/string'), |
51
|
|
|
|
|
|
|
), |
52
|
|
|
|
|
|
|
); |
53
|
|
|
|
|
|
|
} else { |
54
|
|
|
|
|
|
|
Carp::croak("invalid xml: $xml"); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub _extract_values { |
60
|
|
|
|
|
|
|
my @value_nodes = @_; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my @values; |
63
|
|
|
|
|
|
|
for my $node (grep defined, @value_nodes) { |
64
|
|
|
|
|
|
|
my($v_node) = $node->findnodes($value_xpath); |
65
|
|
|
|
|
|
|
my $value; |
66
|
|
|
|
|
|
|
if (defined $v_node) { |
67
|
|
|
|
|
|
|
$value = _extract($v_node); |
68
|
|
|
|
|
|
|
} else { |
69
|
|
|
|
|
|
|
# foo is treated as by default |
70
|
|
|
|
|
|
|
$value = RPC::XML::string->new($node->textContent); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
push @values, $value; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
return @values; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub _extract { |
80
|
|
|
|
|
|
|
my $node = shift; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
return unless defined $node; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
my $nodename = $node->nodeName; |
85
|
|
|
|
|
|
|
my $val = $node->textContent; |
86
|
|
|
|
|
|
|
if ($nodename eq 'base64') { |
87
|
|
|
|
|
|
|
return RPC::XML::base64->new(MIME::Base64::decode_base64($val)); |
88
|
|
|
|
|
|
|
} elsif ($nodename eq 'struct') { |
89
|
|
|
|
|
|
|
my @members = $node->findnodes('./member'); # XXX |
90
|
|
|
|
|
|
|
my $result = {}; |
91
|
|
|
|
|
|
|
for my $member (@members) { |
92
|
|
|
|
|
|
|
my($name) = $member->findnodes('./name'); |
93
|
|
|
|
|
|
|
my($value) = _extract_values ($member->findnodes('./value') ); |
94
|
|
|
|
|
|
|
($result->{$name->textContent}, ) = $value; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
return RPC::XML::struct->new($result); |
97
|
|
|
|
|
|
|
} elsif ($nodename eq 'array') { |
98
|
|
|
|
|
|
|
return RPC::XML::array->new(_extract_values($node->findnodes($node->nodePath . '/data/value'))); |
99
|
|
|
|
|
|
|
} else { |
100
|
|
|
|
|
|
|
my $class = $TYPE_MAP->{ $nodename } or return; |
101
|
|
|
|
|
|
|
return $class->new($val); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
1; |
106
|
|
|
|
|
|
|
__END__ |