File Coverage

blib/lib/Apache/AxKit/Language/LibXSLTEnhanced.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Apache::AxKit::Language::LibXSLTEnhanced;
2              
3             #use 5.008003;
4 1     1   43412 use strict;
  1         3  
  1         49  
5 1     1   8 use warnings;
  1         2  
  1         201  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14              
15             # This allows declaration use Apache::AxKit::Language::LibXSLTEnhanced ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18             our %EXPORT_TAGS = ( 'all' => [ qw(
19            
20             ) ] );
21              
22             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
23              
24             our @EXPORT = qw(
25            
26             );
27              
28             our $VERSION = '0.02';
29              
30 1     1   8 use strict;
  1         8  
  1         69  
31 1     1   8 use vars qw/@ISA $VERSION %DEPENDS/;
  1         2  
  1         109  
32 1     1   531 use XML::LibXSLT 1.30;
  0            
  0            
33             use XML::LibXML;
34             use Apache;
35             use Apache::Request;
36             use Apache::AxKit::Language;
37             use Apache::AxKit::Provider;
38             use Apache::AxKit::LibXMLSupport;
39              
40             @ISA = 'Apache::AxKit::Language';
41              
42             $VERSION = 1.0; # this fixes a CPAN.pm bug. Bah!
43              
44             my %style_cache;
45              
46             sub reset_depends {
47             %DEPENDS = ();
48             }
49              
50             sub add_depends {
51             $DEPENDS{shift()}++;
52             }
53              
54             sub get_depends {
55             return keys %DEPENDS;
56             }
57              
58             sub handler {
59             my $class = shift;
60             my ($r, $xml, $style, $last_in_chain) = @_;
61            
62             my ($xmlstring, $xml_doc);
63            
64             AxKit::Debug(7, "[LibXSLT] getting the XML");
65            
66             if (my $dom = $r->pnotes('dom_tree')) {
67             $xml_doc = $dom;
68             delete $r->pnotes()->{'dom_tree'};
69             }
70             else {
71             $xmlstring = $r->pnotes('xml_string');
72             }
73            
74             my $parser = XML::LibXML->new();
75             $parser->expand_entities(1);
76             local($XML::LibXML::match_cb, $XML::LibXML::open_cb,
77             $XML::LibXML::read_cb, $XML::LibXML::close_cb);
78             Apache::AxKit::LibXMLSupport->reset();
79             local $Apache::AxKit::LibXMLSupport::provider_cb =
80             sub {
81             my $r = shift;
82             my $provider = Apache::AxKit::Provider->new_content_provider($r);
83             add_depends($provider->key());
84             return $provider;
85             };
86              
87             if (!$xml_doc && !$xmlstring) {
88             $xml_doc = $xml->get_dom();
89             }
90             elsif ($xmlstring) {
91             $xml_doc = $parser->parse_string($xmlstring, $r->uri());
92             }
93              
94             $xml_doc->process_xinclude();
95            
96             AxKit::Debug(7, "[LibXSLT] parsing stylesheet");
97              
98             my $stylesheet;
99             my $cache = $style_cache{$style->key()};
100             if (ref($cache) eq 'HASH' && !$style->has_changed($cache->{mtime}) && ref($cache->{depends}) eq 'ARRAY') {
101             AxKit::Debug(8, "[LibXSLT] checking if stylesheet is cached");
102             my $changed = 0;
103             DEPENDS:
104             foreach my $depends (@{ $cache->{depends} }) {
105             my $p = Apache::AxKit::Provider->new_style_provider($r, key => $depends);
106             if ( $p->has_changed( $cache->{mtime} ) ) {
107             $changed = 1;
108             last DEPENDS;
109             }
110             }
111             if (!$changed) {
112             AxKit::Debug(7, "[LibXSLT] stylesheet cached");
113             $stylesheet = $style_cache{$style->key()}{style};
114             }
115             }
116            
117             if (!$stylesheet || ref($stylesheet) ne 'XML::LibXSLT::Stylesheet') {
118             reset_depends();
119             my $style_uri = $style->apache_request->uri();
120             AxKit::Debug(7, "[LibXSLT] parsing stylesheet $style_uri");
121             my $style_doc = $style->get_dom();
122            
123             local($XML::LibXML::match_cb, $XML::LibXML::open_cb,
124             $XML::LibXML::read_cb, $XML::LibXML::close_cb);
125             Apache::AxKit::LibXMLSupport->reset();
126             local $Apache::AxKit::LibXMLSupport::provider_cb =
127             sub {
128             my $r = shift;
129             my $provider = Apache::AxKit::Provider->new_style_provider($r);
130             add_depends($provider->key());
131             return $provider;
132             };
133            
134             $stylesheet = XML::LibXSLT->parse_stylesheet($style_doc);
135            
136             foreach( $r->dir_config->get("LibXSLTFunctionsModule") ) {
137             eval("require $_" );
138            
139             if( $@ ) {
140             die "Could not load module.\n $@";
141             }
142            
143             my $function_lib = $_->new();
144            
145             foreach( $function_lib->getFunctions() ) {
146             XML::LibXSLT->register_function( $function_lib->getNamespace(), $_->[0], $_->[1] );
147             }
148             }
149              
150             unless ($r->dir_config('AxDisableXSLTStylesheetCache')) {
151             $style_cache{$style->key()} =
152             { style => $stylesheet, mtime => time, depends => [ get_depends() ] };
153             }
154             }
155              
156             # get request form/querystring parameters
157             my @params = fixup_params($class->get_params($r));
158              
159             AxKit::Debug(7, "[LibXSLT] performing transformation");
160              
161             my $results = $stylesheet->transform($xml_doc, @params);
162            
163             AxKit::Debug(7, "[LibXSLT] transformation finished, creating $results");
164            
165             if ($last_in_chain) {
166             AxKit::Debug(8, "[LibXSLT] outputting to \$r");
167             if ($XML::LibXSLT::VERSION >= 1.03) {
168             my $encoding = $stylesheet->output_encoding;
169             my $type = $stylesheet->media_type;
170             $r->content_type("$type; charset=$encoding");
171             }
172             $stylesheet->output_fh($results, $r);
173             }
174              
175             AxKit::Debug(7, "[LibXSLT] storing results in pnotes(dom_tree) ($r)");
176             $r->pnotes('dom_tree', $results);
177            
178             # warn "LibXSLT returned $output \n";
179             # print $stylesheet->output_string($results);
180             return Apache::Constants::OK;
181              
182             }
183              
184             sub fixup_params {
185             my @results;
186             while (@_) {
187             push @results, XML::LibXSLT::xpath_to_string(
188             splice(@_, 0, 2)
189             );
190             }
191             return @results;
192             }
193              
194             1;
195              
196              
197              
198              
199              
200              
201              
202              
203             # Preloaded methods go here.
204              
205             1;
206             __END__