File Coverage

blib/lib/XML/SAX/PurePerl.pm
Criterion Covered Total %
statement 305 381 80.0
branch 97 160 60.6
condition 17 26 65.3
subroutine 39 50 78.0
pod 0 19 0.0
total 458 636 72.0


line stmt bran cond sub pod time code
1             # $Id$
2              
3             package XML::SAX::PurePerl;
4              
5 14     14   53661 use strict;
  14         86  
  14         424  
6 14     14   65 use vars qw/$VERSION/;
  14         22  
  14         641  
7              
8             $VERSION = '1.02';
9              
10 14     14   5163 use XML::SAX::PurePerl::Productions qw($NameChar $SingleChar);
  14         27  
  14         1718  
11 14     14   4729 use XML::SAX::PurePerl::Reader;
  14         44  
  14         654  
12 14     14   4813 use XML::SAX::PurePerl::EncodingDetect ();
  14         34  
  14         278  
13 14     14   80 use XML::SAX::Exception;
  14         27  
  14         256  
14 14     14   4840 use XML::SAX::PurePerl::DocType ();
  14         31  
  14         271  
15 14     14   5571 use XML::SAX::PurePerl::DTDDecls ();
  14         40  
  14         285  
16 14     14   5119 use XML::SAX::PurePerl::XMLDecl ();
  14         35  
  14         247  
17 14     14   4776 use XML::SAX::DocumentLocator ();
  14         30  
  14         240  
18 14     14   10305 use XML::SAX::Base ();
  14         216141  
  14         416  
19 14     14   5101 use XML::SAX qw(Namespaces);
  14         35  
  14         790  
20 14     14   6433 use XML::NamespaceSupport ();
  14         30429  
  14         329  
21 14     14   5651 use IO::File;
  14         12258  
  14         1940  
22              
23             if ($] < 5.006) {
24             require XML::SAX::PurePerl::NoUnicodeExt;
25             }
26             else {
27             require XML::SAX::PurePerl::UnicodeExt;
28             }
29              
30 14     14   93 use vars qw(@ISA);
  14         29  
  14         887  
31             @ISA = ('XML::SAX::Base');
32              
33             my %int_ents = (
34             amp => '&',
35             lt => '<',
36             gt => '>',
37             quot => '"',
38             apos => "'",
39             );
40              
41             my $xmlns_ns = "http://www.w3.org/2000/xmlns/";
42             my $xml_ns = "http://www.w3.org/XML/1998/namespace";
43              
44 14     14   72 use Carp;
  14         26  
  14         51655  
