File Coverage

lib/Template/Plugin/XML.pm
Criterion Covered Total %
statement 47 66 71.2
branch 17 30 56.6
condition 5 9 55.5
subroutine 11 18 61.1
pod 8 14 57.1
total 88 137 64.2


line stmt bran cond sub pod time code
1             package Template::Plugin::XML;
2              
3 3     3   119403 use strict;
  3         7  
  3         116  
4 3     3   15 use warnings;
  3         5  
  3         87  
5 3     3   16 use base 'Template::Plugin';
  3         9  
  3         2555  
6              
7             our $VERSION = 2.17;
8             our $DEBUG = 0 unless defined $DEBUG;
9             our $EXCEPTION = 'Template::Exception' unless defined $EXCEPTION;
10             our $LIBXML = eval { require XML::LibXML } unless defined $LIBXML;
11 3     3   20 our $OPENHANDLE = eval "use Scalar::Util qw(openhandle)";
  3         7  
  3         173  
12             our @TYPES = qw( file fh text
13             xml xml_file xml_fh xml_text
14             html html_file html_fh html_text );
15              
16              
17             sub new {
18 10     10 1 42889 my $class = shift;
19 10         18 my $context = shift;
20 10 100 66     117 my $params = @_ && ref $_[-1] eq 'HASH' ? pop(@_) : { };
21 10         17 my ($source, $type);
22              
23 10 100       48 if (@_) {
24             # first positional argument is file name or XML string
25 1         3 $source = shift;
26 1         5 $type = $class->detect_type($source);
27             }
28             else {
29             # look in named params for a known type
30 9         19 foreach (@TYPES) {
31 99 50       208 $type = $_, last
32             if defined ($source = delete $params->{ $_ });
33             }
34             }
35              
36             my $self = bless {
37             context => $context,
38             debug => delete $params->{ debug },
39             libxml => delete $params->{ libxml },
40 10         65 }, $class;
41              
42             # apply defaults for debug and libxml from package variable
43 10 100       50 $self->{ debug } = $DEBUG unless defined $self->{ debug };
44 10 100       31 $self->{ libxml } = $LIBXML unless defined $self->{ libxml };
45              
46             # if libxml is enabled then we create an XML::LibXML parser
47 10   66     27 $self->{ libxml } &&= do {
48             # make sure they didn't try and force libxml=>1 when $LIBXML
49             # says we haven't got XML::LibXML installed
50 1 50       9 return $self->throw('XML::LibXML is not available')
51             unless $LIBXML;
52              
53 0         0 my $parser = XML::LibXML->new();
54              
55             # iterate through remaining params trying to call the
56             # appropriate method on the XML::LibXML object, e.g.
57             # expand_entities => 1 becomes $parse->expand_entities(1)
58              
59 0         0 my ($param, $value, $method);
60 0         0 while (($param, $value) = each %$params) {
61             # throw an error if the parser doesn't have the method
62 0 0       0 $self->throw("invalid configuration parameter: $param")
63             unless ($method = UNIVERSAL::can($parser, $param));
64              
65             # catch any errors thrown and re-throw as our exceptions
66 0         0 eval { &$method($parser, $value) };
  0         0  
67 0 0       0 $self->throw("configuration parameter '$param' failed: $@")
68             if $@;
69             }
70 0         0 $parser;
71             };
72              
73 9         31 return $self;
74             }
75              
76              
77             sub source {
78 0     0 0 0 return $_[0]->{ source };
79             }
80              
81              
82             sub type {
83 0     0 0 0 return $_[0]->{ type };
84             }
85              
86              
87             sub debug {
88 5     5 1 165 my $self = shift;
89 5         16 return $self->{ debug };
90             }
91              
92              
93             sub libxml {
94 3     3 0 92 my $self = shift;
95 3         12 return $self->{ libxml };
96             }
97              
98              
99             sub file {
100 1     1 1 41 my $self = shift;
101 1 50 33     48 my $params = @_ && ref $_[-1] eq 'HASH' ? pop(@_) : { };
102 1         3 my @args = @_;
103 1         2 push(@args, $params);
104              
105             $params->{ libxml } = $self->{ libxml }
106 1 50       7 unless defined $params->{ libxml };
107 1         5 return $self->{ context }->plugin('XML.File', \@args);
108             }
109              
110              
111             sub dir {
112 0     0 1 0 die "dir() not yet implemented";
113              
114             # pretty much as per file
115             }
116              
117             sub dom {
118 0     0 1 0 my $self = shift;
119              
120             # TODO: see if we've got a filename defined, create a DOM parser
121             # (and cache it), and then call its parse() method
122              
123             # ...but for now, we'll just create a plugin
124 0         0 $self->{ context }->plugin('XML.DOM', \@_);
125             }
126              
127             sub xpath {
128 0     0 1 0 my $self = shift;
129             # as above
130 0         0 $self->{ context }->plugin('XML.XPath', \@_);
131             }
132              
133             sub rss {
134 0     0 1 0 my $self = shift;
135             # as above
136 0         0 $self->{ context }->plugin('XML.RSS', \@_);
137             }
138              
139             sub simple {
140 0     0 1 0 my $self = shift;
141             # as above
142 0         0 $self->{ context }->plugin('XML.Simple', \@_ );
143             }
144              
145              
146             sub throw {
147 1     1 0 4 my $self = shift;
148 1         13 die $EXCEPTION->new( XML => join('', @_) );
149             }
150              
151              
152              
153             sub detect_filehandle {
154 7     7 0 9 my $self = shift;
155              
156             # look for a filehandle using Scalar::Utils openhandle if it's
157             # available or our poor-man's version if not.
158 7 50       58 return $OPENHANDLE ? openhandle($_[0]) : defined(fileno $_[0]);
159             }
160              
161              
162             sub detect_type {
163 1     1 0 2 my $self = shift;
164              
165             # look for a filehandle using Scalar::Utils openhandle if it's
166             # available or our poor-man's version if not.
167 1 50       3 return 'fh' if $self->detect_filehandle($_[0]);
168              
169             # okay, look for the xml declaration at the start
170 1 50       5 return 'xml_text' if $_[0] =~ m/^\<\?xml/;
171              
172             # okay, look for the html declaration anywhere in the doc
173 1 50       4 return 'html_text' if $_[0] =~ m//i;
174              
175             # okay, does this contain a "<" symbol, and declare it to be
176             # xml if it's got one, though they should use "
177 1 50       4 return 'text' if $_[0] =~ m{\<};
178              
179             # okay, we've tried everything else, return a filename
180 1         2 return 'file';
181             }
182              
183              
184              
185             1;
186              
187             __END__