File | /usr/local/lib/perl5/site_perl/5.10.1/XML/SAX.pm |
Statements Executed | 271 |
Statement Execution Time | 12.2ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 9.71ms | 10.4ms | load_parsers | XML::SAX::
1 | 1 | 1 | 3.42ms | 46.5ms | BEGIN@18 | XML::SAX::
1 | 1 | 1 | 219µs | 403µs | _parse_ini_file | XML::SAX::
41 | 1 | 1 | 175µs | 10.6ms | parsers | XML::SAX::
36 | 3 | 2 | 89µs | 89µs | CORE:subst (opcode) | XML::SAX::
25 | 2 | 2 | 62µs | 62µs | CORE:match (opcode) | XML::SAX::
1 | 1 | 2 | 57µs | 57µs | CORE:open (opcode) | XML::SAX::
13 | 1 | 2 | 33µs | 33µs | CORE:readline (opcode) | XML::SAX::
1 | 1 | 1 | 24µs | 31µs | BEGIN@5 | XML::SAX::
1 | 1 | 1 | 21µs | 88µs | BEGIN@6 | XML::SAX::
1 | 1 | 1 | 21µs | 116µs | BEGIN@20 | XML::SAX::
1 | 1 | 1 | 20µs | 95µs | BEGIN@15 | XML::SAX::
1 | 1 | 1 | 12µs | 61µs | BEGIN@22 | XML::SAX::
1 | 1 | 1 | 12µs | 59µs | BEGIN@23 | XML::SAX::
1 | 1 | 1 | 11µs | 43µs | BEGIN@17 | XML::SAX::
1 | 1 | 1 | 6µs | 6µs | BEGIN@10 | XML::SAX::
1 | 1 | 1 | 5µs | 5µs | BEGIN@16 | XML::SAX::
0 | 0 | 0 | 0s | 0s | add_parser | XML::SAX::
0 | 0 | 0 | 0s | 0s | do_warn | XML::SAX::
0 | 0 | 0 | 0s | 0s | remove_parser | XML::SAX::
0 | 0 | 0 | 0s | 0s | save_parsers | XML::SAX::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # $Id: SAX.pm,v 1.31 2008-08-05 12:36:24 grant Exp $ | ||||
2 | |||||
3 | package XML::SAX; | ||||
4 | |||||
5 | 3 | 40µs | 2 | 38µs | # spent 31µs (24+7) within XML::SAX::BEGIN@5 which was called
# once (24µs+7µs) by XML::Simple::build_tree at line 5 # spent 31µs making 1 call to XML::SAX::BEGIN@5
# spent 7µs making 1 call to strict::import |
6 | 3 | 48µs | 2 | 156µs | # spent 88µs (21+67) within XML::SAX::BEGIN@6 which was called
# once (21µs+67µs) by XML::Simple::build_tree at line 6 # spent 88µs making 1 call to XML::SAX::BEGIN@6
# spent 67µs making 1 call to vars::import |
7 | |||||
8 | 1 | 900ns | $VERSION = '0.96'; | ||
9 | |||||
10 | 3 | 53µs | 1 | 6µs | # spent 6µs within XML::SAX::BEGIN@10 which was called
# once (6µs+0s) by XML::Simple::build_tree at line 10 # spent 6µs making 1 call to XML::SAX::BEGIN@10 |
11 | 1 | 14µs | @ISA = ('Exporter'); | ||
12 | |||||
13 | 1 | 1µs | @EXPORT_OK = qw(Namespaces Validation); | ||
14 | |||||
15 | 3 | 40µs | 2 | 170µs | # spent 95µs (20+75) within XML::SAX::BEGIN@15 which was called
# once (20µs+75µs) by XML::Simple::build_tree at line 15 # spent 95µs making 1 call to XML::SAX::BEGIN@15
# spent 75µs making 1 call to Exporter::import |
16 | 3 | 27µs | 1 | 5µs | # spent 5µs within XML::SAX::BEGIN@16 which was called
# once (5µs+0s) by XML::Simple::build_tree at line 16 # spent 5µs making 1 call to XML::SAX::BEGIN@16 |
17 | 3 | 29µs | 2 | 75µs | # spent 43µs (11+32) within XML::SAX::BEGIN@17 which was called
# once (11µs+32µs) by XML::Simple::build_tree at line 17 # spent 43µs making 1 call to XML::SAX::BEGIN@17
# spent 32µs making 1 call to Exporter::import |
18 | 3 | 203µs | 1 | 46.5ms | # spent 46.5ms (3.42+43.0) within XML::SAX::BEGIN@18 which was called
# once (3.42ms+43.0ms) by XML::Simple::build_tree at line 18 # spent 46.5ms making 1 call to XML::SAX::BEGIN@18 |
19 | |||||
20 | 3 | 56µs | 2 | 210µs | # spent 116µs (21+95) within XML::SAX::BEGIN@20 which was called
# once (21µs+95µs) by XML::Simple::build_tree at line 20 # spent 116µs making 1 call to XML::SAX::BEGIN@20
# spent 95µs making 1 call to constant::import |
21 | |||||
22 | 3 | 47µs | 2 | 110µs | # spent 61µs (12+49) within XML::SAX::BEGIN@22 which was called
# once (12µs+49µs) by XML::Simple::build_tree at line 22 # spent 61µs making 1 call to XML::SAX::BEGIN@22
# spent 49µs making 1 call to constant::import |
23 | 3 | 1.26ms | 2 | 106µs | # spent 59µs (12+47) within XML::SAX::BEGIN@23 which was called
# once (12µs+47µs) by XML::Simple::build_tree at line 23 # spent 59µs making 1 call to XML::SAX::BEGIN@23
# spent 47µs making 1 call to constant::import |
24 | |||||
25 | 1 | 400ns | my $known_parsers = undef; | ||
26 | |||||
27 | # load_parsers takes the ParserDetails.ini file out of the same directory | ||||
28 | # that XML::SAX is in, and looks at it. Format in POD below | ||||
29 | |||||
30 | =begin EXAMPLE | ||||
31 | |||||
32 | [XML::SAX::PurePerl] | ||||
33 | http://xml.org/sax/features/namespaces = 1 | ||||
34 | http://xml.org/sax/features/validation = 0 | ||||
35 | # a comment | ||||
36 | |||||
37 | # blank lines ignored | ||||
38 | |||||
39 | [XML::SAX::AnotherParser] | ||||
40 | http://xml.org/sax/features/namespaces = 0 | ||||
41 | http://xml.org/sax/features/validation = 1 | ||||
42 | |||||
43 | =end EXAMPLE | ||||
44 | |||||
45 | =cut | ||||
46 | |||||
47 | # spent 10.4ms (9.71+674µs) within XML::SAX::load_parsers which was called
# once (9.71ms+674µs) by XML::SAX::parsers at line 114 | ||||
48 | 8 | 9.76ms | my $class = shift; | ||
49 | my $dir = shift; | ||||
50 | |||||
51 | # reset parsers | ||||
52 | $known_parsers = []; | ||||
53 | |||||
54 | # get directory from wherever XML::SAX is installed | ||||
55 | 2 | 4µs | if (!$dir) { | ||
56 | $dir = $INC{'XML/SAX.pm'}; | ||||
57 | $dir = dirname($dir); # spent 117µs making 1 call to File::Basename::dirname | ||||
58 | } | ||||
59 | |||||
60 | my $fh = gensym(); # spent 13µs making 1 call to Symbol::gensym | ||||
61 | if (!open($fh, File::Spec->catfile($dir, "SAX", PARSER_DETAILS))) { # spent 84µs making 1 call to File::Spec::Unix::catfile
# spent 57µs making 1 call to XML::SAX::CORE:open | ||||
62 | XML::SAX->do_warn("could not find " . PARSER_DETAILS . " in $dir/SAX\n"); | ||||
63 | return $class; | ||||
64 | } | ||||
65 | |||||
66 | $known_parsers = $class->_parse_ini_file($fh); # spent 403µs making 1 call to XML::SAX::_parse_ini_file | ||||
67 | |||||
68 | return $class; | ||||
69 | } | ||||
70 | |||||
71 | # spent 403µs (219+184) within XML::SAX::_parse_ini_file which was called
# once (219µs+184µs) by XML::SAX::load_parsers at line 66 | ||||
72 | 6 | 39µs | my $class = shift; | ||
73 | my ($fh) = @_; | ||||
74 | |||||
75 | my @config; | ||||
76 | |||||
77 | my $lineno = 0; | ||||
78 | 80 | 282µs | 13 | 33µs | while (defined(my $line = <$fh>)) { # spent 33µs making 13 calls to XML::SAX::CORE:readline, avg 3µs/call |
79 | 1 | 41µs | $lineno++; | ||
80 | my $original = $line; | ||||
81 | # strip whitespace | ||||
82 | $line =~ s/\s*$//m; # spent 74µs making 12 calls to XML::SAX::CORE:subst, avg 6µs/call | ||||
83 | $line =~ s/^\s*//m; # spent 8µs making 12 calls to XML::SAX::CORE:subst, avg 700ns/call | ||||
84 | # strip comments | ||||
85 | $line =~ s/[#;].*$//m; # spent 7µs making 12 calls to XML::SAX::CORE:subst, avg 575ns/call | ||||
86 | # ignore blanks | ||||
87 | next if $line =~ /^$/m; # spent 8µs making 12 calls to XML::SAX::CORE:match, avg 625ns/call | ||||
88 | |||||
89 | # heading | ||||
90 | 16 | 32µs | 13 | 54µs | if ($line =~ /^\[\s*(.*)\s*\]$/m) { # spent 54µs making 13 calls to XML::SAX::CORE:match, avg 4µs/call |
91 | push @config, { Name => $1 }; | ||||
92 | next; | ||||
93 | } | ||||
94 | |||||
95 | # instruction | ||||
96 | elsif ($line =~ /^(.*?)\s*?=\s*(.*)$/) { | ||||
97 | unless(@config) { | ||||
98 | push @config, { Name => '' }; | ||||
99 | } | ||||
100 | $config[-1]{Features}{$1} = $2; | ||||
101 | } | ||||
102 | |||||
103 | # not whitespace, comment, or instruction | ||||
104 | else { | ||||
105 | die "Invalid line in ini: $lineno\n>>> $original\n"; | ||||
106 | } | ||||
107 | } | ||||
108 | |||||
109 | return \@config; | ||||
110 | } | ||||
111 | |||||
112 | # spent 10.6ms (175µs+10.4) within XML::SAX::parsers which was called 41 times, avg 257µs/call:
# 41 times (175µs+10.4ms) by XML::SAX::ParserFactory::new at line 18 of XML/SAX/ParserFactory.pm, avg 257µs/call | ||||
113 | 123 | 242µs | my $class = shift; | ||
114 | if (!$known_parsers) { # spent 10.4ms making 1 call to XML::SAX::load_parsers | ||||
115 | $class->load_parsers(); | ||||
116 | } | ||||
117 | return $known_parsers; | ||||
118 | } | ||||
119 | |||||
120 | sub remove_parser { | ||||
121 | my $class = shift; | ||||
122 | my ($parser_module) = @_; | ||||
123 | |||||
124 | if (!$known_parsers) { | ||||
125 | $class->load_parsers(); | ||||
126 | } | ||||
127 | |||||
128 | @$known_parsers = grep { $_->{Name} ne $parser_module } @$known_parsers; | ||||
129 | |||||
130 | return $class; | ||||
131 | } | ||||
132 | |||||
133 | sub add_parser { | ||||
134 | my $class = shift; | ||||
135 | my ($parser_module) = @_; | ||||
136 | |||||
137 | if (!$known_parsers) { | ||||
138 | $class->load_parsers(); | ||||
139 | } | ||||
140 | |||||
141 | # first load module, then query features, then push onto known_parsers, | ||||
142 | |||||
143 | my $parser_file = $parser_module; | ||||
144 | $parser_file =~ s/::/\//g; | ||||
145 | $parser_file .= ".pm"; | ||||
146 | |||||
147 | require $parser_file; | ||||
148 | |||||
149 | my @features = $parser_module->supported_features(); | ||||
150 | |||||
151 | my $new = { Name => $parser_module }; | ||||
152 | foreach my $feature (@features) { | ||||
153 | $new->{Features}{$feature} = 1; | ||||
154 | } | ||||
155 | |||||
156 | # If exists in list already, move to end. | ||||
157 | my $done = 0; | ||||
158 | my $pos = undef; | ||||
159 | for (my $i = 0; $i < @$known_parsers; $i++) { | ||||
160 | my $p = $known_parsers->[$i]; | ||||
161 | if ($p->{Name} eq $parser_module) { | ||||
162 | $pos = $i; | ||||
163 | } | ||||
164 | } | ||||
165 | if (defined $pos) { | ||||
166 | splice(@$known_parsers, $pos, 1); | ||||
167 | push @$known_parsers, $new; | ||||
168 | $done++; | ||||
169 | } | ||||
170 | |||||
171 | # Otherwise (not in list), add at end of list. | ||||
172 | if (!$done) { | ||||
173 | push @$known_parsers, $new; | ||||
174 | } | ||||
175 | |||||
176 | return $class; | ||||
177 | } | ||||
178 | |||||
179 | sub save_parsers { | ||||
180 | my $class = shift; | ||||
181 | |||||
182 | # get directory from wherever XML::SAX is installed | ||||
183 | my $dir = $INC{'XML/SAX.pm'}; | ||||
184 | $dir = dirname($dir); | ||||
185 | |||||
186 | my $file = File::Spec->catfile($dir, "SAX", PARSER_DETAILS); | ||||
187 | chmod 0644, $file; | ||||
188 | unlink($file); | ||||
189 | |||||
190 | my $fh = gensym(); | ||||
191 | open($fh, ">$file") || | ||||
192 | die "Cannot write to $file: $!"; | ||||
193 | |||||
194 | foreach my $p (@$known_parsers) { | ||||
195 | print $fh "[$p->{Name}]\n"; | ||||
196 | foreach my $key (keys %{$p->{Features}}) { | ||||
197 | print $fh "$key = $p->{Features}{$key}\n"; | ||||
198 | } | ||||
199 | print $fh "\n"; | ||||
200 | } | ||||
201 | |||||
202 | print $fh "\n"; | ||||
203 | |||||
204 | close $fh; | ||||
205 | |||||
206 | return $class; | ||||
207 | } | ||||
208 | |||||
209 | sub do_warn { | ||||
210 | my $class = shift; | ||||
211 | # Don't output warnings if running under Test::Harness | ||||
212 | warn(@_) unless $ENV{HARNESS_ACTIVE}; | ||||
213 | } | ||||
214 | |||||
215 | 1 | 11µs | 1; | ||
216 | __END__ | ||||
217 | |||||
218 | =head1 NAME | ||||
219 | |||||
220 | XML::SAX - Simple API for XML | ||||
221 | |||||
222 | =head1 SYNOPSIS | ||||
223 | |||||
224 | use XML::SAX; | ||||
225 | |||||
226 | # get a list of known parsers | ||||
227 | my $parsers = XML::SAX->parsers(); | ||||
228 | |||||
229 | # add/update a parser | ||||
230 | XML::SAX->add_parser(q(XML::SAX::PurePerl)); | ||||
231 | |||||
232 | # remove parser | ||||
233 | XML::SAX->remove_parser(q(XML::SAX::Foodelberry)); | ||||
234 | |||||
235 | # save parsers | ||||
236 | XML::SAX->save_parsers(); | ||||
237 | |||||
238 | =head1 DESCRIPTION | ||||
239 | |||||
240 | XML::SAX is a SAX parser access API for Perl. It includes classes | ||||
241 | and APIs required for implementing SAX drivers, along with a factory | ||||
242 | class for returning any SAX parser installed on the user's system. | ||||
243 | |||||
244 | =head1 USING A SAX2 PARSER | ||||
245 | |||||
246 | The factory class is XML::SAX::ParserFactory. Please see the | ||||
247 | documentation of that module for how to instantiate a SAX parser: | ||||
248 | L<XML::SAX::ParserFactory>. However if you don't want to load up | ||||
249 | another manual page, here's a short synopsis: | ||||
250 | |||||
251 | use XML::SAX::ParserFactory; | ||||
252 | use XML::SAX::XYZHandler; | ||||
253 | my $handler = XML::SAX::XYZHandler->new(); | ||||
254 | my $p = XML::SAX::ParserFactory->parser(Handler => $handler); | ||||
255 | $p->parse_uri("foo.xml"); | ||||
256 | # or $p->parse_string("<foo/>") or $p->parse_file($fh); | ||||
257 | |||||
258 | This will automatically load a SAX2 parser (defaulting to | ||||
259 | XML::SAX::PurePerl if no others are found) and return it to you. | ||||
260 | |||||
261 | In order to learn how to use SAX to parse XML, you will need to read | ||||
262 | L<XML::SAX::Intro> and for reference, L<XML::SAX::Specification>. | ||||
263 | |||||
264 | =head1 WRITING A SAX2 PARSER | ||||
265 | |||||
266 | The first thing to remember in writing a SAX2 parser is to subclass | ||||
267 | XML::SAX::Base. This will make your life infinitely easier, by providing | ||||
268 | a number of methods automagically for you. See L<XML::SAX::Base> for more | ||||
269 | details. | ||||
270 | |||||
271 | When writing a SAX2 parser that is compatible with XML::SAX, you need | ||||
272 | to inform XML::SAX of the presence of that driver when you install it. | ||||
273 | In order to do that, XML::SAX contains methods for saving the fact that | ||||
274 | the parser exists on your system to a "INI" file, which is then loaded | ||||
275 | to determine which parsers are installed. | ||||
276 | |||||
277 | The best way to do this is to follow these rules: | ||||
278 | |||||
279 | =over 4 | ||||
280 | |||||
281 | =item * Add XML::SAX as a prerequisite in Makefile.PL: | ||||
282 | |||||
283 | WriteMakefile( | ||||
284 | ... | ||||
285 | PREREQ_PM => { 'XML::SAX' => 0 }, | ||||
286 | ... | ||||
287 | ); | ||||
288 | |||||
289 | Alternatively you may wish to check for it in other ways that will | ||||
290 | cause more than just a warning. | ||||
291 | |||||
292 | =item * Add the following code snippet to your Makefile.PL: | ||||
293 | |||||
294 | sub MY::install { | ||||
295 | package MY; | ||||
296 | my $script = shift->SUPER::install(@_); | ||||
297 | if (ExtUtils::MakeMaker::prompt( | ||||
298 | "Do you want to modify ParserDetails.ini?", 'Y') | ||||
299 | =~ /^y/i) { | ||||
300 | $script =~ s/install :: (.*)$/install :: $1 install_sax_driver/m; | ||||
301 | $script .= <<"INSTALL"; | ||||
302 | |||||
303 | install_sax_driver : | ||||
304 | \t\@\$(PERL) -MXML::SAX -e "XML::SAX->add_parser(q(\$(NAME)))->save_parsers()" | ||||
305 | |||||
306 | INSTALL | ||||
307 | } | ||||
308 | return $script; | ||||
309 | } | ||||
310 | |||||
311 | Note that you should check the output of this - \$(NAME) will use the name of | ||||
312 | your distribution, which may not be exactly what you want. For example XML::LibXML | ||||
313 | has a driver called XML::LibXML::SAX::Generator, which is used in place of | ||||
314 | \$(NAME) in the above. | ||||
315 | |||||
316 | =item * Add an XML::SAX test: | ||||
317 | |||||
318 | A test file should be added to your t/ directory containing something like the | ||||
319 | following: | ||||
320 | |||||
321 | use Test; | ||||
322 | BEGIN { plan tests => 3 } | ||||
323 | use XML::SAX; | ||||
324 | use XML::SAX::PurePerl::DebugHandler; | ||||
325 | XML::SAX->add_parser(q(XML::SAX::MyDriver)); | ||||
326 | local $XML::SAX::ParserPackage = 'XML::SAX::MyDriver'; | ||||
327 | eval { | ||||
328 | my $handler = XML::SAX::PurePerl::DebugHandler->new(); | ||||
329 | ok($handler); | ||||
330 | my $parser = XML::SAX::ParserFactory->parser(Handler => $handler); | ||||
331 | ok($parser); | ||||
332 | ok($parser->isa('XML::SAX::MyDriver'); | ||||
333 | $parser->parse_string("<tag/>"); | ||||
334 | ok($handler->{seen}{start_element}); | ||||
335 | }; | ||||
336 | |||||
337 | =back | ||||
338 | |||||
339 | =head1 EXPORTS | ||||
340 | |||||
341 | By default, XML::SAX exports nothing into the caller's namespace. However you | ||||
342 | can request the symbols C<Namespaces> and C<Validation> which are the | ||||
343 | URIs for those features, allowing an easier way to request those features | ||||
344 | via ParserFactory: | ||||
345 | |||||
346 | use XML::SAX qw(Namespaces Validation); | ||||
347 | my $factory = XML::SAX::ParserFactory->new(); | ||||
348 | $factory->require_feature(Namespaces); | ||||
349 | $factory->require_feature(Validation); | ||||
350 | my $parser = $factory->parser(); | ||||
351 | |||||
352 | =head1 AUTHOR | ||||
353 | |||||
354 | Current maintainer: Grant McLean, grantm@cpan.org | ||||
355 | |||||
356 | Originally written by: | ||||
357 | |||||
358 | Matt Sergeant, matt@sergeant.org | ||||
359 | |||||
360 | Kip Hampton, khampton@totalcinema.com | ||||
361 | |||||
362 | Robin Berjon, robin@knowscape.com | ||||
363 | |||||
364 | =head1 LICENSE | ||||
365 | |||||
366 | This is free software, you may use it and distribute it under | ||||
367 | the same terms as Perl itself. | ||||
368 | |||||
369 | =head1 SEE ALSO | ||||
370 | |||||
371 | L<XML::SAX::Base> for writing SAX Filters and Parsers | ||||
372 | |||||
373 | L<XML::SAX::PurePerl> for an XML parser written in 100% | ||||
374 | pure perl. | ||||
375 | |||||
376 | L<XML::SAX::Exception> for details on exception handling | ||||
377 | |||||
378 | =cut | ||||
379 | |||||
# spent 62µs within XML::SAX::CORE:match which was called 25 times, avg 2µs/call:
# 13 times (54µs+0s) by XML::SAX::_parse_ini_file at line 90 of XML/SAX.pm, avg 4µs/call
# 12 times (8µs+0s) by XML::SAX::_parse_ini_file at line 87 of XML/SAX.pm, avg 625ns/call | |||||
# spent 57µs within XML::SAX::CORE:open which was called
# once (57µs+0s) by XML::SAX::load_parsers at line 61 of XML/SAX.pm | |||||
# spent 33µs within XML::SAX::CORE:readline which was called 13 times, avg 3µs/call:
# 13 times (33µs+0s) by XML::SAX::_parse_ini_file at line 78 of XML/SAX.pm, avg 3µs/call | |||||
# spent 89µs within XML::SAX::CORE:subst which was called 36 times, avg 2µs/call:
# 12 times (74µs+0s) by XML::SAX::_parse_ini_file at line 82 of XML/SAX.pm, avg 6µs/call
# 12 times (8µs+0s) by XML::SAX::_parse_ini_file at line 83 of XML/SAX.pm, avg 700ns/call
# 12 times (7µs+0s) by XML::SAX::_parse_ini_file at line 85 of XML/SAX.pm, avg 575ns/call |