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 12     12   136669 use strict;
  12         33  
  12         586  
6 12     12   72 use vars qw/$VERSION/;
  12         27  
  12         917  
7              
8             $VERSION = '0.99';
9              
10 12     12   18472 use XML::SAX::PurePerl::Productions qw($NameChar $SingleChar);
  12         66  
  12         2322  
11 12     12   8283 use XML::SAX::PurePerl::Reader;
  12         46  
  12         900  
12 12     12   9291 use XML::SAX::PurePerl::EncodingDetect ();
  12         35  
  12         276  
13 12     12   73 use XML::SAX::Exception;
  12         23  
  12         254  
14 12     12   8902 use XML::SAX::PurePerl::DocType ();
  12         36  
  12         239  
15 12     12   9927 use XML::SAX::PurePerl::DTDDecls ();
  12         42  
  12         364  
16 12     12   11043 use XML::SAX::PurePerl::XMLDecl ();
  12         44  
  12         395  
17 12     12   10320 use XML::SAX::DocumentLocator ();
  12         34  
  12         256  
18 12     12   35081 use XML::SAX::Base ();
  12         352821  
  12         384  
19 12     12   9412 use XML::SAX qw(Namespaces);
  12         35  
  12         850  
20 12     12   29973 use XML::NamespaceSupport ();
  12         45266  
  12         316  
21 12     12   13320 use IO::File;
  12         17799  
  12         2868  
