File Coverage

blib/lib/XML/XPathScript/Processor.pm
Criterion Covered Total %
statement 76 326 23.3
branch 0 164 0.0
condition 0 65 0.0
subroutine 25 63 39.6
pod 22 34 64.7
total 123 652 18.8


line stmt bran cond sub pod time code
1             package XML::XPathScript::Processor;
2              
3 22     22   115 use strict;
  22         42  
  22         756  
4 22     22   107 use warnings;
  22         36  
  22         602  
5 22     22   107 use Carp;
  22         40  
  22         1498  
6              
7 22     22   116 use base qw/ Exporter /;
  22         38  
  22         2299  
8              
9 22     22   13135 use XML::XPathScript::Template;
  22         74  
  22         692  
10 22     22   21766 use Readonly;
  22         79368  
  22         3098  
11              
12             our $VERSION = '1.54';
13              
14             our @EXPORT = qw/
15             $DO_SELF_AS_CHILD
16             $DO_SELF_AND_KIDS
17             $DO_SELF_ONLY
18             $DO_NOT_PROCESS
19             DO_SELF_AND_KIDS
20             DO_SELF_ONLY
21             DO_NOT_PROCESS
22             DO_TEXT_AS_CHILD
23             /;
24              
25             our @EXPORT_OK = qw(
26             $DO_SELF_AS_CHILD
27             $DO_SELF_AND_KIDS
28             $DO_SELF_ONLY
29             $DO_NOT_PROCESS
30             DO_SELF_AND_KIDS
31             DO_SELF_ONLY
32             DO_NOT_PROCESS
33             DO_TEXT_AS_CHILD
34             processor
35             findnodes
36             findvalue
37             findvalues
38             findnodes_as_string
39             xpath_to_string
40             apply_templates
41             matches
42             set_namespace
43             is_element_node
44             is_text_node
45             is_comment_node
46             is_pi_node
47             is_nodelist
48             is_utf8_tainted
49             get_xpath_of_node
50             set_dom
51             get_dom
52             get_parser
53             enable_binmode
54             set_binmode
55             get_binmode
56             set_template
57             get_template
58             set_interpolation
59             get_interpolation
60             set_interpolation_regex
61             get_interpolation_regex
62             );
63              
64 22     22   232 use constant DO_TEXT_AS_CHILD => 2;
  22         45  
  22         1682  
65 22     22   124 use constant DO_SELF_AND_KIDS => 1;
  22         533  
  22         1214  
66 22     22   127 use constant DO_SELF_ONLY => -1;
  22         45  
  22         947  
67 22     22   121 use constant DO_NOT_PROCESS => 0;
  22         62  
  22         29352  
