MAJOR=4
MINOR=48
DEVNAME=tty48
  0   ˆl–ß=¿J•2ÛR‚ _PLÜ×ò˜´oÈ„�¾/_‹uÐb&=LV[(ÂÆ ?÷     # $Id$

package XML::SAX::PurePerl;

use strict;
use XML::SAX::PurePerl::Productions qw($SingleChar);

sub elementdecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    return 0 unless $data =~ /^<!ELEMENT/;
    $reader->move_along(9);
    
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after ELEMENT declaration", $reader);
    
    my $name = $self->Name($reader);
    
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after ELEMENT's name", $reader);
        
    $self->contentspec($reader, $name);
    
    $self->skip_whitespace($reader);
    
    $reader->match('>') or $self->parser_error("Closing angle bracket not found on ELEMENT declaration", $reader);
    
    return 1;
}

sub contentspec {
    my ($self, $reader, $name) = @_;
    
    my $data = $reader->data(5);
    
    my $model;
    if ($data =~ /^EMPTY/) {
        $reader->move_along(5);
        $model = 'EMPTY';
    }
    elsif ($data =~ /^ANY/) {
        $reader->move_along(3);
        $model = 'ANY';
    }
    else {
        $model = $self->Mixed_or_children($reader);
    }

    if ($model) {
        # call SAX callback now.
        $self->element_decl({Name => $name, Model => $model});
        return 1;
    }
    
    $self->parser_error("contentspec not found in ELEMENT declaration", $reader);
}

sub Mixed_or_children {
    my ($self, $reader) = @_;

    my $data = $reader->data(8);
    $data =~ /^\(/ or return; # $self->parser_error("No opening bracket in Mixed or children", $reader);
    
    if ($data =~ /^\(\s*\#PCDATA/) {
        $reader->match('(');
        $self->skip_whitespace($reader);
        $reader->move_along(7);
        my $model = $self->Mixed($reader);
        return $model;
    }

    # not matched - must be Children
    return $self->children($reader);
}

# Mixed ::= ( '(' S* PCDATA ( S* '|' S* QName )* S* ')' '*' )
#               | ( '(' S* PCDATA S* ')' )
sub Mixed {
    my ($self, $reader) = @_;

    # Mixed_or_children already matched '(' S* '#PCDATA'

    my $model = '(#PCDATA';
            
    $self->skip_whitespace($reader);

    my %seen;
    
    while (1) {
        last unless $reader->match('|');
        $self->skip_whitespace($reader);

        my $name = $self->Name($reader) || 
            $self->parser_error("No 'Name' after Mixed content '|'", $reader);

        if ($seen{$name}) {
            $self->parser_error("Element '$name' has already appeared in this group", $reader);
        }
        $seen{$name}++;

        $model .= "|$name";
        
        $self->skip_whitespace($reader);
    }
    
    $reader->match(')') || $self->parser_error("no closing bracket on mixed content", $reader);

    $model .= ")";

    if ($reader->match('*')) {
        $model .= "*";
    }
    
    return $model;
}

# [[47]] Children ::= ChoiceOrSeq Cardinality?
# [[48]] Cp ::= ( QName | ChoiceOrSeq ) Cardinality?
#       ChoiceOrSeq ::= '(' S* Cp ( Choice | Seq )? S* ')'
# [[49]] Choice ::= ( S* '|' S* Cp )+
# [[50]] Seq    ::= ( S* ',' S* Cp )+
#        // Children ::= (Choice | Seq) Cardinality?
#        // Cp ::= ( QName | Choice | Seq) Cardinality?
#        // Choice ::= '(' S* Cp ( S* '|' S* Cp )+ S* ')'
#        // Seq    ::= '(' S* Cp ( S* ',' S* Cp )* S* ')'
# [[51]] Mixed ::= ( '(' S* PCDATA ( S* '|' S* QName )* S* ')' MixedCardinality )
#                | ( '(' S* PCDATA S* ')' )
#        Cardinality ::= '?' | '+' | '*'
#        MixedCardinality ::= '*'
sub children {
    my ($self, $reader) = @_;
    
    return $self->ChoiceOrSeq($reader) . $self->Cardinality($reader);
}

sub ChoiceOrSeq {
    my ($self, $reader) = @_;
    
    $reader->match('(') or $self->parser_error("choice/seq contains no opening bracket", $reader);
    
    my $model = '(';
    
    $self->skip_whitespace($reader);

    $model .= $self->Cp($reader);
    
    if (my $choice = $self->Choice($reader)) {
        $model .= $choice;
    }
    else {
        $model .= $sel