File Coverage

blib/lib/CGI/Form2XML.pm
Criterion Covered Total %
statement 64 106 60.3
branch 10 40 25.0
condition 7 29 24.1
subroutine 10 14 71.4
pod 8 8 100.0
total 99 197 50.2


line stmt bran cond sub pod time code
1             #******************************************************************************
2             #*
3             #* GELLYFISH SOFTWARE
4             #*
5             #*
6             #******************************************************************************
7             #*
8             #* PROGRAM : CGI::Form2XML
9             #*
10             #* AUTHOR : JNS
11             #*
12             #* DESCRIPTION : Render CGI form data as XML
13             #*
14             #*****************************************************************************
15             #*
16             #* $Log: Form2XML.pm,v $
17             #* Revision 1.3 2004/03/02 20:28:02 jonathan
18             #* Put back in CVS
19             #*
20             #* Revision 1.3 2002/07/28 10:10:11 gellyfish
21             #* * POD bugette (noticed in new CPAN search)
22             #*
23             #* Revision 1.2 2002/05/25 09:06:30 gellyfish
24             #* Release version
25             #*
26             #* Revision 1.1.1.1 2002/05/25 09:02:28 gellyfish
27             #* Added to repository
28             #*
29             #*
30             #*
31             #*****************************************************************************/
32              
33             package CGI::Form2XML;
34              
35             =head1 NAME
36              
37             CGI::Form2XML - Render CGI form input as XML
38              
39             =head1 SYNOPSIS
40              
41              
42             use CGI::Form2XML;
43              
44              
45             my $x = CGI::Form2XML->new();
46              
47             $x->ns_prefix("nfd");
48              
49             print $x->asXML();
50              
51              
52             =head1 DESCRIPTION
53              
54             This module provides a method of taking CGI form input and turning it into
55             XML for further processing by another application or storage. Unlike
56             modules such CGI::XML and CGI::XMLForm it produces XML to a fixed schema
57             whose structure is not influenced by the form input. If flexibility as to
58             the structure of the XML data is required you will probably want to consider
59             one of the other modules.
60              
61             The schema is included in the distribution of this module as "xmlform.xsd".
62              
63             The module inherits from the CGI module in order to get access to the CGI
64             parameters, so any of the methods of that module can be used.
65              
66             =head2 METHODS
67              
68             =over 4
69              
70             =cut
71              
72 1     1   1072 use strict;
  1         3  
  1         48  
73              
74 1     1   1745357 use CGI;
  1         17907  
  1         6  
75 1     1   1040 use POSIX qw(strftime);
  1         12854  
  1         9  
76              
77 1     1   4644 use vars qw(@ISA $VERSION);
  1         2  
  1         1542  
