File Coverage

lib/Template/Plugin/XML/File.pm
Criterion Covered Total %
statement 33 59 55.9
branch 11 30 36.6
condition 2 12 16.6
subroutine 9 12 75.0
pod 3 8 37.5
total 58 121 47.9


line stmt bran cond sub pod time code
1             package Template::Plugin::XML::File;
2              
3 1     1   89509 use strict;
  1         4  
  1         44  
4 1     1   8 use warnings;
  1         2  
  1         36  
5 1     1   493 use Template::Plugin::XML;
  1         3  
  1         34  
6 1     1   7 use base 'Template::Plugin::File';
  1         3  
  1         1087  
7              
8             our $VERSION = 2.15;
9             our $DEBUG = 0 unless defined $DEBUG;
10             our $EXCEPTION = 'Template::Exception' unless defined $EXCEPTION;
11             our $XML_PLUGIN = 'Template::Plugin::XML' unless defined $XML_PLUGIN;
12             our $FILE_TYPES = {
13             name => 'name',
14             file => 'name',
15             xml_file => 'name',
16             fh => 'handle',
17             handle => 'handle',
18             xml_fh => 'handle',
19             };
20              
21              
22             sub new {
23 12     12 1 66387 my $class = shift;
24 12         27 my $context = shift;
25 12 100 66     109 my $params = @_ && ref $_[-1] eq 'HASH' ? pop(@_) : { };
26 12         22 my ($source, $type);
27            
28             my $self = bless {
29             debug => delete $params->{ debug },
30             libxml => delete $params->{ libxml },
31 12         93 }, $class;
32              
33             # apply default for debug from package variable
34 12 100       77 $self->{ debug } = $DEBUG unless defined $self->{ debug };
35              
36 12 100       33 if (@_) {
37             # first positional argument is file name or XML string
38 6         9 $source = shift;
39 6 100       31 $type = $XML_PLUGIN->detect_filehandle($source) ? 'handle' : 'name';
40 6         18 $self->{ type } = $type;
41 6         12 $self->{ $type } = $source;
42             }
43             else {
44             # look in named params for a known type
45 6         38 while (my ($param, $type) = each %$FILE_TYPES) {
46 36 100       153 if (defined ($source = delete $params->{ $param })) {
47 6         14 $self->{ type } = $type;
48 6         27 $self->{ $type } = $source;
49             }
50             }
51             }
52              
53             return $self->throw('a file name or file handle must be specified')
54 12 50       41 unless defined $self->{ type };
55              
56 12         41 return $self;
57             }
58              
59              
60             sub type {
61 8     8 0 357 return $_[0]->{ type };
62             }
63              
64              
65             sub name {
66 6     6 1 138 return $_[0]->{ name };
67             }
68              
69              
70             sub libxml {
71 0     0 0 0 my $self = shift;
72 0         0 return $self->{ libxml };
73             }
74              
75             sub dom {
76 0     0 0 0 my $self = shift;
77 0 0 0     0 my $args = @_ && ref $_[-1] eq 'HASH' ? pop(@_) : { };
78              
79 0   0     0 return $self->{ dom } ||= do {
80 0         0 my ($parser, $dom);
81              
82 0 0       0 if ($parser = $self->{ libxml }) {
83 0 0       0 if (defined $self->{ name }) {
84             # file name
85 0 0       0 eval { $dom = $parser->parse_file($self->{ name }) }
  0         0  
86             || $self->throw("failed to parse $self->{ name }: $@");
87             }
88             else {
89             # file handle
90 0 0       0 eval { $dom = $parser->parse_fh($self->{ handle }) }
  0         0  
91             || $self->throw("failed to parse file handle: $@");
92             }
93             }
94             else {
95 0 0       0 eval { require XML::DOM }
  0         0  
96             || $self->throw("XML::DOM not available: $@");
97              
98 0   0     0 $parser = XML::DOM::Parser->new(%$args)
99             || $self->throw("failed to create parser");
100              
101             # TODO: must call dispose() on any XML::DOM documents we create
102 0 0       0 if (defined $self->{ name }) {
103             # file name
104 0 0       0 eval { $dom = $parser->parsefile($self->{ name }) }
  0         0  
105             || $self->throw("failed to parse $self->{ name }: $@");
106             }
107             else {
108             # file handle
109 0         0 local $/ = undef;
110 0         0 my $fh = $self->{ handle };
111 0         0 my $text = <$fh>;
112 0 0       0 eval { $dom = $parser->parse($text) }
  0         0  
113             || $self->throw("failed to parse $self->{ name }: $@");
114             }
115             }
116 0         0 $dom;
117             };
118             }
119              
120             #------------------------------------------------------------------------
121             # handle()
122             #
123             # TODO: this currently returns the handle iff one was specified as a
124             # constructor arg, and undef otherwise. But it would be nice if it
125             # opened the file for you (using any mode/write/append/create params
126             # specified either in the constructor or as args) and returned the handle.
127             # Then you could write [% dir.file('foo.xml').handle %]
128             #------------------------------------------------------------------------
129              
130             sub handle {
131 5     5 0 112 return $_[0]->{ handle };
132             }
133              
134              
135             sub debug {
136 3     3 1 124 return $_[0]->{ debug };
137             }
138              
139             sub throw {
140 0     0 0   my $self = shift;
141 0           die $Template::Plugin::XML::EXCEPTION->new( 'XML.File' => join('', @_) );
142             }
143              
144              
145              
146             1;
147              
148             __END__