File Coverage

blib/lib/Getopt/XML.pm
Criterion Covered Total %
statement 78 101 77.2
branch 17 32 53.1
condition 3 9 33.3
subroutine 15 16 93.7
pod 4 4 100.0
total 117 162 72.2


line stmt bran cond sub pod time code
1             =pod
2              
3             =head1 NAME
4              
5             Getopt::XML - Provide the user input arguments to Getopt::Long as an XML document
6              
7             =head1 SYNOPSIS
8              
9             Read in a list of XML elements and process them as the input arguments to the
10             Getopt::Long module
11              
12             use XML::TreePP;
13             use Getopt::Long;
14             use Getopt::XML qw(GetXMLOptions);
15             use Data::Dump qw(dump);
16             #
17             # Set the XML Data
18             my $xmldata=<<"EOF_XMLDATA";
19            
20             red
21             red delicious
22            
23             Macomb
24             Peoria
25             Galesburg
26            
27             EOF_XMLDATA
28             #
29             # Parse the XML data using XML::TreePP module
30             my $tpp = XML::TreePP->new();
31             my $tree = $tpp->parse( $xmldata );
32             #
33             # Read the XML data in as arguments to Getopt::Long
34             my %options;
35             GetXMLOptions (
36             xmldoc => $tree,
37             xmlpath => '/apple',
38             Getopt_Long =>
39             [
40             \%options,
41             'isAvailable',
42             'color=s',
43             'type=s',
44             'cityGrown=s@'
45             ]
46             );
47             dump(\%options);
48              
49             This is the output:
50              
51             {
52             cityGrown => ["Macomb", "Peoria", "Galesburg"],
53             color => "red",
54             isAvailable => 1,
55             type => "red delicious",
56             }
57              
58             Alternately, the XML data can be in a file.
59             The above code would be rewritten as this:
60              
61             use Getopt::Long;
62             use Getopt::XML qw(GetXMLOptions);
63             use Data::Dump qw(dump);
64             #
65             my %options;
66             GetXMLOptions (
67             xmlfile => '/path/to/xml_file.xml',
68             xmlpath => '/apple',
69             Getopt_Long =>
70             [
71             \%options,
72             'isAvailable',
73             'color=s',
74             'type=s',
75             'cityGrown=s@'
76             ]
77             );
78             dump(\%options);
79              
80             =head1 DESCRIPTION
81              
82             This is simply another way to pass in user defined arguments to an application
83             using Getop::Long. The module provides a way to pass in user arguments from an
84             XML file into Getopt::Long.
85              
86             In this way, the user can provide input to an application via an XML file. And
87             this can be useful if the application is ran at a regular interval. Or it may
88             be useful if the input to the application can change between multiple
89             executions, but the provided content is consistant over time based on the
90             context of the execution.
91              
92             This input method may be desired for an application which has default values
93             for options the author wishes to exist, but the author wants those default
94             values to be changed by the user without having to edit the application code.
95              
96             Or perhaps the application will reside in a multi-user environment, and this
97             module would be used to store the input options as part of the user preferences.
98              
99             And finally, perhaps the options to be passed into the application resides
100             somewhere else in XML or another storage format that can be transformed into
101             XML as input to an application.
102              
103             =head1 REQUIREMENTS
104              
105             The following perl modules are depended on by this module:
106             ( I )
107              
108             =over 4
109              
110             =item * XML::TreePP
111              
112             =item * XML::TreePP::XMLPath
113              
114             =item * Getopt::Long # Getopt::Long 2.37 or greater is required
115              
116             =back
117              
118             Both XML::TreePP and XML::TreePP::XMLPath required modules are Pure PERL
119             implementations.
120              
121             Getopt::Long version 2.37 introduces the GetOptionsFromArray() method. Versions
122             of Getopt::Long previous to 2.37 do not contain the GetOptionsFromArray() method.
123              
124             The process of transforming XML data into options that can be passed into
125             Getopt::Long is performed with the GetOptionsFromArray() method.
126              
127             =head1 IMPORTABLE METHODS
128              
129             When the calling application invokes this module in a use clause, the following
130             methods can be imported into its space.
131              
132             =over 4
133              
134             =item * C
135              
136             =item * C
137              
138             =back
139              
140             Example:
141              
142             use Getopt::XML qw( GetXMLOptions GetXMLOptionsFromFile );
143              
144             =head1 METHODS
145              
146             =cut
147              
148             package Getopt::XML;
149              
150 1     1   23182 use 5.008001;
  1         4  
  1         39  