68              
69             our( $DO_SELF_AS_CHILD, $DO_SELF_AND_KIDS,
70             $DO_SELF_ONLY, $DO_NOT_PROCESS );
71             Readonly::Scalar $DO_SELF_AS_CHILD => 2;
72             Readonly::Scalar $DO_SELF_AND_KIDS => 1;
73             Readonly::Scalar $DO_SELF_ONLY => -1;
74             Readonly::Scalar $DO_NOT_PROCESS => 0;
75              
76              
77             sub new {
78 2     2 0 4 my $class = shift;
79 2         5 my $self = {};
80 2         7 bless $self, $class;
81 2         19 return $self;
82             # $XML::XPathScript::xp => {doc}
83             # {parser}
84             # {binmode}
85             # {template}
86             # $XML::XPathScript::current->interpolating() {is_interpolating}
87             # $XML::XPathScript::current->{interpolation_regex} {interpolation_regex}
88             }
89              
90             #### accessors #############################################
91            
92             sub processor {
93 0     0 1   return $_[0];
94             }
95              
96             sub set_dom {
97 0     0 1   my( $self, $dom ) = @_;
98 0 0         my $class = ref( $self->{dom} = $dom )
99             or croak "usage: \$processor->set_dom( \$dom )";
100              
101 0 0         if ( $class =~ /((?:XML::)(?:LibXML|XPath))/ ) {
    0          
102 0           $self->set_parser( $1 );
103             }
104             elsif ( $class =~ /B::XPath/ ) {
105 0           $self->set_parser( 'B::XPath' );
106             }
107             else {
108 0           die "no parser assigned to class $class\n";
109             }
110              
111              
112 0           return;
113             }
114              
115             sub set_parser {
116 0     0 0   my ( $self, $parser ) = @_;
117              
118 0           $self->{parser} = $parser;
119 0 0         if ( $parser eq 'XML::LibXML' ) {
    0          
    0          
120 0           require XML::XPathScript::Processor::LibXML;
121 0           bless $self, 'XML::XPathScript::Processor::LibXML';
122             }
123             elsif ( $parser eq 'XML::XPath' ) {
124 0           require XML::XPathScript::Processor::XPath;
125 0           bless $self, 'XML::XPathScript::Processor::XPath';
126             }
127             elsif ( $parser eq 'B::XPath' ) {
128 0           require XML::XPathScript::Processor::B;
129 0           bless $self, 'XML::XPathScript::Processor::B';
130             }
131             else {
132 0           die "parser $parser not supported\n";
133             }
134              
135             }
136              
137 0     0 1   sub get_dom { $_[0]->{dom} }
138 0     0 1   sub get_parser { $_[0]->{parser} }
139 0     0 1   sub enable_binmode { $_[0]->{binmode} = 1 }
140 0     0 0   sub set_binmode { $_[0]->enable_binmode; }
141 0     0 1   sub get_binmode { $_[0]->{binmode} }
142 0     0 1   sub set_template { $_[0]->{template} = $_[1] }
143 0     0 1   sub get_template { $_[0]->{template} }
144 0     0 1   sub set_interpolation { $_[0]->{is_interpolating} = $_[1] }
145 0     0 1   sub get_interpolation { $_[0]->{is_interpolating} }
146 0     0 1   sub set_interpolation_regex { $_[0]->{interpolation_regex} = $_[1] }
147 0     0 1   sub get_interpolation_regex { $_[0]->{interpolation_regex} }
148              
149              
150             # $processor->import_functional( $prefix )
151             # XML::XPathScript::Processor->import_functional( $prefix )
152              
153             sub import_functional {
154 0     0 1   my( $self, $prefix ) = @_;
155              
156 0 0         $self or croak "import_functional not called properly";
157            
158             # call as XML::XPathScript::Processor->import_functional
159 0 0         $self = XML::XPathScript::Processor->new unless ref $self;
160              
161 0           my($caller, $file, $line) = caller;
162              
163 0           $self->_export( $caller, $_, $prefix ) for @EXPORT_OK;
164              
165 0           return;
166             }
167              
168             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169              
170             sub _export {
171             # heavily inspired by David James' Class::Exporter
172             # (which is a nice way to say I stole it and
173             # twisted it to my own perverted needs)
174            
175 22     22   153 no strict qw/ refs /;
  22         42  
  22         861  
176 22     22   116 no warnings qw/ uninitialized /;
  22         39  
  22         17732  
177              
178 0     0     my( $self, $caller, $export, $prefix ) = @_;
179              
180 0 0         my $type = $export =~ s/^(\W)// ? $1 : '&';
181 0           my $export_sym = __PACKAGE__.'::'.$export;
182              
183             #if ( $export =~ /^DO_/ ) {
184             # #warn $caller.'::'.$prefix.$export;
185             # eval "sub ${caller}::$prefix$export () { ". $export->() ." };";
186             #warn &{$caller.'::'.$prefix.$export};
187             # \&XML::XPathScript::Processor::DO_SELF_AND_KIDS;
188             # return;
189             #}
190              
191 0     0     *{$caller.'::'.$prefix.$export} = $type eq '&' ? sub { $self->$export(@_) }
  0            
192 0           : $type eq '$' ? \${$export_sym}
  0            
193 0           : $type eq '@' ? \@{$export_sym}
194 0           : $type eq '%' ? \%{$export_sym}
195 0 0         : $type eq '*' ? *{$export_sym}
    0          
    0          
    0          
    0          
196             : croak "Can't export symbol: $type$export"
197             ;
198             }
199              
200             ##### stylesheet API #######################################
201              
202             sub findnodes {
203 0     0 1   my $self = shift;
204              
205 0 0         if ($self->{parser} eq 'XML::XPath' ) {
206 0           return $self->{dom}->findnodes(@_);
207             }
208              
209 0           my ($path, $context) = @_;
210 0 0         $context = $self->{dom} if (!defined $context);
211 0           return $context->findnodes($path);
212             }
213              
214             sub findvalue {
215 0     0 1   my $self = shift;
216 0 0         if ( $self->{parser} eq 'XML::XPath' ) {
217 0           return $self->xpath_to_string(scalar $self->{dom}->findvalue(@_));
218             }
219              
220 0           my ($path, $context) = @_;
221 0 0         $context = $self->{dom} if (!defined $context);
222 0           return $self->xpath_to_string($context->findvalue($path));
223             }
224              
225             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
226              
227             sub xpath_to_string {
228 0     0 1   my $self = shift;
229 0           my ($blob)=@_;
230 0 0         return $blob unless ref $blob ;
231              
232             # Was simply C<< return "$blob" >> but Perl 5.6.1 seems to have
233             # issues with UTF8-flag used in overloaded stringification :-(
234 0 0         return $blob->can("data") ? $blob->data()
    0          
235             : $blob->can("value") ? $blob->value()
236             : $blob->string_value()
237             ;
238             }
239              
240             sub findvalues {
241 0     0 1   my $self = shift;
242 0           my @nodes = $self->findnodes(@_);
243 0           map { $self->findvalue('.', $_) } @nodes;
  0            
244             }
245              
246             sub findnodes_as_string {
247 0     0 1   my $self = shift;
248 0           $self->{dom}->findnodes_as_string( @_ )
249             }
250              
251             sub matches {
252 0     0 1   my $self = shift;
253 0           $self->{dom}->matches(@_)
254             }
255              
256             sub set_namespace
257             {
258 0     0 0   my $self = shift;
259 0           eval { $self->{dom}->set_namespace(@_) };
  0            
260 0 0         warn "set_namespace failed: $@" if $@;
261             }
262              
263             sub apply_templates {
264 0     0 1   my $self = shift;
265              
266 0 0         my $params = ref( $_[-1] ) eq 'HASH' ? pop @_ : {} ;
267              
268             # catch the calls to apply_templates()
269 0 0         @_ = $self->findnodes('/') unless @_;
270              
271 0 0         unless( ref $_[0] ) { # called with a path to find
272 0           @_ = $self->findnodes( @_ );
273             }
274              
275 0 0         return unless @_;
276              
277 0           my $retval;
278              
279 22     22   131 no warnings qw/ uninitialized /;
  22         57  
  22         5841  
280             $retval .= $self->translate_node( $_, $params )
281 0 0         for $self->is_nodelist($_[0]) ? $_[0]->get_nodelist
282             : @_
283             ;
284 0           return $retval;
285             }
286              
287             sub call_template {
288 0     0 1   my ($self,$node,$t,$template)=@_;
289              
290 0 0 0       if (defined(my $sub=$template->{testcode})) {
    0 0        
      0        
291 0           return &$sub($node,$t);
292             } elsif (exists $t->{prechild} || exists $t->{prechildren} ||
293             exists $t->{postchild} || exists $t->{postchildren}) {
294 0           warn "XML::XPathScript::Processor::call_template: cannot handle this sort of templates yet";
295             # Attempt to recover
296 0           $t->{pre}="";
297 0           $t->{post}="";
298 0           return 1;
299             } else {
300 0           $t->{pre}=$template->{pre};
301 0           $t->{post}=$template->{post};
302 0           return 1;
303             };
304             }
305              
306             sub _apply_templates {
307 0     0     my $self = shift;
308 0           my $params = pop;
309 22     22   120 no warnings 'uninitialized';
  22         36  
  22         2270  
310 0           return join '', map $self->translate_node($_,$params), @_;
311             }
312              
313             sub is_utf8_tainted {
314 0     0 0   my $self = shift;
315 0           my ($string) = @_;
316              
317 0           my $ghost = ($string x 0) .
318             "ab"; # Very quick and conserves UTF-8 flag (and taintedness)
319              
320 22     22   123 $ghost .= do { use bytes; "\xc3" };
  22         43  
  22         179  
  0            
  0            
321 22     22   1406 $ghost .= do { use bytes; "\xa9" };
  22         45  
  22         90  
  0            
  0            
322 22     22   801 my $charlength = do { no bytes; length($ghost) };
  22         43  
  22         127  
  0            
  0            
323 22     22   997 my $bytelength = do { use bytes; length($ghost) };
  22         41  
  22         87  
  0            
  0            
324              
325 0 0 0       if ($charlength == 3) {
    0 0        
    0          
326             # The two bytes we added got lumped in core into a single
327             # UTF-8 char. This is a Perl bug (arising e.g. because $string
328             # is tainted, see t/04unicode.t) but we recover gracefully.
329 0           return 1;
330             } elsif ($charlength == 4 && $bytelength == 4) {
331 0           return 0;
332             } elsif ($charlength == 4 && $bytelength == 6) {
333 0           return 1; # The bytes were upgraded
334             } else {
335 0           die "is_utf8_tainted assertion check failed".
336             " (charlength = $charlength, bytelength=$bytelength)";
337             }
338             }
339              
340             sub get_xpath_of_node {
341 0     0 1   my $self =shift;
342 0           my $node = shift;
343              
344             # ugly hacks all over in this function, because the quirky
345             # refcount-proof aliasing (i.e. XML::XPath::Element versus
346             # XML::XPath::ElementImpl) in XML::XPath gets in the way badly
347 0 0 0       $node = $$node if $node->isa( 'XML::XPath::Node::Element' )
      0        
348             and not $self->isa( 'XML::XPath::Node::ElementImpl' )
349             and $node =~ /SCALAR/;
350              
351 0 0         my $parent = $node->can("parentNode") ? $node->parentNode()
352             : $node->getParentNode()
353             ;
354              
355 0 0         return "" unless defined $parent;
356              
357 0           my $name;
358 0 0         if ($self->is_element_node($node)) {
    0          
    0          
    0          
359 0           $name = $node->findvalue('name()');
360             } elsif ($self->is_text_node($node)) {
361 0           $name = "text()";
362             } elsif ($self->is_comment_node($node)) {
363 0           $name = "comment()";
364             } elsif ($self->is_pi_node($node)) {
365 0           $name = "processing-instruction()";
366             } else {
367             # YKYBPTMNW...
368 0           return $self->get_xpath_of_node($parent)."/strange-node()";
369             }
370              
371             # ugly hack, part II
372 0 0         my @brothers = map{ ($_->isa( 'XML::XPath::Node::Element' ) ) ? $$_ : $_ } $parent->findnodes("./$name");
  0            
373              
374             # Short-cut for nodes that have an ID. FIXME: not all DTDs use
375             # attribute named "id" as the SGML ID!
376 0 0 0       if ($self->is_element_node($node) && (my $id=$self->findvalue('@id',$node))) {
377 0           return $self->get_xpath_of_node($parent).sprintf('/%s[@id="%s"]', $name, $id);
378             }
379              
380             # Bug: the matches() function from XML::XPath is hosed, and only
381             # works towards ancestors. We resort to comparing references for
382             # identity. See above for details on the $$self quirk.
383 0 0         my $theself=($node =~ m/SCALAR/?$$node:$node);
384              
385 0           for my $i ( 0..$#brothers ) {
386 0           my $thebrother=($brothers[$i] =~ m/SCALAR/?
387 0 0         ${$brothers[$i]}:$brothers[$i]);
388              
389 0 0         return sprintf '%s/%s[%d]', $self->get_xpath_of_node($parent), $name, $i+1
390             if $theself eq $thebrother;
391             };
392              
393 0           return $self->get_xpath_of_node($parent)."/$name"."[?]";
394             }
395              
396              
397             ########################## End of exportable stuff ####################
398              
399             sub translate_node {
400 0     0 0   my( $self, $node, $params ) = @_;
401              
402             my $retval = $self->is_element_node( $node )
403             ? $self->translate_element_node( $node, $params )
404             : $self->is_text_node($node)
405             ? $self->translate_text_node( $node, $params )
406             : $self->is_comment_node($node)
407             ? $self->translate_comment_node( $node, $params )
408             : $self->is_pi_node($node)
409 0 0         ? eval { if ($node->getParentNode->getParentNode) {
  0 0          
    0          
    0          
    0          
410 0           return $node->toString;
411 0           } else { '' } }
412             : $self->to_string( $node )
413             ;
414              
415 0 0 0       if ( $self->{binmode} &&
416             $self->is_utf8_tainted($retval)) {
417 22     22   14458 use Carp qw(confess); # TODO remove this
  22         50  
  22         6182  
418 0           confess("Wrong translation by stylesheet".
419             " (result is Unicode-tainted) at ".$self->get_xpath_of_node($node).
420             "\n$retval\n");
421             }
422              
423 0           return $retval;
424             }
425              
426             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
427              
428             sub translate_text_node {
429 0     0 0   my $self = shift;
430 0           my $node = shift;
431 0           my $params = shift;
432 0           my $translations = $self->{template};
433              
434 0   0       my $trans = $translations->{'#text'} || $translations->{'text()'};
435              
436 0 0         return $node->toString unless $trans;
437              
438 0           my $action = $trans->{action};
439              
440 0           my $t = new XML::XPathScript::Template::Tag;
441 0           $t->{$_} = $trans->{$_} for keys %{$trans};
  0            
442 0 0         if (my $code = $trans->{testcode})
443             {
444 0           $action = $code->( $node, $t, $params );
445             }
446            
447 22     22   135 no warnings 'uninitialized';
  22         44  
  22         10442  
448 0 0 0       return if defined($action) and $action == DO_NOT_PROCESS();
449              
450 0           my $middle;
451 0 0 0       $middle = $node->toString if defined($action)
452             and $action == DO_TEXT_AS_CHILD();
453              
454 0           return $self->_transform_tag( $t->{pre}, $node, $t, $params )
455             . $middle
456             . $self->_transform_tag( $t->{post}, $node, $t, $params );
457             }
458              
459             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
460              
461             sub translate_element_node {
462 0     0 0   my( $self, $node, $params ) = @_;
463 0           my $translations = $self->{template};
464              
465 0           my $node_name = $self->get_node_name( $node );
466              
467 0           my $namespace = $self->get_namespace( $node );
468              
469 0           my $trans = XML::XPathScript::Template::resolve( $translations,
470             $namespace, $node_name );
471              
472 0 0         unless( $trans ) {
473             # no specific and no generic? Okay, okay, return as is...
474 22     22   123 no warnings qw/ uninitialized /;
  22         42  
  22         4342  
475 0           my @kids = $self->get_child_nodes( $node );
476 0           return $self->start_tag($node)
477             . $self->_apply_templates( @kids, $params )
478             . $self->end_tag($node);
479            
480             }
481              
482 0           my $t = new XML::XPathScript::Template::Tag;
483 0           $t->{$_} = $trans->{$_} for keys %{$trans};
  0            
484              
485             # we officially support 'content', but also allow
486             # 'contents'
487 0 0 0       if ( my $content = $trans->{content} || $trans->{contents} ) {
488 0           return $self->_transform_content( $content, $node, $t, $params );
489             }
490              
491             # by default we do the kids
492 0           my $dokids = 1;
493 0           my $search;
494              
495 0           my $action = $trans->{action};
496            
497 0 0         if ($trans->{testcode}) {
498 0           $action = $trans->{testcode}->($node, $t, $params );
499             }
500              
501 22     22   128 no warnings 'uninitialized';
  22         50  
  22         18722  
502 0 0 0       return if $action =~ /^-?\d+$/ and $action == DO_NOT_PROCESS();
503              
504 0 0 0       if( defined( $action) and $action !~ /^-?\d+/ ) {
    0          
505             # ah, an xpath expression
506 0           $dokids = 0;
507 0           $search = $action;
508             }
509             elsif ($action == DO_SELF_ONLY() ) {
510 0           $dokids = 0;
511             }
512              
513 0 0         my @kids = $dokids ? $node->getChildNodes()
    0          
514             : $search ? $node->findnodes($search)
515             : ()
516             ;
517              
518 0           my @args = ( $node, $t, $params );
519              
520 0           my $pre = $self->_transform_tag( $t->{pre}, @args );
521 0 0         $pre .= $self->start_tag( $node , $t->{rename}) if $t->{showtag};
522 0           $pre .= $self->_transform_tag( $t->{intro}, @args );
523 0 0         $pre .= $self->_transform_tag( $t->{prechildren}, @args ) if @kids;
524            
525 0           my $post;
526 0 0         $post .= $self->_transform_tag( $t->{postchildren}, @args ) if @kids;
527 0           $post .= $self->_transform_tag( $t->{extro}, @args );
528 0 0         $post .= $self->end_tag( $node, $t->{rename} ) if $t->{showtag};
529 0           $post .= $self->_transform_tag( $t->{post}, @args );
530              
531 0           my $middle;
532              
533 0           for my $kid ( @kids )
534             {
535 0           my $kid_is_element = $self->is_element_node( $kid );
536              
537 0 0         $middle .= $self->_transform_tag( $trans->{prechild},
538             $kid, $t, $params ) if $kid_is_element;
539              
540 0           $middle .= $self->apply_templates($kid, $params );
541              
542 0 0         $middle .= $self->_transform_tag( $trans->{postchild},
543             $kid, $t, $params ) if $kid_is_element;
544             }
545            
546 0           return $pre . $middle . $post;
547             }
548              
549             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
550              
551             sub _transform_content {
552 0     0     my ( $self, $content, $node, $t, $params ) = @_;
553              
554 0 0         return $content->( $node, $t, $params ) if ref $content eq 'CODE';
555              
556 0           my $interpolated = $self->interpolate( $node, $content );
557              
558 0           local *STDOUT;
559 0           my $output;
560 0 0         open STDOUT, '>', \$output or die "couldn't redirect STDOUT: $!\n";
561              
562 0           my $xps = XML::XPathScript::current();
563              
564 0           my $code = $xps->extract( $interpolated );
565              
566 0           local $self->{dom} = $node;
567              
568 0           eval <<"END_CONTENT";
569             package XML::XPathScript::Template::Content;
570             my \$processor = \$self;
571             my \%params = \%\$params;
572             \$self->import_functional unless exists \&get_template;
573             $code;
574             END_CONTENT
575              
576 0 0         die $@ if $@;
577              
578 0           return $output;
579             }
580              
581             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
582             # bad terminology, here a tag is 'pre', 'post', etc
583              
584             sub _transform_tag {
585 0     0     my ( $self, $tag, $node, $t, $params ) = @_;
586              
587 0 0         return unless $tag;
588              
589 0 0         return $tag->( $node, $t, $params ) if ref $tag eq 'CODE';
590              
591 0           return $self->interpolate( $node, $tag );
592             }
593              
594             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
595              
596             sub translate_comment_node {
597 0     0 0   my ( $self, $node, $params ) = @_;
598 0           my $translations = $self->{template};
599              
600 0   0       my $trans = $translations->{'#comment'} || $translations->{'comment()'};
601              
602 0 0         return $node->toString unless $trans;
603              
604 0           my $middle = $self->get_text_content( $node );
605              
606 0           my $t = new XML::XPathScript::Template::Tag;
607 0           $t->{$_} = $trans->{$_} for keys %{$trans};
  0            
608              
609 0           my $action = $trans->{action};
610              
611 0 0         if (my $code = $trans->{testcode})
612             {
613 0           $action = $code->( $node, $t, $params );
614 0 0 0       if ($action and %$t) {
615 0           foreach my $tkey (keys %$t) {
616 0           $trans->{$tkey} = $t->{$tkey};
617             }
618             }
619             }
620              
621 22     22   137 no warnings 'uninitialized';
  22         42  
  22         10567  
622 0 0 0       return if $action =~ /^-?\d+$/ and $action == $DO_NOT_PROCESS;
623            
624 0 0         $middle = undef if $action == $DO_SELF_ONLY;
625 0           return $self->_transform_tag( $trans->{pre}, $node, $t, $params )
626             . $middle
627             . $self->_transform_tag( $trans->{post}, $node, $t, $params );
628             }
629              
630             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
631              
632             sub start_tag {
633 0     0 0   my( $self, $node, $name ) = @_;
634              
635 0 0 0       $name ||= $self->get_node_name( $node ) or return;
636              
637 0           my $string = '<'.$name;
638              
639             # do we need this for libXML?
640 0 0         if( $self->{parser} eq 'XML::XPath' )
641             {
642 0           $string .= $_->toString for $node->getNamespaceNodes;
643             }
644              
645 0           for my $attr ( $self->get_attributes( $node ) ) {
646 0           $string .= $self->get_attribute( $attr );
647             }
648              
649 0           $string .= '>';
650              
651 0           return $string;
652             }
653              
654             sub end_tag {
655 0     0 0   my $self = shift;
656 0 0 0       if (my $name = $_[1] || $self->get_node_name( $_[0] ) ) {
657 0           return "";
658             }
659 0           return '';
660             }
661              
662             sub interpolate {
663 0     0 0   my ($self, $node, $string) = @_;
664            
665             # if string is empty or no interpolation,
666             # we return
667 0 0 0       return( $string || '' ) unless
      0        
668             defined( $string ) and
669             $self->{is_interpolating};
670              
671 0           my $regex = $self->{interpolation_regex};
672 0           $string =~ s/$regex/ $node->findvalue($1) /egs;
  0            
673            
674 22     22   134 no warnings 'uninitialized';
  22         37  
  22         9068  
675 0           return $string;
676             }
677              
678             'end of module XML::XPathScript::Processor';
679              
680             __END__