File Coverage

blib/lib/XML/Atom/Syndication/Writer.pm
Criterion Covered Total %
statement 57 62 91.9
branch 13 20 65.0
condition 4 9 44.4
subroutine 11 13 84.6
pod 6 8 75.0
total 91 112 81.2


line stmt bran cond sub pod time code
1             package XML::Atom::Syndication::Writer;
2 22     22   111 use strict;
  22         41  
  22         901  
3              
4 22     22   135 use base qw( Class::ErrorHandler );
  22         51  
  22         2289  
5              
6 22     22   40471 use XML::Writer;
  22         494911  
  22         1207  
7 22     22   321 use XML::Elemental::Util qw( process_name );
  22         54  
  22         29620  
8              
9             my %NSPrefix = ( # default prefix table.
10             # '' => "http://www.w3.org/2005/Atom",
11             dc => "http://purl.org/dc/elements/1.1/",
12             dcterms => "http://purl.org/dc/terms/",
13             sy => "http://purl.org/rss/1.0/modules/syndication/",
14             trackback => "http://madskills.com/public/xml/rss/module/trackback/",
15             xhtml => "http://www.w3.org/1999/xhtml",
16             xml => "http://www.w3.org/XML/1998/namespace"
17             );
18              
19             sub new {
20 23     23 1 58 my $class = shift;
21 23         82 my $self = bless {}, $class;
22 23         111 $self->init(@_);
23             }
24              
25             sub init {
26 23     23 0 228 my %nsp = %NSPrefix; # clone
27 23         166 $_[0]->{__PREFIX} = \%nsp;
28 23         274 $_[0]->{__NS} = {reverse %nsp};
29 23         100 $_[0];
30             }
31              
32             sub set_prefix {
33 23     23 1 85 $_[0]->{__NS}->{$_[2]} = $_[1];
34 23         115 $_[0]->{__PREFIX}->{$_[1]} = $_[2];
35             }
36              
37 0     0 1 0 sub get_prefix { $_[0]->{__NS}->{$_[1]} }
38 0     0 1 0 sub get_namespace { $_[0]->{__PREFIX}->{$_[1]} }
39              
40             sub no_cdata {
41 14 50   14 1 48 if (defined $_[1]) {
42 14 50       70 $_[0]->{__NO_CDATA} = $_[1] ? 1 : 0;
43             }
44 14         44 $_[0]->{__NO_CDATA};
45             }
46              
47             sub as_xml {
48 32     32 1 62 my ($self, $node, $is_full) = @_;
49 32         53 my $xml = '';
50 32         51 my $w;
51 32 100       87 if ($is_full) { # full doc
52 6         26 my ($name, $ns) = process_name($node->name);
53 6         172 $w = XML::Writer->new(
54             OUTPUT => \$xml,
55             UNSAFE => 1, # consequence of not using buggy characters method
56             NAMESPACES => 1,
57             PREFIX_MAP => $self->{__NS}, # FORCED_NS_DECLS => [ $ns ]
58             );
59 6         2467 $w->xmlDecl('utf-8');
60             } else { # fragment
61 26         187 $w = XML::Writer->new(OUTPUT => \$xml, UNSAFE => 1);
62             }
63 32         7408 my $dumper;
64             $dumper = sub {
65 83     83   556 my $node = shift;
66 83 100       379 return encode_xml($w, $node->data, $self->{__NO_CDATA})
67             if (ref $node eq 'XML::Elemental::Characters');
68 30         108 my ($name, $ns) =
69             process_name($node->name); # it must be an element then.
70 30 100       536 my $tag = $is_full ? [$ns, $name] : $name;
71 30         44 my @attr;
72 30         92 my $a = $node->attributes;
73 30         250 my $children = $node->contents;
74 30         256 foreach (keys %$a) {
75 6         18 my ($aname, $ans) = process_name($_);
76             next
77 6 50 33     103 if ( $ans eq 'http://www.w3.org/2000/xmlns/'
78             || $aname eq 'xmlns');
79 0 0 0     0 my $key = $is_full && $ans ? [$ans, $aname] : $aname;
80 0         0 push @attr, $key, $a->{$_};
81             }
82 30 50       129 if (@$children) {
83 30         171 $w->startTag($tag, @attr);
84 30         2033 $dumper->($_) for @$children;
85 30         446 $w->endTag($tag);
86             } else {
87 0         0 $w->emptyTag($tag, @attr);
88             }
89 32         209 };
90 32         98 $dumper->($node);
91              
92             # $w->end; # this adds a character return we don't want.
93 32         1073 $xml;
94             }
95              
96             my %Map = (
97             '&' => '&',
98             '"' => '"',
99             '<' => '<',
100             '>' => '>',
101             '\'' => '''
102             );
103             my $RE = join '|', keys %Map;
104              
105             sub encode_xml
106             { # XML::Writer::character encoding is wrong so we handle this ourselves.
107 53     53 0 433 my ($w, $str, $nocdata) = @_;
108 53 50       136 return '' unless defined $str;
109 53 100 100     306 if (
110             !$nocdata
111             && $str =~ m/
112             <[^>]+> ## HTML markup
113             | ## or
114             &(?:(?!(\#([0-9]+)|\#x([0-9a-fA-F]+))).*?);
115             ## something that looks like an HTML entity.
116             /x
117             ) {
118             ## If ]]> exists in the string, encode the > to >.
119 1         6 $str =~ s/]]>/]]>/g;
120 1         4 $str = '';
121             } else {
122 52         808 $str =~ s!($RE)!$Map{$1}!g;
123             }
124 53         207 $w->raw($str); # forces UNSAFE mode at all times.
125             }
126              
127             1;
128              
129             __END__