File Coverage

blib/lib/XML/XOXO/Node.pm
Criterion Covered Total %
statement 6 69 8.7
branch 0 20 0.0
condition 0 12 0.0
subroutine 2 11 18.1
pod 7 9 77.7
total 15 121 12.4


line stmt bran cond sub pod time code
1             package XML::XOXO::Node;
2 1     1   4 use strict;
  1         2  
  1         173  
3             use Class::XPath 1.4
4             get_name => 'name',
5             get_parent => 'parent',
6             get_root => 'root',
7 0 0         get_children => sub { $_[0]->contents ? @{ $_[0]->contents } : () },
  0            
8 0           get_attr_names => sub { keys %{ $_[0]->attributes } },
  0            
9 0 0         get_attr_value => sub { $_[0]->attributes->{ $_[1] } || '' },
10 1     1   963 get_content => sub { $_[0]->attributes->{text} };
  1         3235  
  1         15  
  0            
11              
12             sub new {
13 0     0 1   my $self = bless {}, $_[0];
14 0           $self->{attributes} = {};
15 0           $self->{contents} = [];
16 0           $self;
17             }
18              
19 0     0 1   sub name { my $this = shift; $this->stash( 'name', @_ ); }
  0            
20 0     0 1   sub parent { my $this = shift; $this->stash( 'parent', @_ ); }
  0            
21 0     0 1   sub contents { my $this = shift; $this->stash( 'contents', @_ ); }
  0            
22 0     0 1   sub attributes { my $this = shift; $this->stash( 'attributes', @_ ); }
  0            
23              
24             sub root {
25 0     0 1   my $e = shift;
26 0   0       while ( $e->can('parent') && $e->parent ) { $e = $e->parent }
  0            
27 0           $e;
28             }
29              
30             sub stash {
31 0 0   0 0   $_[0]->{ $_[1] } = $_[2] if defined $_[2];
32 0           $_[0]->{ $_[1] };
33             }
34              
35             #--- output
36              
37             sub as_xml {
38 0     0 1   my $this = shift;
39 0   0       my $node = shift || $this;
40 0 0         die 'A node is required when invoking as_xml as a class method.'
41             unless ref($node);
42 0           my $name = $node->name;
43 0           my $a = \%{ $node->attributes }; # cloned.
  0            
44 0           my $children = $node->contents;
45 0           my $out = "<$name>\n";
46              
47             # special attributes
48 0   0       my $text = $a->{text} || $a->{title} || $a->{url};
49 0           delete $a->{text};
50 0           my $aa = '';
51 0 0         if ( exists $a->{url} ) {
52 0           $a->{href} = $a->{url};
53 0           delete $a->{url};
54             }
55 0           map { $aa .= " $_=\"" . encode_xml( $a->{$_}, 1 ) . "\""; delete $a->{$_}; }
  0            
  0            
56 0           grep { exists $a->{$_} } qw( href title rel type );
57 0 0         if ( length($aa) ) {
58 0           $text = encode_xml( $text, 1 );
59 0           $out .= "$text\n";
60             }
61              
62             # extended (including multi-valued) attributes
63 0           my $cout = '';
64 0           foreach ( sort keys %$a ) {
65 0           $cout .= '
' . encode_xml($_) . "
\n";
66 0           $cout .= '
';
67 0 0         $cout .=
68             ref( $a->{$_} )
69             ? "\n" . $this->as_xml( $a->{$_} )
70             : encode_xml( $a->{$_}, 1 );
71 0           $cout .= "\n";
72             }
73 0 0         $out .= "
\n" . $cout . "
\n" if length($cout);
74              
75             # children elements
76 0           map { $out .= $this->as_xml($_) } @$children;
  0            
77 0           $out .= "\n";
78 0           $out;
79             }
80              
81             my %Map = (
82             '&' => '&',
83             '"' => '"',
84             '<' => '<',
85             '>' => '>',
86             '\'' => '''
87             );
88             my $RE = join '|', keys %Map;
89              
90             sub encode_xml {
91 0     0 0   my ( $str, $nocdata ) = @_;
92 0 0         return unless defined($str);
93 0 0 0       if (
94             !$nocdata
95             && $str =~ m/
96             <[^>]+> ## HTML markup
97             | ## or
98             &(?:(?!(\#([0-9]+)|\#x([0-9a-fA-F]+))).*?);
99             ## something that looks like an HTML entity.
100             /x
101             ) {
102             ## If ]]> exists in the string, encode the > to >.
103 0           $str =~ s/]]>/]]>/g;
104 0           $str = '';
105             } else {
106 0           $str =~ s!($RE)!$Map{$1}!g;
107             }
108 0           $str;
109             }
110              
111             *query = \&match;
112              
113             1;
114              
115             __END__