22              
23             if ($] < 5.006) {
24             require XML::SAX::PurePerl::NoUnicodeExt;
25             }
26             else {
27             require XML::SAX::PurePerl::UnicodeExt;
28             }
29              
30 12     12   97 use vars qw(@ISA);
  12         24  
  12         1239  
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 12     12   67 use Carp;
  12         24  
  12         65730  
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 2     2   2363 my $self = shift;
55 2         6 my ($fh) = @_;
56 2         29 my $reader = XML::SAX::PurePerl::Reader::Stream->new($fh);
57 2         12 return $self->_parse($reader);
58             }
59              
60             sub _parse_string {
61 3     3   2000 my $self = shift;
62 3         7 my ($str) = @_;
63 3         36 my $reader = XML::SAX::PurePerl::Reader::String->new($str);
64 3         25 return $self->_parse($reader);
65             }
66              
67             sub _parse_systemid {
68 17     17   9045 my $self = shift;
69 17         39 my ($uri) = @_;
70 17         191 my $reader = XML::SAX::PurePerl::Reader::URI->new($uri);
71 17         71 return $self->_parse($reader);
72             }
73              
74             sub _parse {
75 22     22   46 my ($self, $reader) = @_;
76            
77 22         235 $reader->public_id($self->{ParseOptions}{Source}{PublicId});
78 22         208 $reader->system_id($self->{ParseOptions}{Source}{SystemId});
79              
80 22         225 $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 22         955 ),
91             );
92            
93 22         676 $self->start_document({});
94              
95 22 50       242 if (defined $self->{ParseOptions}{Source}{Encoding}) {
96 0         0 $reader->set_encoding($self->{ParseOptions}{Source}{Encoding});
97             }
98             else {
99 22         127 $self->encoding_detect($reader);
100             }
101            
102             # parse a document
103 22         126 $self->document($reader);
104            
105 18         157 return $self->end_document({});
106             }
107              
108             sub parser_error {
109 3     3 0 7 my $self = shift;
110 3         7 my ($error, $reader) = @_;
111            
112             # warn("parser error: $error from ", $reader->line, " : ", $reader->column, "\n");
113 3         40 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         90 $self->fatal_error($exception);
122 3         113 $exception->throw;
123             }
124              
125             sub document {
126 22     22 0 52 my ($self, $reader) = @_;
127            
128             # document ::= prolog element Misc*
129            
130 22         102 $self->prolog($reader);
131 19 50       79 $self->element($reader) ||
132             $self->parser_error("Document requires an element", $reader);
133            
134 18         81 while(length($reader->data)) {
135 15 50       57 $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 22     22 0 40 my ($self, $reader) = @_;
142            
143 22         146 $self->XMLDecl($reader);
144            
145             # consume all misc bits
146 20         8483 1 while($self->Misc($reader));
147            
148 19 100       117 if ($self->doctypedecl($reader)) {
149 1         3 while (length($reader->data)) {
150 4 100       15 $self->Misc($reader) || last;
151             }
152             }
153             }
154              
155             sub element {
156 455     455 0 689 my ($self, $reader) = @_;
157            
158 455 50       1328 return 0 unless $reader->match('<');
159            
160 455   33     1195 my $name = $self->Name($reader) || $self->parser_error("Invalid element name", $reader);
161            
162 455         665 my %attribs;
163            
164 455         1103 while( my ($k, $v) = $self->Attribute($reader) ) {
165 2002         9334 $attribs{$k} = $v;
166             }
167            
168 455         2202 my $have_namespaces = $self->get_feature(Namespaces);
169            
170             # Namespace processing
171 455         19337 $self->{NSHelper}->push_context;
172 455         5565 my @new_ns;
173             # my %attrs = @attribs;
174             # while (my ($k,$v) = each %attrs) {
175 455 50       979 if ($have_namespaces) {
176 455         1977 while ( my ($k, $v) = each %attribs ) {
177 2002 100       7720 if ($k =~ m/^xmlns(:(.*))?$/) {
178 4   100     29 my $prefix = $2 || '';
179 4         20 $self->{NSHelper}->declare_prefix($prefix, $v);
180 4         116 my $ns =
181             {
182             Prefix => $prefix,
183             NamespaceURI => $v,
184             };
185 4         9 push @new_ns, $ns;
186 4         28 $self->SUPER::start_prefix_mapping($ns);
187             }
188             }
189             }
190              
191             # Create element object and fire event
192 455         685 my %attrib_hash;
193 455         1572 while (my ($name, $value) = each %attribs ) {
194             # TODO normalise value here
195 2002         2246 my ($ns, $prefix, $lname);
196 2002 50       3618 if ($have_namespaces) {
197 2002         6848 ($ns, $prefix, $lname) = $self->{NSHelper}->process_attribute_name($name);
198             }
199 2002   100     40989 $ns ||= ''; $prefix ||= ''; $lname ||= '';
  2002   100     7035  
  2002   50     3407  
200 2002         19571 $attrib_hash{"{$ns}$lname"} = {
201             Name => $name,
202             LocalName => $lname,
203             Prefix => $prefix,
204             NamespaceURI => $ns,
205             Value => $value,
206             };
207             }
208            
209 455         3284 %attribs = (); # lose the memory since we recurse deep
210            
211 455         664 my ($ns, $prefix, $lname);
212 455 50       1519 if ($self->get_feature(Namespaces)) {
213 455         16957 ($ns, $prefix, $lname) = $self->{NSHelper}->process_element_name($name);
214             }
215             else {
216 0         0 $lname = $name;
217             }
218 454   100     10874 $ns ||= ''; $prefix ||= ''; $lname ||= '';
  454   100     1778  
  454   50     810  
219              
220             # Process remainder of start_element
221 454         3391 $self->skip_whitespace($reader);
222 454         508 my $have_content;
223 454         1357 my $data = $reader->data(2);
224 454 100       1170 if ($data =~ /^\/>/) {
225 9         41 $reader->move_along(2);
226             }
227             else {
228 445 50       1677 $data =~ /^>/ or $self->parser_error("No close element tag", $reader);
229 445         1557 $reader->move_along(1);
230 445         649 $have_content++;
231             }
232            
233 454         2322 my $el =
234             {
235             Name => $name,
236             LocalName => $lname,
237             Prefix => $prefix,
238             NamespaceURI => $ns,
239             Attributes => \%attrib_hash,
240             };
241 454         2142 $self->start_element($el);
242            
243             # warn("($name\n");
244            
245 454 100       7499 if ($have_content) {
246 445         1329 $self->content($reader);
247            
248 445         1265 my $data = $reader->data(2);
249 445 50       1780 $data =~ /^<\// or $self->parser_error("No close tag marker", $reader);
250 445         1368 $reader->move_along(2);
251 445         1388 my $end_name = $self->Name($reader);
252 445 50       1091 $end_name eq $name || $self->parser_error("End tag mismatch ($end_name != $name)", $reader);
253 445         1056 $self->skip_whitespace($reader);
254 445 50       1560 $reader->match('>') or $self->parser_error("No close '>' on end tag", $reader);
255             }
256            
257 454         3468 my %end_el = %$el;
258 454         1759 delete $end_el{Attributes};
259 454         1956 $self->end_element(\%end_el);
260              
261 454         1395 for my $ns (@new_ns) {
262 3         22 $self->end_prefix_mapping($ns);
263             }
264 454         2137 $self->{NSHelper}->pop_context;
265            
266 454         14556 return 1;
267             }
268              
269             sub content {
270 445     445 0 966 my ($self, $reader) = @_;
271            
272 445         482 while (1) {
273 946         2300 $self->CharData($reader);
274            
275 946         2840 my $data = $reader->data(2);
276            
277 946 100       5942 if ($data =~ /^<\//) {
    100          
    100          
    50          
    50          
278 445         841 return 1;
279             }
280             elsif ($data =~ /^&/) {
281 51 50       146 $self->Reference($reader) or $self->parser_error("bare & not allowed in content", $reader);
282 51         85 next;
283             }
284             elsif ($data =~ /^
285 14 50 66     43 ($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       1347 $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 22 my ($self, $reader) = @_;
304            
305 14         38 my $data = $reader->data(9);
306 14 100       243 return 0 unless $data =~ /^
307 2         8 $reader->move_along(9);
308            
309 2         27 $self->start_cdata({});
310            
311 2         1071 $data = $reader->data;
312 2         6 while (1) {
313 2 50       15 $self->parser_error("EOF looking for CDATA section end", $reader)
314             unless length($data);
315            
316 2 50       21 if ($data =~ /^(.*?)\]\]>/s) {
317 2         5 my $chars = $1;
318 2         8 $reader->move_along(length($chars) + 3);
319 2         20 $self->characters({Data => $chars});
320 2         588 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         23 $self->end_cdata({});
329 2         98 return 1;
330             }
331              
332             sub CharData {
333 946     946 0 1218 my ($self, $reader) = @_;
334            
335 946         2561 my $data = $reader->data;
336            
337 946         1313 while (1) {
338 954 50       12280 return unless length($data);
339            
340 954 100       4590 if ($data =~ /^([^<&]*)[<&]/s) {
341 946         1792 my $chars = $1;
342 946 50       2314 $self->parser_error("String ']]>' not allowed in character data", $reader)
343             if $chars =~ /\]\]>/;
344 946         4022 $reader->move_along(length($chars));
345 946 100       5900 $self->characters({Data => $chars}) if length($chars);
346 946         3354 last;
347             }
348             else {
349 8         46 $self->characters({Data => $data});
350 8         37 $reader->move_along(length($data));
351 8         23 $data = $reader->data;
352             }
353             }
354             }
355              
356             sub Misc {
357 61     61 0 109 my ($self, $reader) = @_;
358 61 100       160 if ($self->Comment($reader)) {
    100          
    100          
359 4         111 return 1;
360             }
361             elsif ($self->PI($reader)) {
362 4         15 return 1;
363             }
364             elsif ($self->skip_whitespace($reader)) {
365 32         157 return 1;
366             }
367            
368 20         64 return 0;
369             }
370              
371             sub Reference {
372 51     51 0 72 my ($self, $reader) = @_;
373            
374 51 50       157 return 0 unless $reader->match('&');
375            
376 51         134 my $data = $reader->data;
377              
378             # Fetch more data if we have an incomplete numeric reference
379 51 50       413 if ($data =~ /^(#\d*|#x[0-9a-fA-F]*)$/) {
380 0         0 $data = $reader->data(length($data) + 6);
381             }
382            
383 51 50       586 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     134 my $name = $self->Name($reader)
404             || $self->parser_error("Invalid name in entity", $reader);
405 51 50       201 $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       185 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         292 $self->characters({ Data => $int_ents{$name} });
427 51         188 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 6 my ($self, $name, $reader) = @_;
437 3 100       18 if ($name =~ /^#x([0-9a-fA-F]+)$/) {
    100          
438 1         10 my $chr = chr_ref(hex($1));
439 1 50       7 $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       7 $chr =~ /$SingleChar/o or $self->parser_error("Character reference '&$name;' refers to an illegal XML character", $reader);
445 1         3 return $chr;
446             }
447             else {
448 1 50       4 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         8 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   85 my ($self, $name) = @_;
484             # TODO: ditto above
485 52 50       196 if (exists $self->{ParseOptions}{entities}{$name}) {
486 0         0 return 1;
487             }
488 52         418 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 7442     7442 0 9385 my ($self, $reader) = @_;
516            
517 7442         19678 my $data = $reader->data;
518            
519 7442         10701 my $found = 0;
520 7442         139351 while ($data =~ s/^([\x20\x0A\x0D\x09]*)//) {
521 9500 100       30725 last unless length($1);
522 2058         2545 $found++;
523 2058         7203 $reader->move_along(length($1));
524 2058         6241 $data = $reader->data;
525             }
526            
527 7442         20058 return $found;
528             }
529              
530             sub Attribute {
531 2457     2457 0 4190 my ($self, $reader) = @_;
532            
533 2457 100       4498 $self->skip_whitespace($reader) || return;
534            
535 2007         6679 my $data = $reader->data(2);
536 2007 100       5900 return if $data =~ /^\/?>/;
537            
538 2002 50       4730 if (my $name = $self->Name($reader)) {
539 2002         4249 $self->skip_whitespace($reader);
540 2002 50       6105 $reader->match('=') or $self->parser_error("No '=' in Attribute", $reader);
541 2002         4125 $self->skip_whitespace($reader);
542 2002         11987 my $value = $self->AttValue($reader);
543              
544 2002 50       4517 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         8302 return $name, $value;
551             }
552            
553 0         0 return;
554             }
555              
556             sub cdata_attrib {
557             # TODO implement this!
558 2002     2002 0 4495 return 1;
559             }
560              
561             sub AttValue {
562 2002     2002 0 2660 my ($self, $reader) = @_;
563            
564 2002         3576 my $quote = $self->quote($reader);
565            
566 2002         2544 my $value = '';
567            
568 2002         2021 while (1) {
569 2007         5858 my $data = $reader->data;
570 2007 50       31346 $self->parser_error("EOF found while looking for the end of attribute value", $reader)
571             unless length($data);
572 2007 100       14026 if ($data =~ /^([^$quote]*)$quote/) {
573 2002         7747 $reader->move_along(length($1) + 1);
574 2002         4030 $value .= $1;
575 2002         4145 last;
576             }
577             else {
578 5         15 $value .= $data;
579 5         22 $reader->move_along(length($data));
580             }
581             }
582            
583 2002 50       5022 if ($value =~ /
584 0         0 $self->parser_error("< character not allowed in attribute values", $reader);
585             }
586            
587 2002         3976 $value =~ s/[\x09\x0A\x0D]/\x20/g;
588 2002         2701 $value =~ s/&(#(x[0-9a-fA-F]+)|#([0-9]+)|\w+);/$self->AttReference($1, $reader)/geo;
  3         9  
589            
590 2002         4153 return $value;
591             }
592              
593             sub Comment {
594 73     73 0 203 my ($self, $reader) = @_;
595            
596 73         325 my $data = $reader->data(4);
597 73 100       287 if ($data =~ /^/s) {
605 17         47 $comment_str .= $1;
606 17 100       78 $self->parser_error("Invalid comment (dash)", $reader) if $comment_str =~ /-$/;
607 16         87 $reader->move_along(length($1) + 3);
608 16         31 last;
609             }
610             else {
611 0         0 $comment_str .= $data;
612 0         0 $reader->move_along(length($data));
613             }
614             }
615            
616 16         229 $self->comment({ Data => $comment_str });
617            
618 16         124 return 1;
619             }
620 56         251 return 0;
621             }
622              
623             sub PI {
624 56     56 0 88 my ($self, $reader) = @_;
625            
626 56         161 my $data = $reader->data(2);
627            
628 56 100       173 if ($data =~ /^<\?/) {
629 4         11 $reader->move_along(2);
630 4         6 my ($target);
631 4   33     12 $target = $self->Name($reader) ||
632             $self->parser_error("PI has no target", $reader);
633            
634 4         6 my $pi_data = '';
635 4 100       11 if ($self->skip_whitespace($reader)) {
636 2         3 while (1) {
637 2         7 my $data = $reader->data;
638 2 50       6 $self->parser_error("End of data seen while looking for close PI marker", $reader)
639             unless length($data);
640 2 50       13 if ($data =~ /^(.*?)\?>/s) {
641 2         11 $pi_data .= $1;
642 2         9 $reader->move_along(length($1) + 2);
643 2         4 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         8 my $data = $reader->data(2);
653 2 50       12 $data =~ /^\?>/ or $self->parser_error("PI closing sequence not found", $reader);
654 2         16 $reader->move_along(2);
655             }
656            
657 4         44 $self->processing_instruction({ Target => $target, Data => $pi_data });
658            
659 4         17 return 1;
660             }
661 52         226 return 0;
662             }
663              
664             sub Name {
665 2958     2958 0 4252 my ($self, $reader) = @_;
666            
667 2958         3461 my $name = '';
668 2958         2913 while(1) {
669 2962         8324 my $data = $reader->data;
670 2962 50       50393 return unless length($data);
671 2962 50       17256 $data =~ /^([^\s>\/&\?;=<\)\(\[\],\%\#\!\*\|]*)/ or return;
672 2962         7045 $name .= $1;
673 2962         4879 my $len = length($1);
674 2962         8928 $reader->move_along($len);
675 2962 100       10261 last if ($len != length($data));
676             }
677            
678 2958 50       7203 return unless length($name);
679            
680 2958 50       24689 $name =~ /$NameChar/o or $self->parser_error("Name <$name> does not match NameChar production", $reader);
681              
682 2958         10161 return $name;
683             }
684              
685             sub quote {
686 2003     2003 0 2107 my ($self, $reader) = @_;
687            
688 2003         20147 my $data = $reader->data;
689            
690 2003 50       7900 $data =~ /^(['"])/ or $self->parser_error("Invalid quote token", $reader);
691 2003         5540 $reader->move_along(1);
692 2003         6089 return $1;
693             }
694              
695             1;
696             __END__