File Coverage

blib/lib/SOAP/Data/Builder.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package SOAP::Data::Builder;
2 1     1   24080 use strict;
  1         2  
  1         51  
3              
4             =head1 NAME
5              
6             SOAP::Data::Builder - A wrapper simplifying SOAP::Data and SOAP::Serialiser
7              
8             =head1 DESCRIPTION
9              
10             This Module provides a quick and easy way to build complex SOAP data
11             and header structures for use with SOAP::Lite.
12              
13             It primarily provides a wrapper around SOAP::Serializer and SOAP::Data
14             (or SOAP::Header) enabling you to generate complex XML within your SOAP
15             request or response.
16              
17             =head1 VERSION
18              
19             1.0
20              
21             =head1 SYNOPSIS
22              
23             use SOAP::Lite ( +trace => 'all', maptype => {} );
24              
25             use SOAP::Data::Builder;
26              
27             # create new Builder object
28             my $soap_data_builder = SOAP::Data::Builder->new();
29              
30             #
31             $soap_data_builder->add_elem(name => 'eb:MessageHeader',
32             header=>1,
33             attributes => {"eb:version"=>"2.0", "SOAP::mustUnderstand"=>"1"});
34              
35             #
36             # uri:example.com
37             # http://rosettanet.org/roles/Buyer
38             #
39             my $from = $soap_data_builder->add_elem(name=>'eb:From',
40             parent=>$soap_data_builder->get_elem('eb:MessageHeader'));
41              
42             $soap_data_builder->add_elem(name=>'eb:PartyId',
43             parent=>$from,
44             value=>'uri:example.com');
45              
46             $from->add_elem(name=>'eb:Role', value=>'http://path.to/roles/foo');
47              
48             #
49             $soap_data_builder->add_elem(name=>'eb:DuplicateElimination', parent=>$soap_data_builder->get_elem('eb:MessageHeader'));
50              
51              
52             # fetch Data
53             my $data = SOAP::Data->name('SOAP:ENV' =>
54             \SOAP::Data->value( $soap_data_builder->to_soap_data )
55             );
56              
57             # serialise Data using SOAP::Serializer
58             my $serialized_xml = SOAP::Serializer->autotype(0)->serialize( $data );
59              
60             # serialise Data using wrapper
61             my $wrapper_serialised_xml = $soap_data_builder->serialise();
62              
63             # make SOAP request with data
64              
65             my $foo = SOAP::Lite
66             -> uri('http://www.liverez.com/SoapDemo')
67             -> proxy('http://www.liverez.com/soap.pl')
68             -> getTest( $soap_data_builder->to_soap_data )
69             -> result;
70              
71             =cut
72              
73 1     1   524 use SOAP::Data::Builder::Element;
  1         2  
  1         31  
74 1     1   426 use SOAP::Lite ( maptype => {} );
  0            
  0            