151 1     1   6 use strict;
  1         1  
  1         35  
152 1     1   5 use warnings;
  1         6  
  1         37  
153 1     1   4 use Exporter;
  1         2  
  1         45  
154 1     1   5 use Carp;
  1         2  
  1         242  
155 1     1   1302 use Getopt::Long qw(GetOptionsFromArray); # requires Getopt::Long 2.37 or greater
  1         14872  
  1         7  
156 1     1   1348 use XML::TreePP;
  1         10082  
  1         45  
157 1     1   1662 use XML::TreePP::XMLPath qw(filterXMLDoc);
  1         21772  
  1         145  
158              
159              
160             BEGIN {
161 1     1   13 use vars qw(@ISA @EXPORT @EXPORT_OK);
  1         2  
  1         76  
162 1     1   15 @ISA = qw(Exporter);
163 1         2 @EXPORT = qw();
164 1         4 @EXPORT_OK = qw(&GetXMLOptions &GetXMLOptionsFromFile);
165              
166 1     1   5 use vars qw($REF_NAME);
  1         1  
  1         71  
167 1         1 $REF_NAME = "Getopt::XML"; # package name
168              
169 1     1   5 use vars qw( $VERSION );
  1         1  
  1         33  
170 1         826 $VERSION = '0.53';
171             }
172              
173              
174             =pod
175              
176             =head2 new
177              
178             Create a new object instances of this module.
179              
180             =over 4
181              
182             =item * I
183              
184             An object instance of this module.
185              
186             =back
187              
188             my $glx = new Getopt::XML();
189              
190             =cut
191              
192             # new
193             #
194             # It is not necessary to create an object of this module.
195             # However, if you choose to do so any way, here is how you do it.
196             #
197             # my $obj = new Getopt::XML;
198             #
199             # You will have problems with the methods if you call them in an object
200             # oriented mannor. So you are better off not creating an object instance of
201             # this module, unless you are sure you know what you are doing.
202             #
203             sub new {
204 1     1 1 1389 my $pkg = shift;
205 1   33     10 my $class = ref($pkg) || $pkg;
206 1         2 my $self = bless {}, $class;
207 1         4 return $self;
208             }
209              
210              
211             =pod
212              
213             =head2 XMLToGetoptArgsArray
214              
215             This method formats a subtree of an XML document into an array that is
216             acceptable to be passed in to the Getopt::Long::GetOptionsFromArray() method.
217              
218             =over 4
219              
220             =item * B
221              
222             The hash reference of a parsed XML file, which has been parsed
223             by XML::TreePP::parse()
224              
225             =item * I
226              
227             A reference to an array which an acceptable array input to the
228             Getopt::Long::GetOptionsFromArray() method.
229              
230             =back
231              
232             my $ha_list = XMLToGetoptArgsArray ( $XMLTree )
233              
234             =cut
235              
236             # XMLToGetoptArgsArray
237             # @param xmltree the XML::TreePP XML Tree
238             # @return [options] an array reference of options suitable for GetOpt::Long::GetoptionsFromArray()
239             sub XMLToGetoptArgsArray ($);
240             sub XMLToGetoptArgsArray ($) {
241 2 50 50 2 1 17 my $self = shift if ref($_[0]) eq $REF_NAME || undef;
242 2 50       8 if (@_ != 1) { carp 'method XMLToGetoptArgsArray($) requires one argument.'; return undef; }
  0         0  
  0         0  
243 2         4 my $xmltree = shift;
244 2         3 my @options;
245              
246 2 100       9 if (ref $xmltree eq "ARRAY") {
    50          
247             # If the XMLPath filters to more than one node, we accept all results
248 1         2 foreach my $xml_e (@{$xmltree}) {
  1         3  
249 1         14 my $sopt = XMLToGetoptArgsArray($xml_e);
250 1 50       3 next if !defined $sopt;
251 1         1 push (@options,@{$sopt});
  1         7  
252             }
253 1         4 return \@options;
254             } elsif (ref $xmltree ne "HASH") {
255 0         0 return undef;
256             }
257 1         2 while (my ($key,$val) = each(%{$xmltree})) {
  5         24  
258             # We include attribute in the
259 4 50       11 if ($key =~ /^\-/) {
260 0         0 $key =~ s/^\-//;
261             }
262 4 100       15 if (! defined $val) {
    100          
    50          
    50          
263 1         3 push(@options,('--'.$key));
264 1         2 next;
265             } elsif (ref $val eq "ARRAY") {
266 1         2 foreach my $a (@{$val}) {
  1         9  
267 3         6 push(@options,('--'.$key));
268 3         8 push(@options,$a);
269             }
270             } elsif (ref $val eq "HASH") {
271 0         0 push(@options,('--'.$key));
272 0         0 foreach (my ($skey,$sval) = each %{$val}) {
  0         0  
273 0         0 push(@options,($skey.'='.$sval));
274             }
275             } elsif (ref $val eq "SCALAR") {
276 0         0 push(@options,('--'.$key));
277 0         0 push(@options,${$val});
  0         0  
278             } else {
279 2         35 push(@options,('--'.$key));
280 2         6 push(@options,$val);
281             }
282             }
283 1         3 return \@options;
284             }
285              
286              
287             =pod
288              
289             =head2 GetXMLOptions
290              
291             Read a XML::TreePP parsed XML document, retrieve the XML data located at the
292             specified XML subtree, and transform it into an acceptable argument array that
293             can be passed into to the Getopt::Long::GetOptionsFromArray() method.
294              
295             =over 4
296              
297             =item * B
298              
299             The hash reference of a parsed XML file, which has been parsed
300             by XML::TreePP::parse()
301              
302             =item * B - I
303              
304             The XML Path as recognized by the XML::TreePP::XMLPath module.
305             Note that XMLPath is NOT an XPath, although it has similarities.
306              
307             =item * B
308              
309             The hash array of a Getopt::Long configuration which is a definition
310             of the expected Getopt::Long::GetOptions() input options.
311              
312             =back
313              
314             GetXMLOptions ( xmldoc => $XMLTree, xmlpath => $XMLPath, Getopt_Long => \@options )
315              
316             =cut
317              
318             # GetXMLOptions
319             # @param xmldoc the XML::TreePP parsed XML file as a HASH
320             # @param xmlpath an XPath-like string used to retrieve a XML child element for the parsing, instead of the XML root
321             # @param Getopt_Long input for the Getopt::Long::GetOptions(@) method used in this method for input
322             # @return the result of Getopt::Long() using the 'xmldoc' as input (as opposed to @ARGV as input)
323             #
324             # This method does not look at nor touch @ARGV, but instead parses the XML
325             # document 'xmldoc', starting at 'path', and uses that in place of @ARGV.
326             # Thus, the returning data is from the result of
327             # Getopt::Long::GetOptionsFromArray(,@{'Getopt_Long'})
328             #
329             sub GetXMLOptions (@) {
330 1 50 50 1 1 22716 my $self = shift if ref($_[0]) eq $REF_NAME || undef;
331 1 50       5 if (! @_ >= 1) { carp 'method GetXMLOptions(@) requires at least one argument.'; return undef; }
  0         0  
  0         0  
332 1         7 my %args = @_; # xmldoc, dtddoc, xmlpath, Getopt_Long,
333 1         3 my $tree = $args{'xmldoc'};
334             # not yet supported # @param dtddoc (optional) the DTD doc to validate the XML doc
335             #my %args = validate ( @_, { xmldoc => { optional => 0 },
336             # dtddoc => { optional => 1 },
337             # xmlpath => { type => SCALAR, optional => 1 },
338             # Getopt_Long => { type => ARRAYREF, optional => 1 }
339             # }
340             # );
341 1         2 my $subtree;
342              
343 1 50       5 if (defined $args{'xmlpath'}) {
344 1         9 $subtree = filterXMLDoc($tree,$args{'xmlpath'});
345             } else {
346 0         0 $subtree = $tree;
347             }
348 1 50       854 if (! defined $subtree) {
349 0         0 return undef;
350             }
351 1         10 my $xmlargs = XMLToGetoptArgsArray($subtree);
352 1         2 return GetOptionsFromArray($xmlargs,@{$args{'Getopt_Long'}});
  1         8  
353             }
354              
355              
356             =pod
357              
358             =head2 GetXMLOptionsFromFile
359              
360             This method is a wrapper around the Getopt::XML::GetXMLOptions() method.
361             Parse a XML file with the XML::TreePP::parsefile() method, then call the
362             GetXMLOptions() method with the resulting XML::TreePP parsed XML document and
363             other parameters passed in from the caller.
364              
365             =over 4
366              
367             =item * B
368              
369             The XML file which will be parsed by XML::TreePP::parse() into a hash reference.
370              
371             =item * B - I
372              
373             The XML Path as recognized by the XML::TreePP::XMLPath module.
374             Note that XMLPath is NOT an XPath, although it has similarities.
375              
376             =item * B
377              
378             The hash array of a Getopt::Long configuration which is a definition
379             of the expected Getopt::Log::GetOptions() input options.
380              
381             =back
382              
383             GetXMLOptionsFromFile ( xmlfile => $XMLFile, xmlpath => $XMLPath, Getopt_Long => \@options )
384              
385             =cut
386              
387             # GetXMLOptionsFromFile
388             # @param xmlfile the XML file
389             # @param xmlpath an XPath-like string used to retrieve a XML child element for the parsing, instead of the XML root
390             # @param Getopt_Long input for the Getopt::Long::GetOptions(@) method used in this method for input
391             # @return the result of Getopt::Long() using the 'xmlfile' as input (as opposed to @ARGV as input)
392             #
393             # See GetXMLOptions method.
394             #
395             sub GetXMLOptionsFromFile (@) {
396 0 0 0 0 1   my $self = shift if ref($_[0]) eq $REF_NAME || undef;
397 0 0         if (! @_ >= 1) { carp 'method GetXMLOptionsFromFile(@) requires at least one argument.'; return undef; }
  0            
  0            
398 0           my %args = @_; # xmlfile, dtdfile, xmlpath, Getopt_Long,
399             # not yet supported # @param dtdfile (optional) the DTD file to validate the XML file
400             #my %args = validate ( @_, { xmlfile => { optional => 0 },
401             # dtdfile => { optional => 1 },
402             # xmlpath => { type => SCALAR, optional => 1 },
403             # Getopt_Long => { type => ARRAYREF, optional => 0 }
404             # }
405             # );
406              
407 0           my $tpp = XML::TreePP->new();
408 0           my $tree = $tpp->parsefile( $args{'xmlfile'} );
409              
410 0           return GetXMLOptions(
411             xmldoc => $tree,
412             xmlpath => $args{'xmlpath'},
413             Getopt_Long => $args{'Getopt_Long'}
414             );
415             }
416              
417             1;
418             __END__