File Coverage

blib/lib/SVG/XML.pm
Criterion Covered Total %
statement 73 76 96.0
branch 18 28 64.2
condition 10 15 66.6
subroutine 16 16 100.0
pod 0 13 0.0
total 117 148 79.0


line stmt bran cond sub pod time code
1             package SVG::XML;
2 25     25   167 use strict;
  25         55  
  25         735  
3 25     25   119 use warnings;
  25         42  
  25         1156  
4              
5             our $VERSION = '2.86';
6              
7             =pod
8              
9             =head1 NAME
10              
11             SVG::XML - Handle the XML generation bits for SVG.pm
12              
13             =head1 AUTHOR
14              
15             Ronan Oger, cpan@roitsystems.com
16              
17             =head1 SEE ALSO
18              
19             L,
20             L,
21             L,
22             L,
23             L
24              
25             For Commercial Perl/SVG development, refer to the following sites:
26             L,
27             L,
28             L
29              
30             =cut
31              
32 25     25   167 use Exporter;
  25         44  
  25         38318  
33              
34             our @ISA = ('Exporter');
35              
36             our @EXPORT = qw(
37             xmlesc
38             xmlescape
39             xmlescp
40             cssstyle
41             xmlattrib
42             xmlcomment
43             xmlpi
44             xmltag
45             xmltagopen
46             xmltagclose
47             xmltag_ln
48             xmltagopen_ln
49             xmltagclose_ln
50             processtag
51             xmldecl
52             dtddecl
53             );
54              
55             sub xmlescp {
56 13     13 0 32 my ( $self, $s ) = @_;
57              
58 13 50       48 $s = '0' unless defined $s;
59 13 50       45 $s = join( ', ', @{$s} ) if ( ref($s) eq 'ARRAY' );
  0         0  
60              
61             # Special XML entities are escaped
62 13         39 $s =~ s/&(?!#(x\w\w|\d+?);)/&/g;
63 13         28 $s =~ s/>/>/g;
64 13         25 $s =~ s/
65 13         21 $s =~ s/\"/"/g;
66 13         21 $s =~ s/\'/'/g;
67              
68             # Backtick is just a regular XML citizen
69             #$s=~s/\`/'/g;
70              
71             # Invalid XML characters are removed, not just escaped: \x00-\x08\x0b\x1f
72             # Tabs (\x09) and newlines (\x0a) are valid.
73 13         58 while ( $s =~ s/([\x00-\x08\x0b\x1f])/''/e ) {
  10         29  
74 10         32 my $char = q{'\\x} . sprintf( '%02X', ord($1) ) . q{'};
75 10         21 $self->error( $char => 'This forbidden XML character was removed' );
76             }
77              
78             # Per suggestion from Adam Schneider
79 13         39 $s =~ s/([\200-\377])/'&#'.ord($1).';'/ge;
  0         0  
80              
81 13         44 return $s;
82             }
83              
84             *xmlesc = \&xmlescp;
85              
86             *xmlescape = \&xmlescp;
87              
88             sub cssstyle {
89 5     5 0 27 my %attrs = @_;
90 5         44 return ( join( '; ', map { qq($_: ) . $attrs{$_} } sort keys(%attrs) ) );
  13         64  
91             }
92              
93             # Per suggestion from Adam Schneider
94             sub xmlattrib {
95 85     85 0 251 my %attrs = @_;
96 85 100       294 return '' unless ( scalar( keys %attrs ) );
97             return (
98             ' '
99             . join( ' ',
100 61         284 map { qq($_=") . $attrs{$_} . q(") } sort keys(%attrs) )
  275         901  
101             );
102             }
103              
104             sub xmltag {
105 36     36 0 93 my ( $name, $ns, %attrs ) = @_;
106 36 50       93 $ns = $ns ? "$ns:" : '';
107 36   100     96 my $at = xmlattrib(%attrs) || '';
108 36         175 return qq(<$ns$name$at />);
109             }
110              
111             sub xmltag_ln {
112 36     36 0 107 my ( $name, $ns, %attrs ) = @_;
113 36         110 return xmltag( $name, $ns, %attrs );
114             }
115              
116             sub xmltagopen {
117 49     49 0 125 my ( $name, $ns, %attrs ) = @_;
118 49 50       140 $ns = $ns ? "$ns:" : '';
119 49   100     192 my $at = xmlattrib(%attrs) || '';
120 49         260 return qq(<$ns$name$at>);
121             }
122              
123             sub xmltagopen_ln {
124 49     49 0 174 my ( $name, $ns, %attrs ) = @_;
125 49         189 return xmltagopen( $name, $ns, %attrs );
126             }
127              
128             sub xmlcomment {
129 22     22 0 57 my ( $self, $r_comment ) = @_;
130             my $ind = $self->{-docref}->{-elsep}
131 22         84 . $self->{-docref}->{-indent} x $self->{-docref}->{-level};
132              
133             # If the comment starts with newline character then do not prefix
134             # with space (RT #123896).
135             return (
136             $ind . join(
137             $ind,
138             map {
139 22 50       54 ( (/^\n/) ? (q()) : (q( -->)) );
141             } @$r_comment
142             )
143             );
144             }
145              
146             sub xmlpi {
147 2     2 0 5 my ( $self, $r_pi ) = @_;
148             my $ind = $self->{-docref}->{-elsep}
149 2         7 . $self->{-docref}->{-indent} x $self->{-docref}->{-level};
150 2         5 return ( join( $ind, map {qq()} @$r_pi ) );
  5         18  
151             }
152              
153             *processinginstruction = \&xmlpi;
154              
155             sub xmltagclose {
156 49     49 0 104 my ( $name, $ns ) = @_;
157 49 50       133 $ns = $ns ? "$ns:" : '';
158 49         160 return qq();
159             }
160              
161             sub xmltagclose_ln {
162 49     49 0 127 my ( $name, $ns ) = @_;
163 49         129 return xmltagclose( $name, $ns );
164             }
165              
166             sub dtddecl {
167 26     26 0 74 my $self = shift;
168 26   50     100 my $docroot = $self->{-docroot} || 'svg';
169 26         42 my $id;
170              
171 26 100       79 if ( $self->{-pubid} ) {
    50          
172 25         88 $id = 'PUBLIC "' . $self->{-pubid} . '"';
173 25 50       149 $id .= ' "' . $self->{-sysid} . '"' if ( $self->{-sysid} );
174             }
175             elsif ( $self->{-sysid} ) {
176 1         4 $id = 'SYSTEM "' . $self->{-sysid} . '"';
177             }
178             else {
179             $id
180             = 'PUBLIC "-//W3C//DTD SVG 1.0//EN"'
181             . $self->{-docref}->{-elsep}
182 0         0 . "\"$self->{-docref}->{-dtd}\"";
183             }
184              
185 26         87 my $at = join( ' ', ( $docroot, $id ) );
186              
187             #>>>TBD: add internal() method to return this
188             my $extension
189             = ( exists $self->{-internal} )
190             ? $self->{-internal}->render()
191 26 50       88 : q{};
192 26 100 66     139 if ( exists $self->{-extension} and $self->{-extension} ) {
193             $extension
194             .= $self->{-docref}{-elsep}
195             . $self->{-extension}
196 1         4 . $self->{-docref}{-elsep};
197             }
198 26 100       73 $extension = ' [' . $self->{-docref}{-elsep} . $extension . ']'
199             if $extension;
200              
201 26         142 return qq[$self->{-docref}{-elsep}];
202             }
203              
204             sub xmldecl {
205 21     21 0 41 my $self = shift;
206              
207 21   50     72 my $version = $self->{-version} || '1.0';
208 21   50     72 my $encoding = $self->{-encoding} || 'UTF-8';
209 21   50     63 my $standalone = $self->{-standalone} || 'yes';
210              
211             return
212 21         144 qq{};
213             }
214              
215             #-------------------------------------------------------------------------------
216              
217             1;