75             use Carp qw(carp cluck croak confess);
76             use Data::Dumper;
77              
78             our $VERSION = 1.0;
79              
80             =head1 METHODS
81              
82             =head2 new(autotype=>0)
83              
84             Constructor method for this class, it instantiates and returns the Builder object,
85             taking named options as parameters
86              
87             my $builder = SOAP::Data::Builder->new( autotype=>0 ); # new object with no autotyping
88              
89             supported options are :
90              
91             * autotype which switches on/off SOAP::Serializers autotype setting
92              
93             * readable which switches on/off SOAP::Serialixer readable setting
94              
95             =cut
96              
97             sub new {
98             my ($class,%args) = @_;
99              
100             my $self = { elements => [], };
101             bless ($self,ref $class || $class);
102             foreach my $key (keys %args) {
103             $self->{options}{$key} = $args{$key};
104             }
105              
106             return $self;
107             }
108              
109             =head2 serialise()
110              
111             Wrapper for SOAP::Serializer (sic), serialises the contents of the Builder object
112             and returns the XML as a string
113              
114             # serialise Data using wrapper
115             my $wrapper_serialised_xml = $soap_data_builder->serialise();
116              
117             This method does not accept any arguments
118              
119             NOTE: serialise is spelt properly using the King's English
120              
121             =cut
122              
123             sub serialise {
124             my $self = shift;
125             my $data = SOAP::Data->name('SOAP:ENV' =>
126             \SOAP::Data->value( $self->to_soap_data )
127             );
128             my $serialized = SOAP::Serializer->autotype($self->autotype)->readable($self->readable)->serialize( $data );
129             }
130              
131             =head2 autotype()
132              
133             returns whether the object currently uses autotype when serialising
134              
135             =cut
136              
137             sub autotype {
138             return shift->{options}{autotype} || 0;
139             }
140              
141             =head2 readable()
142              
143             returns whether the object currently uses readable when serialising
144              
145             =cut
146              
147             sub readable {
148             return shift->{options}{readable} || 0;
149             }
150              
151             =head2 to_soap_data()
152              
153             returns the contents of the object as a list of SOAP::Data and/or SOAP::Header objects
154              
155             NOTE: make sure you call this in array context!
156              
157             =cut
158              
159             sub to_soap_data {
160             my $self = shift;
161             my @data = ();
162             foreach my $elem ( $self->elems ) {
163             push(@data,$self->get_as_data($elem,1));
164             }
165             return @data;
166             }
167              
168             sub elems {
169             my $self = shift;
170             my @elems = @{$self->{elements}};
171             return @elems;
172             }
173              
174             =head1 add_elem
175              
176             This method adds an element to the structure, either to the root list
177             or a specified element.
178              
179             optional parameters are : parent, value, attributes, header, isMethod
180              
181             parent should be an element 'add_elem(parent=>$parent_element, .. );'
182              
183             or the full name of an element 'add_elem(parent=>'name/of/parent', .. );'
184              
185             value should be a string,
186              
187             attributes should be a hashref : { 'ns:foo'=> bar, .. }
188              
189             header should be 1 or 0 specifying whether the element should be built using SOAP::Data or SOAP::Header
190              
191             returns the added element
192              
193             my $bar_elem = $builder->add_elem(name=>'bar', value=>$foo->{bar}, parent=>$foo);
194              
195             would produce SOAP::Data representing an XML fragment like '..'
196              
197             =cut
198              
199             sub add_elem {
200             my ($self,%args) = @_;
201             my $elem = SOAP::Data::Builder::Element->new(%args);
202             if ( $args{parent} ) {
203             my $parent = $args{parent};
204             unless (ref $parent eq 'SOAP::Data::Builder::Element') {
205             $parent = $self->get_elem($args{parent});
206             }
207             $parent->add_elem($elem);
208             } else {
209             push(@{$self->{elements}},$elem);
210             }
211             return $elem;
212             }
213              
214             =head2 get_elem('ns:elementName')
215              
216             returns an element (which is an internal data structure rather than an object)
217              
218             returns the first element with the name passed as an argument,
219             sub elements can be referred to as 'grandparent/parent/element'
220              
221             This structure is passed to other object methods and may change in behaviour,
222             type or structure without warning as the class is developed
223              
224             =cut
225              
226             sub get_elem {
227             my ($self,$name) = (@_,'');
228             my ($a,$b);
229             my @keys = split (/\//,$name);
230             foreach my $elem ( $self->elems) {
231             if ($elem->name eq $keys[0]) {
232             $a = $elem;
233             $b = shift(@keys);
234             last;
235             }
236             }
237              
238             my $elem = $a;
239             $b = shift(@keys);
240             if ($b) {
241             $elem = $self->find_elem($elem,$b,@keys);
242             }
243              
244             return $elem;
245             }
246              
247             # internal method
248              
249             sub find_elem {
250             my ($self,$parent,$key,@keys) = @_;
251              
252             croak 'parent not defined' unless $parent;
253              
254             my ($a,$b);
255             foreach my $elem ( $parent->get_children()) {
256             next unless ref $elem;
257             if ($elem->{name} eq $key) {
258             $a = $elem;
259             $b = $key;
260             last;
261             }
262             }
263              
264             my $elem = $a;
265             undef($b);
266             while ($b = shift(@keys) ) {
267             $elem = $self->find_elem($elem,$b,@keys);
268             }
269             return $elem;
270             }
271              
272              
273             # internal method
274              
275             sub get_as_data {
276             my ($self,$elem) = @_;
277             my @values;
278             foreach my $value ( @{$elem->value} ) {
279             next unless ($value);
280             if (ref $value) {
281             push(@values,$self->get_as_data($value))
282             } else {
283             push(@values,$value);
284             }
285             }
286             my @data = ();
287              
288             if (ref $values[0]) {
289             $data[0] = \SOAP::Data->value( @values );
290             } else {
291             @data = @values;
292             }
293             if ($elem->{header}) {
294             $data[0] = SOAP::Header->name($elem->{name} => $data[0])->attr($elem->attributes());
295             } else {
296             if ($elem->{isMethod}) {
297             @data = ( SOAP::Data->name($elem->{name} )->attr($elem->attributes()) => SOAP::Data->value( @values ) );
298             } elsif ($elem->{type}) {
299             $data[0] = SOAP::Data->name($elem->{name} => $data[0])->attr($elem->attributes())->type($elem->{type});
300             } else {
301             $data[0] = SOAP::Data->name($elem->{name} => $data[0])->attr($elem->attributes());
302             }
303             }
304             return @data;
305             }
306              
307             =head2 EXPORT
308              
309             None.
310              
311             =head1 SEE ALSO
312              
313             L
314              
315             L
316              
317             =head1 AUTHOR
318              
319             Aaron Trevena, Eteejay@droogs.orgE
320              
321             =head1 COPYRIGHT AND LICENSE
322              
323             Copyright (C) 2004,2005 by Aaron Trevena
324              
325             This library is free software; you can redistribute it and/or modify
326             it under the same terms as Perl itself,
327              
328             =cut
329              
330              
331             #############################################################################
332             #############################################################################
333              
334             1;