File Coverage

blib/lib/Data/DumpXML.pm
Criterion Covered Total %
statement 94 105 89.5
branch 34 54 62.9
condition 5 9 55.5
subroutine 11 12 91.6
pod 0 5 0.0
total 144 185 77.8


line stmt bran cond sub pod time code
1             package Data::DumpXML;
2              
3 2     2   1409 use strict;
  2         3  
  2         77  
4 2     2   11 use vars qw(@EXPORT_OK $VERSION);
  2         3  
  2         240  
5              
6             require Exporter;
7             *import = \&Exporter::import;
8             @EXPORT_OK=qw(dump_xml dump_xml2 dump);
9              
10             $VERSION = "1.06"; # $Date: 2003/12/18 09:18:27 $
11              
12             # configuration
13 2     2   11 use vars qw($INDENT $INDENT_STYLE $XML_DECL $CPAN $NAMESPACE $NS_PREFIX $SCHEMA_LOCATION $DTD_LOCATION);
  2         12  
  2         383  
14             $INDENT_STYLE = "XML" unless defined $INDENT_STYLE;
15             $XML_DECL = 1 unless defined $XML_DECL;
16             $INDENT = " " unless defined $INDENT;
17             $CPAN = "http://www.cpan.org/modules/by-authors/Gisle_Aas/" unless defined $CPAN;
18             $NAMESPACE = $CPAN . "Data-DumpXML-1.05.xsd" unless defined $NAMESPACE;
19             $NS_PREFIX = "" unless defined $NS_PREFIX;
20             $SCHEMA_LOCATION = "" unless defined $SCHEMA_LOCATION;
21             $DTD_LOCATION = $CPAN . "Data-DumpXML-1.04.dtd" unless defined $DTD_LOCATION;
22              
23             # other globals
24 2     2   10 use vars qw($NL);
  2         2  
  2         74  
25              
26              
27 2     2   3472 use overload ();
  2         16890  
  2         62  
28 2     2   20 use vars qw(%seen %ref $count $prefix);
  2         5  
  2         5557  
