123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- package XML::RPC;
- use strict;
- use XML::TreePP;
- use Data::Dumper;
- use vars qw($VERSION $faultCode);
- no strict 'refs';
- $VERSION = 0.5;
- sub new {
- my $package = shift;
- my $self = { };
- bless $self, $package;
- $self->{url} = shift;
- $self->{tpp} = XML::TreePP->new(@_);
- return $self;
- }
- sub call {
- my $self = shift;
- my ( $methodname, @params ) = @_;
- die 'no url' if ( !$self->{url} );
- $faultCode = 0;
- my $xml = $self->create_call_xml( $methodname, @params );
- #print STDERR $xml;
- my $result = $self->{tpp}->parsehttp(
- POST => $self->{url},
- $xml,
- {
- 'Content-Type' => 'text/xml',
- 'User-Agent' => 'XML-RPC/' . $VERSION,
- 'Content-Length' => length($xml)
- }
- );
- my @data = $self->unparse_response($result);
- return @data == 1 ? $data[0] : @data;
- }
- sub receive {
- my $self = shift;
- my $result = eval {
- my $xml = shift || die 'no xml';
- my $handler = shift || die 'no handler';
- my $hash = $self->{tpp}->parse($xml);
- my ( $methodname, @params ) = $self->unparse_call($hash);
- $self->create_response_xml( $handler->( $methodname, @params ) );
- };
- return $self->create_fault_xml($@) if ($@);
- return $result;
- }
- sub create_fault_xml {
- my $self = shift;
- my $error = shift;
- chomp($error);
- return $self->{tpp}
- ->write( { methodResponse => { fault => $self->parse( { faultString => $error, faultCode => $faultCode } ) } } );
- }
- sub create_call_xml {
- my $self = shift;
- my ( $methodname, @params ) = @_;
- return $self->{tpp}->write(
- {
- methodCall => {
- methodName => $methodname,
- params => { param => [ map { $self->parse($_) } @params ] }
- }
- }
- );
- }
- sub create_response_xml {
- my $self = shift;
- my @params = @_;
- return $self->{tpp}->write( { methodResponse => { params => { param => [ map { $self->parse($_) } @params ] } } } );
- }
- sub parse {
- my $self = shift;
- my $p = shift;
- my $result;
- if ( ref($p) eq 'HASH' ) {
- $result = $self->parse_struct($p);
- }
- elsif ( ref($p) eq 'ARRAY' ) {
- $result = $self->parse_array($p);
- }
- else {
- $result = $self->parse_scalar($p);
- }
- return { value => $result };
- }
- sub parse_scalar {
- my $self = shift;
- my $scalar = shift;
- local $^W = undef;
- if ( ( $scalar =~ m/^[\-+]?\d+$/ )
- && ( abs($scalar) <= ( 0xffffffff >> 1 ) ) )
- {
- return { i4 => $scalar };
- }
- elsif ( $scalar =~ m/^[\-+]?\d+\.\d+$/ ) {
- return { double => $scalar };
- }
- else {
- return { string => \$scalar };
- }
- }
- sub parse_struct {
- my $self = shift;
- my $hash = shift;
- my @members;
- while ( my ( $k, $v ) = each(%$hash) ) {
- push @members, { name => $k, %{ $self->parse($v) } };
- }
- return { struct => { member => \@members } };
- }
- sub parse_array {
- my $self = shift;
- my $array = shift;
- return { array => { data => { value => [ map { $self->parse($_)->{value} } $self->list($array) ] } } };
- }
- sub unparse_response {
- my $self = shift;
- my $hash = shift;
- my $response = $hash->{methodResponse} || die 'no data';
- if ( $response->{fault} ) {
- return $self->unparse_value( $response->{fault}->{value} );
- }
- else {
- return map { $self->unparse_value( $_->{value} ) } $self->list( $response->{params}->{param} );
- }
- }
- sub unparse_call {
- my $self = shift;
- my $hash = shift;
- my $response = $hash->{methodCall} || die 'no data';
- my $methodname = $response->{methodName};
- my @args =
- map { $self->unparse_value( $_->{value} ) } $self->list( $response->{params}->{param} );
- return ( $methodname, @args );
- }
- sub unparse_value {
- my $self = shift;
- my $value = shift;
- my $result;
- return $value if ( ref($value) ne 'HASH' ); # for unspecified params
- if ( $value->{struct} ) {
- $result = $self->unparse_struct( $value->{struct} );
- return !%$result
- ? undef
- : $result; # fix for empty hashrefs from XML::TreePP
- }
- elsif ( $value->{array} ) {
- return $self->unparse_array( $value->{array} );
- }
- else {
- return $self->unparse_scalar($value);
- }
- }
- sub unparse_scalar {
- my $self = shift;
- my $scalar = shift;
- my ($result) = values(%$scalar);
- return ( ref($result) eq 'HASH' && !%$result )
- ? undef
- : $result; # fix for empty hashrefs from XML::TreePP
- }
- sub unparse_struct {
- my $self = shift;
- my $struct = shift;
- return { map { $_->{name} => $self->unparse_value( $_->{value} ) } $self->list( $struct->{member} ) };
- }
- sub unparse_array {
- my $self = shift;
- my $array = shift;
- my $data = $array->{data};
- return [ map { $self->unparse_value($_) } $self->list( $data->{value} ) ];
- }
- sub list {
- my $self = shift;
- my $param = shift;
- return () if ( !$param );
- return @$param if ( ref($param) eq 'ARRAY' );
- return ($param);
- }
- 1;
|