78              
79             @ISA = qw(
80             CGI
81             );
82              
83             $VERSION = '1.4';
84              
85             =item new
86              
87             The constructor for the class. Returns a blessed object of type CGI::Form2XML.
88             Any arguments provided will be passed to the constructor of CGI.
89              
90             =cut
91              
92             sub new
93             {
94 1     1 1 846 my ( $proto, @args) = @_;
95              
96 1   33     9 my $class = ref($proto) || $proto;
97              
98              
99 1         10 my $self = $class->SUPER::new(@args);
100              
101 1         4189 bless $self, $class;
102              
103              
104 1         4 return $self;
105             }
106              
107              
108             =item asXML
109              
110             Returns the XML document that represents this CGI request.
111             It takes a hashref of arguments whose keys are :
112              
113             =over 2
114              
115             =item ns_prefix
116              
117             The namespace prefix that should be used for this document. The default
118             is no namespace.
119              
120             =item ns_url
121              
122             The URL that describes this namespace - the default is
123             'http://schemas.gellyfish.com/FormData', there is currently nothing at this
124             URL.
125              
126             =item omit_info
127              
128             If this is set to a true value then the 'header' information will not be
129             emitted by asXML().
130              
131             =back
132              
133             =cut
134              
135             sub asXML
136             {
137 1     1 1 2 my ( $self, $args ) = @_;
138              
139 1         3 my $xml = '';
140 1         1 my $info = '';
141 1         3 my $items = '';
142              
143 1         2 my $indent = ' ' x 3;
144              
145 1         4 my @params = grep !/(?:destination|session_id|owner)/, $self->param();
146              
147 1         19 my ($referer, $handler, $time, $destination, $session_id, $owner);
148              
149 1   33     6 my $ns_prefix = $args->{ns_prefix} || $self->ns_prefix();
150 1   33     7 my $ns_url = $args->{ns_url} || $self->ns_url();
151              
152 1         2 my %info;
153              
154 1 50       5 my $pref = $ns_prefix ? "$ns_prefix:" : '' ;
155              
156 1 50 33     3 unless ( $self->omit_info() || $args->{omit_info} )
157             {
158 0         0 my %mandatory = (
159             referer => 1,
160             handler => 1,
161             timestamp => 1
162             );
163              
164 0   0     0 $info{referer} = $self->referer() || '';
165 0   0     0 $info{handler} = $self->script_name() || '';
166              
167 0         0 $info{timestamp} = strftime("%Y-%d-%mT%H:%M:%S",localtime());
168              
169              
170 0   0     0 $info{destination} = $self->param('destination') || $self->destination()
171             || '';
172 0   0     0 $info{session_id} = $self->param('session_id') || $self->sess_id() || '';
173 0   0     0 $info{owner} = $self->param('owner') || $self->owner() || '' ;
174              
175            
176              
177            
178 0         0 for my $item ( keys %info )
179             {
180 0         0 my $indent = $indent x 2;
181            
182 0 0       0 if ( length $info{$item} )
    0          
183             {
184 0         0 $info{$item} = _quote_xml($info{$item});
185            
186 0         0 $info .= "$indent<$pref$item>$info{$item}\n";
187             }
188             elsif ($mandatory{$item})
189             {
190 0         0 $info .= "$indent<$pref$item />\n";
191             }
192             }
193              
194 0         0 $info = "$indent<${pref}info>\n$info$indent\n";
195             }
196              
197 1         3 foreach my $param ( @params )
198             {
199 1         3 my $indent = $indent x 2;
200              
201 1         3 my $value = $self->param($param);
202              
203 1 50       20 if (ref $value )
204             {
205 0         0 my $index = 0;
206 0         0 foreach my $mvalue ( @{$value} )
  0         0  
207             {
208 0         0 $index++;
209 0         0 $mvalue = _quote_xml($mvalue);
210 0         0 $items .= qq%$indent<${pref}field name="$param" index="$index">%;
211 0         0 $items .= "$mvalue\n";
212             }
213             }
214             else
215             {
216 1         3 $value = _quote_xml($value);
217 1         4 $items .= qq%$indent<${pref}field name="$param">%;
218 1         7 $items .= "$value\n";
219             }
220             }
221              
222 1         4 $items = "$indent<${pref}items>\n$items$indent\n";
223              
224 1         2 my $ns_att = '';
225              
226            
227 1 50       3 if ( $ns_url )
228             {
229              
230 1         2 my $prefix_part = '';
231              
232 1 50       3 if ($ns_prefix )
233             {
234 1         2 $prefix_part = ":$ns_prefix";
235             }
236 1         3 $ns_att = qq% xmlns$prefix_part="$ns_url"%;
237             }
238              
239 1         4 $xml = "<${pref}form_data$ns_att>\n$info$items\n";
240              
241 1         5 return $xml;
242             }
243              
244             =item ns_prefix
245              
246             Gets and/or sets the namespace prefix as described as an argument to asXML()
247             above.
248              
249             =cut
250              
251             sub ns_prefix
252             {
253 3     3 1 563 my ( $self, $ns_prefix ) = @_;
254              
255 3 100       9 if ( defined $ns_prefix )
256             {
257 1         4 $self->{_private}->{ns_prefix} = $ns_prefix;
258             }
259            
260 3   50     20 return $self->{_private}->{ns_prefix} || '';
261             }
262              
263             =item
264              
265             Returns and/or sets the namespace URL for the document as described as an
266             argument to asXML() above.
267              
268             =cut
269              
270             sub ns_url
271             {
272 1     1 1 2 my ( $self, $ns_url ) = @_;
273              
274 1 50       3 if ( defined $ns_url )
275             {
276 0         0 $self->{_private}->{ns_url} = $ns_url;
277             }
278            
279 1         2 my $def_url = 'http://schemas.gellyfish.com/FormData';
280              
281 1   33     8 return $self->{_private}->{ns_url} || $def_url;
282              
283             }
284              
285             =item omit_info
286              
287             If this is set to a true value then the 'header' information will not be
288             emitted in the output document.
289              
290             =cut
291              
292             sub omit_info
293             {
294 3     3 1 6 my ( $self, $omit_info ) = @_;
295              
296 3 100       9 if ( defined $omit_info )
297             {
298 1         2 $self->{_private}->{omit_info} = $omit_info;
299             }
300              
301 3   50     16 return $self->{_private}->{omit_info} || 0;
302              
303             }
304              
305             =item destination
306              
307             This is used to set the value of the 'destination' element in the header
308             information of the output document. This may be a URL, email address or
309             some other identifier. Its content is entirely application specific.
310              
311             =cut
312              
313             sub destination
314             {
315 0     0 1 0 my ( $self, $destination ) = @_;
316              
317 0 0       0 if ( defined $destination )
318             {
319 0         0 $self->{_private}->{destination} = $destination;
320             }
321              
322 0 0       0 return exists $self->{_private}->{destination} ?
323             $self->{_private}->{destination} : '';
324             }
325              
326             =item sess_id
327              
328             This sets the 'session id' for this CGI request, it is intended to be a
329             unique identifier for this request and may take the form of a UUID or an
330             MD5 hash or something similar. Its use is application specific.
331              
332             =cut
333              
334             sub sess_id
335             {
336 0     0 1 0 my ( $self , $sess_id ) = @_;
337              
338 0 0       0 if ( defined $sess_id )
339             {
340 0         0 $self->{_private}->{sess_id} = $sess_id;
341             }
342              
343 0 0       0 return exists $self->{_private}->{sess_id} ?
344             $self->{_private}->{sess_id} : '' ;
345              
346             }
347              
348             =item owner
349              
350             This sets the value of the 'owner' element in the header information. This
351             is intended to be the e-mail address indicating the contact for this
352             application. The usage of this information is application specific.
353              
354             =cut
355              
356             sub owner
357             {
358 0     0 1 0 my ( $self , $owner ) = @_;
359              
360 0 0       0 if ( defined $owner )
361             {
362 0         0 $self->{_private}->{owner} = $owner;
363             }
364              
365 0 0       0 return exists $self->{_private}->{owner} ?
366             $self->{_private}->{owner} : '' ;
367              
368             }
369              
370             sub _quote_xml
371             {
372 1     1   3 $_[0] =~ s/&/&/g;
373 1         2 $_[0] =~ s/
374 1         3 $_[0] =~ s/>/>/g;
375 1         2 $_[0] =~ s/'/'/g;
376 1         18 $_[0] =~ s/"/"/g;
377 1         3 $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
  0         0  
378 1         3 return($_[0]);
379             }
380              
381             # I borrowed this from CGI::XML which in turn said
382             # borrowed from XML::DOM
383              
384             sub _xml_utf8_encode
385             {
386 0     0     my ($n) = @_;
387 0 0         if ($n < 0x80)
    0          
    0          
    0          
388             {
389 0           return chr ($n);
390             }
391             elsif ($n < 0x800)
392             {
393 0           return pack ("CC", (($n >> 6) | 0xc0), (($n & 0x3f) | 0x80));
394             }
395             elsif ($n < 0x10000)
396             {
397 0           return pack ("CCC", (($n >> 12) | 0xe0), ((($n >> 6) & 0x3f) | 0x80),
398             (($n & 0x3f) | 0x80));
399             }
400             elsif ($n < 0x110000)
401             {
402 0           return pack ("CCCC", (($n >> 18) | 0xf0), ((($n >> 12) & 0x3f) | 0x80),
403             ((($n >> 6) & 0x3f) | 0x80), (($n & 0x3f) | 0x80));
404             }
405              
406 0           return $n;
407             }
408              
409             =back
410              
411             =cut
412              
413             1;
414             __END__