File Coverage

blib/lib/SVG/XML.pm
Criterion Covered Total %
statement 76 79 96.2
branch 18 28 64.2
condition 10 15 66.6
subroutine 17 17 100.0
pod 0 13 0.0
total 121 152 79.6


line stmt bran cond sub pod time code
1             package SVG::XML;
2 25     25   164 use strict;
  25         52  
  25         734  
3 25     25   119 use warnings;
  25         47  
  25         1143  
4              
5             our $VERSION = '2.85';
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   173 use Exporter;
  25         52  
  25         1124  
33 25     25   145 use vars qw(@ISA @EXPORT);
  25         51  
  25         38054  
34             @ISA = ('Exporter');
35              
36             @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 34 my ( $self, $s ) = @_;
57              
58 13 50       30 $s = '0' unless defined $s;
59 13 50       47 $s = join( ', ', @{$s} ) if ( ref($s) eq 'ARRAY' );
  0         0  
60              
61             # Special XML entities are escaped
62 13         40 $s =~ s/&(?!#(x\w\w|\d+?);)/&/g;
63 13         25 $s =~ s/>/>/g;
64 13         24 $s =~ s/
65 13         24 $s =~ s/\"/"/g;
66 13         19 $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         60 while ( $s =~ s/([\x00-\x08\x0b\x1f])/''/e ) {
  10         28  
74 10         30 my $char = q{'\\x} . sprintf( '%02X', ord($1) ) . q{'};
75 10         22 $self->error( $char => 'This forbidden XML character was removed' );
76             }
77              
78             # Per suggestion from Adam Schneider
79 13         29 $s =~ s/([\200-\377])/'&#'.ord($1).';'/ge;
  0         0  
80              
81 13         62 return $s;
82             }
83              
84             *xmlesc = \&xmlescp;
85              
86             *xmlescape = \&xmlescp;
87              
88             sub cssstyle {
89 5     5 0 22 my %attrs = @_;
90 5         26 return ( join( '; ', map { qq($_: ) . $attrs{$_} } sort keys(%attrs) ) );
  13         69  
91             }
92              
93             # Per suggestion from Adam Schneider
94             sub xmlattrib {
95 85     85 0 222 my %attrs = @_;
96 85 100       333 return '' unless ( scalar( keys %attrs ) );
97             return (
98             ' '
99             . join( ' ',
100 61         300 map { qq($_=") . $attrs{$_} . q(") } sort keys(%attrs) )
  275         962  
101             );
102             }
103              
104             sub xmltag {
105 36     36 0 99 my ( $name, $ns, %attrs ) = @_;
106 36 50       89 $ns = $ns ? "$ns:" : '';
107 36   100     92 my $at = xmlattrib(%attrs) || '';
108 36         180 return qq(<$ns$name$at />);
109             }
110              
111             sub xmltag_ln {
112 36     36 0 117 my ( $name, $ns, %attrs ) = @_;
113 36         483 return xmltag( $name, $ns, %attrs );
114             }
115              
116             sub xmltagopen {
117 49     49 0 141 my ( $name, $ns, %attrs ) = @_;
118 49 50       152 $ns = $ns ? "$ns:" : '';
119 49   100     180 my $at = xmlattrib(%attrs) || '';
120 49         265 return qq(<$ns$name$at>);
121             }
122              
123             sub xmltagopen_ln {
124 49     49 0 173 my ( $name, $ns, %attrs ) = @_;
125 49         173 return xmltagopen( $name, $ns, %attrs );
126             }
127              
128             sub xmlcomment {
129 22     22 0 61 my ( $self, $r_comment ) = @_;
130             my $ind = $self->{-docref}->{-elsep}
131 22         88 . $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       56 ( (/^\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         6 . $self->{-docref}->{-indent} x $self->{-docref}->{-level};
150 2         7 return ( join( $ind, map {qq()} @$r_pi ) );
  5         17  
151             }
152              
153             *processinginstruction = \&xmlpi;
154              
155             sub xmltagclose {
156 49     49 0 97 my ( $name, $ns ) = @_;
157 49 50       115 $ns = $ns ? "$ns:" : '';
158 49         159 return qq();
159             }
160              
161             sub xmltagclose_ln {
162 49     49 0 120 my ( $name, $ns ) = @_;
163 49         128 return xmltagclose( $name, $ns );
164             }
165              
166             sub dtddecl {
167 26     26 0 72 my $self = shift;
168 26   50     89 my $docroot = $self->{-docroot} || 'svg';
169 26         51 my $id;
170              
171 26 100       91 if ( $self->{-pubid} ) {
    50          
172 25         83 $id = 'PUBLIC "' . $self->{-pubid} . '"';
173 25 50       127 $id .= ' "' . $self->{-sysid} . '"' if ( $self->{-sysid} );
174             }
175             elsif ( $self->{-sysid} ) {
176 1         5 $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         107 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     171 if ( exists $self->{-extension} and $self->{-extension} ) {
193             $extension
194             .= $self->{-docref}{-elsep}
195             . $self->{-extension}
196 1         7 . $self->{-docref}{-elsep};
197             }
198 26 100       62 $extension = ' [' . $self->{-docref}{-elsep} . $extension . ']'
199             if $extension;
200              
201 26         149 return qq[$self->{-docref}{-elsep}];
202             }
203              
204             sub xmldecl {
205 21     21 0 43 my $self = shift;
206              
207 21   50     82 my $version = $self->{-version} || '1.0';
208 21   50     89 my $encoding = $self->{-encoding} || 'UTF-8';
209 21   50     91 my $standalone = $self->{-standalone} || 'yes';
210              
211             return
212 21         131 qq{};
213             }
214              
215             #-------------------------------------------------------------------------------
216              
217             1;