45             sub _parse_characterstream {
46 0     0   0 my $self = shift;
47 0         0 my ($fh) = @_;
48 0         0 confess("CharacterStream is not yet correctly implemented");
49 0         0 my $reader = XML::SAX::PurePerl::Reader::Stream->new($fh);
50 0         0 return $self->_parse($reader);
51             }
52              
53             sub _parse_bytestream {
54 3     3   1278 my $self = shift;
55 3         8 my ($fh) = @_;
56 3         27 my $reader = XML::SAX::PurePerl::Reader::Stream->new($fh);
57 3         13 return $self->_parse($reader);
58             }
59              
60             sub _parse_string {
61 4     4   1228 my $self = shift;
62 4         12 my ($str) = @_;
63 4         34 my $reader = XML::SAX::PurePerl::Reader::String->new($str);
64 4         23 return $self->_parse($reader);
65             }
66              
67             sub _parse_systemid {
68 18     18   3446 my $self = shift;
69 18         36 my ($uri) = @_;
70 18         137 my $reader = XML::SAX::PurePerl::Reader::URI->new($uri);
71 18         60 return $self->_parse($reader);
72             }
73              
74             sub _parse {
75 25     25   53 my ($self, $reader) = @_;
76            
77 25         195 $reader->public_id($self->{ParseOptions}{Source}{PublicId});
78 25         123 $reader->system_id($self->{ParseOptions}{Source}{SystemId});
79              
80 25         151 $self->{NSHelper} = XML::NamespaceSupport->new({xmlns => 1});
81              
82             $self->set_document_locator(
83             XML::SAX::DocumentLocator->new(
84 0     0   0 sub { $reader->public_id },
85 0     0   0 sub { $reader->system_id },
86 0     0   0 sub { $reader->line },
87 0     0   0 sub { $reader->column },
88 0     0   0 sub { $reader->get_encoding },
89 0     0   0 sub { $reader->get_xml_version },
90 25         708 ),
91             );
92            
93 25         551 $self->start_document({});
94              
95 25 50       252 if (defined $self->{ParseOptions}{Source}{Encoding}) {
96 0         0 $reader->set_encoding($self->{ParseOptions}{Source}{Encoding});
97             }
98             else {
99 25         93 $self->encoding_detect($reader);
100             }
101            
102             # parse a document
103 25         94 $self->document($reader);
104            
105 21         144 return $self->end_document({});
106             }
107              
108             sub parser_error {
109 3     3 0 8 my $self = shift;
110 3         5 my ($error, $reader) = @_;
111            
112             # warn("parser error: $error from ", $reader->line, " : ", $reader->column, "\n");
113 3         17 my $exception = XML::SAX::Exception::Parse->new(
114             Message => $error,
115             ColumnNumber => $reader->column,
116             LineNumber => $reader->line,
117             PublicId => $reader->public_id,
118             SystemId => $reader->system_id,
119             );
120              
121 3         55 $self->fatal_error($exception);
122 3         113 $exception->throw;
123             }
124              
125             sub document {
126 25     25 0 54 my ($self, $reader) = @_;
127            
128             # document ::= prolog element Misc*
129            
130 25         70 $self->prolog($reader);
131 22 50       70 $self->element($reader) ||
132             $self->parser_error("Document requires an element", $reader);
133            
134 21         66 while(length($reader->data)) {
135 18 50       52 $self->Misc($reader) ||
136             $self->parser_error("Only Comments, PIs and whitespace allowed at end of document", $reader);
137             }
138             }
139              
140             sub prolog {
141 25     25 0 49 my ($self, $reader) = @_;
142            
143 25         105 $self->XMLDecl($reader);
144            
145             # consume all misc bits
146 23         80 1 while($self->Misc($reader));
147            
148 22 100       223 if ($self->doctypedecl($reader)) {
149 1         3 while (length($reader->data)) {
150 4 100       11 $self->Misc($reader) || last;
151             }
152             }
153             }
154              
155             sub element {
156 458     458 0 673 my ($self, $reader) = @_;
157            
158 458 50       790 return 0 unless $reader->match('<');
159            
160 458   33     861 my $name = $self->Name($reader) || $self->parser_error("Invalid element name", $reader);
161            
162 458         568 my %attribs;
163            
164 458         870 while( my ($k, $v) = $self->Attribute($reader) ) {
165 2002         5583 $attribs{$k} = $v;
166             }
167            
168 458         1184 my $have_namespaces = $self->get_feature(Namespaces);
169            
170             # Namespace processing
171 458         11192 $self->{NSHelper}->push_context;
172 458         3895 my @new_ns;
173             # my %attrs = @attribs;
174             # while (my ($k,$v) = each %attrs) {
175 458 50       723 if ($have_namespaces) {
176 458         1153 while ( my ($k, $v) = each %attribs ) {
177 2002 100       4643 if ($k =~ m/^xmlns(:(.*))?$/) {
178 4   100     16 my $prefix = $2 || '';
179 4         12 $self->{NSHelper}->declare_prefix($prefix, $v);
180 4         85 my $ns =
181             {
182             Prefix => $prefix,
183             NamespaceURI => $v,
184             };
185 4         8 push @new_ns, $ns;
186 4         14 $self->SUPER::start_prefix_mapping($ns);
187             }
188             }
189             }
190              
191             # Create element object and fire event
192 458         564 my %attrib_hash;
193 458         938 while (my ($name, $value) = each %attribs ) {
194             # TODO normalise value here
195 2002         2380 my ($ns, $prefix, $lname);
196 2002 50       2541 if ($have_namespaces) {
197 2002         3517 ($ns, $prefix, $lname) = $self->{NSHelper}->process_attribute_name($name);
198             }
199 2002   100     38344 $ns ||= ''; $prefix ||= ''; $lname ||= '';
  2002   100     4854  
  2002   50     2456  
200 2002         9129 $attrib_hash{"{$ns}$lname"} = {
201             Name => $name,
202             LocalName => $lname,
203             Prefix => $prefix,
204             NamespaceURI => $ns,
205             Value => $value,
206             };
207             }
208            
209 458         973 %attribs = (); # lose the memory since we recurse deep
210            
211 458         576 my ($ns, $prefix, $lname);
212 458 50       862 if ($self->get_feature(Namespaces)) {
213 458         9392 ($ns, $prefix, $lname) = $self->{NSHelper}->process_element_name($name);
214             }
215             else {
216 0         0 $lname = $name;
217             }
218 457   100     9191 $ns ||= ''; $prefix ||= ''; $lname ||= '';
  457   100     1213  
  457   50     726  
219              
220             # Process remainder of start_element
221 457         872 $self->skip_whitespace($reader);
222 457         467 my $have_content;
223 457         808 my $data = $reader->data(2);
224 457 100       935 if ($data =~ /^\/>/) {
225 12         39 $reader->move_along(2);
226             }
227             else {
228 445 50       1070 $data =~ /^>/ or $self->parser_error("No close element tag", $reader);
229 445         1068 $reader->move_along(1);
230 445         597 $have_content++;
231             }
232            
233 457         1485 my $el =
234             {
235             Name => $name,
236             LocalName => $lname,
237             Prefix => $prefix,
238             NamespaceURI => $ns,
239             Attributes => \%attrib_hash,
240             };
241 457         1602 $self->start_element($el);
242            
243             # warn("($name\n");
244            
245 457 100       5399 if ($have_content) {
246 445         935 $self->content($reader);
247            
248 445         808 my $data = $reader->data(2);
249 445 50       1070 $data =~ /^<\// or $self->parser_error("No close tag marker", $reader);
250 445         995 $reader->move_along(2);
251 445         723 my $end_name = $self->Name($reader);
252 445 50       1072 $end_name eq $name || $self->parser_error("End tag mismatch ($end_name != $name)", $reader);
253 445         925 $self->skip_whitespace($reader);
254 445 50       775 $reader->match('>') or $self->parser_error("No close '>' on end tag", $reader);
255             }
256            
257 457         1815 my %end_el = %$el;
258 457         892 delete $end_el{Attributes};
259 457         1262 $self->end_element(\%end_el);
260              
261 457         1058 for my $ns (@new_ns) {
262 3         20 $self->end_prefix_mapping($ns);
263             }
264 457         1349 $self->{NSHelper}->pop_context;
265            
266 457         5744 return 1;
267             }
268              
269             sub content {
270 445     445 0 602 my ($self, $reader) = @_;
271            
272 445         473 while (1) {
273 946         1773 $self->CharData($reader);
274            
275 946         1654 my $data = $reader->data(2);
276            
277 946 100       3129 if ($data =~ /^<\//) {
    100          
    100          
    50          
    50          
278 445         1020 return 1;
279             }
280             elsif ($data =~ /^&/) {
281 51 50       112 $self->Reference($reader) or $self->parser_error("bare & not allowed in content", $reader);
282 51         68 next;
283             }
284             elsif ($data =~ /^
285 14 50 66     41 ($self->CDSect($reader)
286             or
287             $self->Comment($reader))
288             and next;
289             }
290             elsif ($data =~ /^<\?/) {
291 0 0       0 $self->PI($reader) and next;
292             }
293             elsif ($data =~ /^
294 436 50       808 $self->element($reader) and next;
295             }
296 0         0 last;
297             }
298            
299 0         0 return 1;
300             }
301              
302             sub CDSect {
303 14     14 0 26 my ($self, $reader) = @_;
304            
305 14         32 my $data = $reader->data(9);
306 14 100       94 return 0 unless $data =~ /^
307 2         9 $reader->move_along(9);
308            
309 2         18 $self->start_cdata({});
310            
311 2         87 $data = $reader->data;
312 2         4 while (1) {
313 2 50       9 $self->parser_error("EOF looking for CDATA section end", $reader)
314             unless length($data);
315            
316 2 50       17 if ($data =~ /^(.*?)\]\]>/s) {
317 2         6 my $chars = $1;
318 2         8 $reader->move_along(length($chars) + 3);
319 2         24 $self->characters({Data => $chars});
320 2         240 last;
321             }
322             else {
323 0         0 $self->characters({Data => $data});
324 0         0 $reader->move_along(length($data));
325 0         0 $data = $reader->data;
326             }
327             }
328 2         24 $self->end_cdata({});
329 2         100 return 1;
330             }
331              
332             sub CharData {
333 946     946 0 1208 my ($self, $reader) = @_;
334            
335 946         1599 my $data = $reader->data;
336            
337 946         1147 while (1) {
338 954 50       9091 return unless length($data);
339            
340 954 100       2998 if ($data =~ /^([^<&]*)[<&]/s) {
341 946         1622 my $chars = $1;
342 946 50       1621 $self->parser_error("String ']]>' not allowed in character data", $reader)
343             if $chars =~ /\]\]>/;
344 946         2477 $reader->move_along(length($chars));
345 946 100       3757 $self->characters({Data => $chars}) if length($chars);
346 946         1948 last;
347             }
348             else {
349 8         27 $self->characters({Data => $data});
350 8         27 $reader->move_along(length($data));
351 8         17 $data = $reader->data;
352             }
353             }
354             }
355              
356             sub Misc {
357 72     72 0 117 my ($self, $reader) = @_;
358 72 100       152 if ($self->Comment($reader)) {
    100          
    100          
359 4         14 return 1;
360             }
361             elsif ($self->PI($reader)) {
362 5         14 return 1;
363             }
364             elsif ($self->skip_whitespace($reader)) {
365 39         132 return 1;
366             }
367            
368 23         67 return 0;
369             }
370              
371             sub Reference {
372 51     51 0 72 my ($self, $reader) = @_;
373            
374 51 50       88 return 0 unless $reader->match('&');
375            
376 51         95 my $data = $reader->data;
377              
378             # Fetch more data if we have an incomplete numeric reference
379 51 50       144 if ($data =~ /^(#\d*|#x[0-9a-fA-F]*)$/) {
380 0         0 $data = $reader->data(length($data) + 6);
381             }
382            
383 51 50       184 if ($data =~ /^#x([0-9a-fA-F]+);/) {
    50          
384 0         0 my $ref = $1;
385 0         0 $reader->move_along(length($ref) + 3);
386 0         0 my $char = chr_ref(hex($ref));
387 0 0       0 $self->parser_error("Character reference &#$ref; refers to an illegal XML character ($char)", $reader)
388             unless $char =~ /$SingleChar/o;
389 0         0 $self->characters({ Data => $char });
390 0         0 return 1;
391             }
392             elsif ($data =~ /^#([0-9]+);/) {
393 0         0 my $ref = $1;
394 0         0 $reader->move_along(length($ref) + 2);
395 0         0 my $char = chr_ref($ref);
396 0 0       0 $self->parser_error("Character reference &#$ref; refers to an illegal XML character ($char)", $reader)
397             unless $char =~ /$SingleChar/o;
398 0         0 $self->characters({ Data => $char });
399 0         0 return 1;
400             }
401             else {
402             # EntityRef
403 51   33     98 my $name = $self->Name($reader)
404             || $self->parser_error("Invalid name in entity", $reader);
405 51 50       103 $reader->match(';') or $self->parser_error("No semi-colon found after entity name", $reader);
406            
407             # warn("got entity: \&$name;\n");
408            
409             # expand it
410 51 50       105 if ($self->_is_entity($name)) {
    50          
411            
412 0 0       0 if ($self->_is_external($name)) {
413 0         0 my $value = $self->_get_entity($name);
414 0         0 my $ent_reader = XML::SAX::PurePerl::Reader::URI->new($value);
415 0         0 $self->encoding_detect($ent_reader);
416 0         0 $self->extParsedEnt($ent_reader);
417             }
418             else {
419 0         0 my $value = $self->_stringify_entity($name);
420 0         0 my $ent_reader = XML::SAX::PurePerl::Reader::String->new($value);
421 0         0 $self->content($ent_reader);
422             }
423 0         0 return 1;
424             }
425             elsif ($name =~ /^(?:amp|gt|lt|quot|apos)$/) {
426 51         199 $self->characters({ Data => $int_ents{$name} });
427 51         129 return 1;
428             }
429             else {
430 0         0 $self->parser_error("Undeclared entity", $reader);
431             }
432             }
433             }
434              
435             sub AttReference {
436 3     3 0 10 my ($self, $name, $reader) = @_;
437 3 100       18 if ($name =~ /^#x([0-9a-fA-F]+)$/) {
    100          
438 1         7 my $chr = chr_ref(hex($1));
439 1 50       6 $chr =~ /$SingleChar/o or $self->parser_error("Character reference '&$name;' refers to an illegal XML character", $reader);
440 1         4 return $chr;
441             }
442             elsif ($name =~ /^#([0-9]+)$/) {
443 1         3 my $chr = chr_ref($1);
444 1 50       6 $chr =~ /$SingleChar/o or $self->parser_error("Character reference '&$name;' refers to an illegal XML character", $reader);
445 1         13 return $chr;
446             }
447             else {
448 1 50       3 if ($self->_is_entity($name)) {
    50          
449 0 0       0 if ($self->_is_external($name)) {
450 0         0 $self->parser_error("No external entity references allowed in attribute values", $reader);
451             }
452             else {
453 0         0 my $value = $self->_stringify_entity($name);
454 0         0 return $value;
455             }
456             }
457             elsif ($name =~ /^(?:amp|lt|gt|quot|apos)$/) {
458 1         6 return $int_ents{$name};
459             }
460             else {
461 0         0 $self->parser_error("Undeclared entity '$name'", $reader);
462             }
463             }
464             }
465              
466             sub extParsedEnt {
467 0     0 0 0 my ($self, $reader) = @_;
468            
469 0         0 $self->TextDecl($reader);
470 0         0 $self->content($reader);
471             }
472              
473             sub _is_external {
474 0     0   0 my ($self, $name) = @_;
475             # TODO: Fix this to use $reader to store the entities perhaps.
476 0 0       0 if ($self->{ParseOptions}{external_entities}{$name}) {
477 0         0 return 1;
478             }
479 0         0 return ;
480             }
481              
482             sub _is_entity {
483 52     52   89 my ($self, $name) = @_;
484             # TODO: ditto above
485 52 50       124 if (exists $self->{ParseOptions}{entities}{$name}) {
486 0         0 return 1;
487             }
488 52         221 return 0;
489             }
490              
491             sub _stringify_entity {
492 0     0   0 my ($self, $name) = @_;
493             # TODO: ditto above
494 0 0       0 if (exists $self->{ParseOptions}{expanded_entity}{$name}) {
495 0         0 return $self->{ParseOptions}{expanded_entity}{$name};
496             }
497             # expand
498 0         0 my $reader = XML::SAX::PurePerl::Reader::URI->new($self->{ParseOptions}{entities}{$name});
499 0         0 my $ent = '';
500 0         0 while(1) {
501 0         0 my $data = $reader->data;
502 0         0 $ent .= $data;
503 0 0       0 $reader->move_along(length($data)) or last;
504             }
505 0         0 return $self->{ParseOptions}{expanded_entity}{$name} = $ent;
506             }
507              
508             sub _get_entity {
509 0     0   0 my ($self, $name) = @_;
510             # TODO: ditto above
511 0         0 return $self->{ParseOptions}{entities}{$name};
512             }
513              
514             sub skip_whitespace {
515 7465     7465 0 9018 my ($self, $reader) = @_;
516            
517 7465         11211 my $data = $reader->data;
518            
519 7465         8451 my $found = 0;
520 7465         88469 while ($data =~ s/^([\x20\x0A\x0D\x09]*)//) {
521 9534 100       20073 last unless length($1);
522 2069         2249 $found++;
523 2069         4654 $reader->move_along(length($1));
524 2069         3240 $data = $reader->data;
525             }
526            
527 7465         11492 return $found;
528             }
529              
530             sub Attribute {
531 2460     2460 0 3499 my ($self, $reader) = @_;
532            
533 2460 100       3388 $self->skip_whitespace($reader) || return;
534            
535 2007         3603 my $data = $reader->data(2);
536 2007 100       3824 return if $data =~ /^\/?>/;
537            
538 2002 50       2960 if (my $name = $self->Name($reader)) {
539 2002         3701 $self->skip_whitespace($reader);
540 2002 50       3403 $reader->match('=') or $self->parser_error("No '=' in Attribute", $reader);
541 2002         3711 $self->skip_whitespace($reader);
542 2002         2878 my $value = $self->AttValue($reader);
543              
544 2002 50       3134 if (!$self->cdata_attrib($name)) {
545 0         0 $value =~ s/^\x20*//; # discard leading spaces
546 0         0 $value =~ s/\x20*$//; # discard trailing spaces
547 0         0 $value =~ s/ {1,}/ /g; # all >1 space to single space
548             }
549            
550 2002         5201 return $name, $value;
551             }
552            
553 0         0 return;
554             }
555              
556             sub cdata_attrib {
557             # TODO implement this!
558 2002     2002 0 3190 return 1;
559             }
560              
561             sub AttValue {
562 2002     2002 0 2500 my ($self, $reader) = @_;
563            
564 2002         2879 my $quote = $self->quote($reader);
565            
566 2002         2457 my $value = '';
567            
568 2002         1968 while (1) {
569 2007         3124 my $data = $reader->data;
570 2007 50       20773 $self->parser_error("EOF found while looking for the end of attribute value", $reader)
571             unless length($data);
572 2007 100       7473 if ($data =~ /^([^$quote]*)$quote/) {
573 2002         5818 $reader->move_along(length($1) + 1);
574 2002         3364 $value .= $1;
575 2002         3221 last;
576             }
577             else {
578 5         13 $value .= $data;
579 5         12 $reader->move_along(length($data));
580             }
581             }
582            
583 2002 50       3655 if ($value =~ /
584 0         0 $self->parser_error("< character not allowed in attribute values", $reader);
585             }
586            
587 2002         3416 $value =~ s/[\x09\x0A\x0D]/\x20/g;
588 2002         2504 $value =~ s/&(#(x[0-9a-fA-F]+)|#([0-9]+)|\w+);/$self->AttReference($1, $reader)/geo;
  3         8  
589            
590 2002         3524 return $value;
591             }
592              
593             sub Comment {
594 84     84 0 126 my ($self, $reader) = @_;
595            
596 84         172 my $data = $reader->data(4);
597 84 100       220 if ($data =~ /^/s) {
605 17         43 $comment_str .= $1;
606 17 100       47 $self->parser_error("Invalid comment (dash)", $reader) if $comment_str =~ /-$/;
607 16         56 $reader->move_along(length($1) + 3);
608 16         29 last;
609             }
610             else {
611 0         0 $comment_str .= $data;
612 0         0 $reader->move_along(length($data));
613             }
614             }
615            
616 16         103 $self->comment({ Data => $comment_str });
617            
618 16         84 return 1;
619             }
620 67         177 return 0;
621             }
622              
623             sub PI {
624 67     67 0 110 my ($self, $reader) = @_;
625            
626 67         193 my $data = $reader->data(2);
627            
628 67 100       157 if ($data =~ /^<\?/) {
629 5         26 $reader->move_along(2);
630 5         5 my ($target);
631 5   33     12 $target = $self->Name($reader) ||
632             $self->parser_error("PI has no target", $reader);
633            
634 5         8 my $pi_data = '';
635 5 100       8 if ($self->skip_whitespace($reader)) {
636 3         4 while (1) {
637 3         6 my $data = $reader->data;
638 3 50       6 $self->parser_error("End of data seen while looking for close PI marker", $reader)
639             unless length($data);
640 3 50       12 if ($data =~ /^(.*?)\?>/s) {
641 3         7 $pi_data .= $1;
642 3         10 $reader->move_along(length($1) + 2);
643 3         5 last;
644             }
645             else {
646 0         0 $pi_data .= $data;
647 0         0 $reader->move_along(length($data));
648             }
649             }
650             }
651             else {
652 2         3 my $data = $reader->data(2);
653 2 50       6 $data =~ /^\?>/ or $self->parser_error("PI closing sequence not found", $reader);
654 2         6 $reader->move_along(2);
655             }
656            
657 5         39 $self->processing_instruction({ Target => $target, Data => $pi_data });
658            
659 5         208 return 1;
660             }
661 62         181 return 0;
662             }
663              
664             sub Name {
665 2962     2962 0 3701 my ($self, $reader) = @_;
666            
667 2962         3288 my $name = '';
668 2962         3057 while(1) {
669 2966         4431 my $data = $reader->data;
670 2966 50       29313 return unless length($data);
671 2966 50       7396 $data =~ /^([^\s>\/&\?;=<\)\(\[\],\%\#\!\*\|]*)/ or return;
672 2966         5322 $name .= $1;
673 2966         3741 my $len = length($1);
674 2966         5964 $reader->move_along($len);
675 2966 100       5366 last if ($len != length($data));
676             }
677            
678 2962 50       4684 return unless length($name);
679            
680 2962 50       14336 $name =~ /$NameChar/o or $self->parser_error("Name <$name> does not match NameChar production", $reader);
681              
682 2962         5888 return $name;
683             }
684              
685             sub quote {
686 2003     2003 0 2345 my ($self, $reader) = @_;
687            
688 2003         3101 my $data = $reader->data;
689            
690 2003 50       4395 $data =~ /^(['"])/ or $self->parser_error("Invalid quote token", $reader);
691 2003         4069 $reader->move_along(1);
692 2003         3389 return $1;
693             }
694              
695             1;
696             __END__