File Coverage

blib/lib/UltraDNS/Parser.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package UltraDNS::Parser;
2              
3 6     6   38 use strict;
  6         16  
  6         260  
4 6     6   34 use warnings;
  6         11  
  6         270  
5 6     6   158 use 5.00800;
  6         20  
  6         377  
6              
7             our $VERSION = '0.04';
8              
9 6     6   35 use base qw/Exporter/;
  6         16  
  6         743  
10 6     6   7788 use RPC::XML;
  0            
  0            
11             use XML::LibXML;
12             use MIME::Base64;
13             use Carp;
14              
15             use UltraDNS::Type;
16              
17              
18             my $udns_types = UltraDNS::Type->_type_to_class_map();
19              
20             our $TYPE_MAP = {
21             int => 'RPC::XML::int',
22             i4 => 'RPC::XML::int',
23             boolean => 'RPC::XML::boolean',
24             string => 'RPC::XML::string',
25             double => 'RPC::XML::double',
26             'dateTime.iso8601' => 'RPC::XML::datetime_iso8601',
27             array => 'RPC::XML::array',
28             struct => 'RPC::XML::struct',
29             %$udns_types,
30             };
31              
32             my $value_xpath = join "|", map "./$_",
33             keys %$TYPE_MAP,
34             qw(base64 struct array);
35              
36             sub _parse_rpc_xml {
37             my $self = shift;
38             my $xml = shift;
39              
40             my $x = XML::LibXML->new;
41             my $doc = $x->parse_string($xml)->documentElement;
42             my @nodes;
43              
44             # the common case first
45             if (@nodes = $doc->findnodes('/methodResponse/params/param/value')) {
46             return RPC::XML::response->new(_extract_values(@nodes));
47             }
48             # sometimes doesn't contain a ,
49             elsif (@nodes = $doc->findnodes('/methodResponse/params/param')) {
50             # so long as we find a we're happy to return an undef
51             # XXX RPC::XML doesn't really understand undefs, but this'll do:
52             return RPC::XML::response->new(RPC::XML::simple_type->new(undef));
53             # else fall thru and croak
54             }
55             elsif ($doc->findnodes('/methodResponse/fault')) {
56             return RPC::XML::response->new(
57             RPC::XML::fault->new(
58             $doc->findvalue('/methodResponse/fault/value/struct/member/value/int'),
59             $doc->findvalue('/methodResponse/fault/value/struct/member/value/string'),
60             ),
61             );
62             }
63             croak "Invalid methodResponse: $xml";
64             }
65              
66              
67             sub _extract_values {
68             my @value_nodes = @_;
69              
70             my @values;
71             for my $node (grep defined, @value_nodes) {
72             my($v_node) = $node->findnodes($value_xpath);
73             my $value;
74             if (defined $v_node) {
75             $value = _extract($v_node);
76             } else {
77             # foo is treated as by default
78             $value = RPC::XML::string->new($node->textContent);
79             }
80              
81             push @values, $value;
82             }
83              
84             return @values;
85             }
86              
87             sub _extract {
88             my $node = shift;
89              
90             return unless defined $node;
91              
92             my $nodename = $node->nodeName;
93             my $val = $node->textContent;
94             if ($nodename eq 'base64') {
95             return RPC::XML::base64->new(decode_base64($val));
96             } else {
97             my $class = $TYPE_MAP->{ $nodename }
98             or return;
99             if ($class->isa('RPC::XML::struct')) {
100             my @members = $node->findnodes('./member'); # XXX
101             my $result = {};
102             for my $member (@members) {
103             my($name) = $member->findnodes('./name');
104             my($value) = _extract_values($member->findnodes('./value') );
105             ($result->{$name->textContent}, ) = $value;
106             }
107             return $class->new($result);
108             }
109             elsif ($class->isa('RPC::XML::array')) {
110             return $class->new(_extract_values($node->findnodes($node->nodePath . '/data/value')));
111             }
112             else {
113             return $class->new($val);
114             }
115             }
116             }
117              
118             1;
119             __END__