29              
30             sub dump_xml2 {
31 0     0 0 0 local $DTD_LOCATION = "";
32 0         0 local $XML_DECL = "";
33 0         0 dump_xml(@_);
34             }
35              
36             sub dump_xml {
37 6     6 0 219 local %seen;
38 6         8 local %ref;
39 6         9 local $count = 0;
40 6 50 33     27 local $prefix = ($NAMESPACE && $NS_PREFIX) ? "$NS_PREFIX:" : "";
41              
42 6 50       13 local $NL = ($INDENT) ? "\n" : "";
43              
44 6         9 my $out = "";
45 6 50       18 $out .= qq(\n) if $XML_DECL;
46 6 50       21 $out .= qq(\n) if $DTD_LOCATION;
47              
48 6         10 $out .= "<${prefix}data";
49 6 50       25 $out .= " " . ($NS_PREFIX ? "xmlns:$NS_PREFIX" : "xmlns") . qq(="$NAMESPACE")
    50          
50             if $NAMESPACE;
51 6 50       14 $out .= qq( xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="$SCHEMA_LOCATION")
52             if $SCHEMA_LOCATION;
53              
54 6         8 $out .= ">";
55 6         16 $out .= format_list(map _dump($_), @_);
56 6         11 $out .= "\n";
57              
58 6         7 $count = 0;
59 6 100       25 $out =~ s/\01/$ref{++$count} ? qq( id="r$ref{$count}") : ""/ge;
  22         84  
60              
61 6 50       14 print STDERR $out unless defined wantarray;
62 6         38 $out;
63             }
64              
65             *dump = \&dump_xml;
66              
67             sub _dump {
68 23     23   44 my $rval = \$_[0]; shift;
  23         25  
69 23         27 my $deref = shift;
70 23 100       39 $rval = $$rval if $deref;
71              
72 23         23 my($class, $type, $id);
73 23 50       53 if (overload::StrVal($rval) =~ /^(?:([^=]+)=)?([A-Z]+)\(0x([^\)]+)\)$/) {
74 23         192 $class = $1;
75 23         31 $type = $2;
76 23         39 $id = $3;
77             } else {
78 0         0 return qq();
79             }
80              
81 23 100       60 if (my $seq = $seen{$id}) {
82 1   33     12 my $ref_no = $ref{$seq} || ($ref{$seq} = keys(%ref) + 1);
83 1         6 return qq(<${prefix}alias ref="r$ref_no"/>);
84             }
85 22         43 $seen{$id} = ++$count;
86              
87 22 100       39 $class = $class ? " class=" . quote($class) : "";
88 22         26 $id = "\1"; # magic that is removed or expanded to ' id="r1"' in the end.
89              
90 22 100 100     85 if ($type eq "SCALAR" || $type eq "REF") {
    100          
    50          
    0          
    0          
91 18 100       39 return "<${prefix}undef$class$id/>"
92             unless defined $$rval;
93 17 100       76 return "<${prefix}ref$class$id>" . format_list(_dump($$rval, 1)) . ""
94             if ref $$rval;
95 9         18 my($str, $enc) = esc($$rval);
96 9         54 return "<${prefix}str$class$id$enc>$str";
97             }
98             elsif ($type eq "ARRAY") {
99 2 50       9 return "<${prefix}array$class$id/>" unless @$rval;
100 2         9 return "<${prefix}array$class$id>" . format_list(map _dump($_), @$rval) .
101             "";
102             }
103             elsif ($type eq "HASH") {
104 2         6 my $out = "<${prefix}hash$class$id>$NL";
105 2         12 for my $key (sort keys %$rval) {
106 2         3 my $val = \$rval->{$key};
107 2         10 $val = _dump($$val);
108 2 50       7 if ($INDENT) {
109 2         21 $val =~ s/^/$INDENT$INDENT/gm;
110 2         5 $out .= $INDENT;
111             }
112 2         5 my($str, $enc) = esc($key);
113 2         14 $out .= "<${prefix}key$enc>$str$NL$val$NL";
114             }
115 2 50       8 if ($INDENT_STYLE eq "Lisp") {
116             # kill final NL
117 0         0 substr($out, -length($NL)) = "";
118             }
119 2         3 $out .= "";
120 2         7 return $out;
121             }
122             elsif ($type eq "GLOB") {
123 0         0 return "<${prefix}glob$class$id/>";
124             }
125             elsif ($type eq "CODE") {
126 0         0 return "<${prefix}code$class$id/>";
127             }
128             else {
129             #warn "Can't handle $type data";
130 0         0 return "";
131             }
132 0         0 die "Assert";
133             }
134              
135             sub format_list {
136 16     16 0 50 my @elem = @_;
137 16 50       32 if ($INDENT) {
138 16         28 for (@elem) { s/^/$INDENT/gm; }
  21         140  
139             }
140 16 50       109 return join($NL, "", @elem, ($INDENT_STYLE eq "Lisp" ? () : ("")) );
141             }
142              
143             # put a string value in double quotes
144             sub quote {
145 3     3 0 5 local($_) = shift;
146 3         6 s/&/&/g;
147 3         4 s/\"/"/g;
148 3         4 s/]]>/]]>/g;
149 3         4 s/
150 3         5 s/([^\040-\176])/sprintf("&#x%x;", ord($1))/ge;
  0         0  
151 3         9 return qq("$_");
152             }
153              
154             sub esc {
155 11     11 0 29 local($_) = shift;
156 11 100       33 if (/[\x00-\x08\x0B\x0C\x0E-\x1F\x7f-\xff]/) {
157             # \x00-\x08\x0B\x0C\x0E-\x1F these chars can't be represented in XML at all
158             # \x7f is special
159             # \x80-\xff will be mangled into UTF-8
160 2         1099 require MIME::Base64;
161 2 50       910 my $nl = (length($_) < 40) ? "" : $NL;
162 2         11 my $b64 = MIME::Base64::encode($_, $nl);
163 2         8 return $nl.$b64, qq( encoding="base64");
164             }
165              
166 9         15 s/&/&/g;
167 9         13 s/
168 9         11 s/]]>/]]>/g;
169 9         16 s/([^\040-\176])/sprintf("&#x%x;", ord($1))/ge;
  0         0  
170 9         25 return $_, "";
171             }
172              
173             1;
174              
175             __END__