home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / share / perl5 / XML / ESISParser.pm < prev    next >
Encoding:
Text File  |  2003-10-21  |  19.5 KB  |  740 lines

  1. #
  2. # Copyright (C) 1999 Ken MacLeod
  3. # See the file COPYING for distribution terms.
  4. #
  5. # $Id: ESISParser.pm,v 1.9 2000/03/02 20:18:09 kmacleod Exp $
  6. #
  7.  
  8. use strict;
  9.  
  10. use IO::File;
  11. use UNIVERSAL;
  12.  
  13. package XML::ESISParser;
  14.  
  15. use vars qw{ $VERSION $NSGMLS_sgml $NSGMLS_FLAGS_sgml $NSGMLS_ENV_sgml
  16.          $NSGMLS_xml $NSGMLS_FLAGS_xml $NSGMLS_ENV_xml
  17.          $XML_DECL };
  18.  
  19. # will be substituted by make-rel script
  20. $VERSION = "0.08";
  21.  
  22. $NSGMLS_sgml = 'nsgmls';
  23. $NSGMLS_FLAGS_sgml = '-oentity -oempty -onotation-sysid -oincluded -oline -E0';
  24. $NSGMLS_ENV_sgml = '';
  25.  
  26. $NSGMLS_xml = 'nsgmls';
  27. $XML_DECL = '/usr/lib/sgml/declaration/xml.decl';
  28. $NSGMLS_FLAGS_xml = '-oentity -oempty -onotation-sysid -oline -oincluded -wxml -E0 ';
  29. $NSGMLS_ENV_xml = 'SP_CHARSET_FIXED=YES SP_ENCODING=XML';
  30.  
  31. sub new {
  32.     my $type = shift;
  33.  
  34.     return bless { @_ }, $type;
  35. }
  36.  
  37. sub parse {
  38.     my $self = shift;
  39.  
  40.     die "XML::ESISParser: parser instance ($self) already parsing\n"
  41.     if (defined $self->{ParseOptions});
  42.  
  43.     # If there's one arg and it has no ref, it's a string
  44.     my $args;
  45.     if (scalar (@_) == 1 && !ref($_[0])) {
  46.     $args = { Source => { String => shift } };
  47.     } else {
  48.     $args = (scalar (@_) == 1) ? shift : { @_ };
  49.     }
  50.  
  51.     my $parse_options = { %$self, %$args };
  52.     $self->{ParseOptions} = $parse_options;
  53.  
  54.     # ensure that we have at least one source
  55.     if (!defined $parse_options->{Source}
  56.     || !(defined $parse_options->{Source}{String}
  57.          || defined $parse_options->{Source}{ByteStream}
  58.          || defined $parse_options->{Source}{SystemId}
  59.          || defined $parse_options->{Source}{ESISStream})) {
  60.     die "XML::ESISParser: no source defined for parse\n";
  61.     }
  62.  
  63.     # assign default Handler to any undefined handlers
  64.     if (defined $parse_options->{Handler}) {
  65.     $parse_options->{DocumentHandler} = $parse_options->{Handler}
  66.         if (!defined $parse_options->{DocumentHandler});
  67.     $parse_options->{DTDHandler} = $parse_options->{Handler}
  68.         if (!defined $parse_options->{DTDHandler});
  69.     $parse_options->{ErrorHandler} = $parse_options->{Handler}
  70.         if (!defined $parse_options->{ErrorHandler});
  71.     }
  72.  
  73.     # create the NSGMLS command
  74.     my ($nsgmls_command, $nsgmls, $nsgmls_flags);
  75.     if (defined $parse_options->{NSGMLSCommand}) {
  76.     $nsgmls_command = $parse_options->{NSGMLSCommand};
  77.     } elsif (defined $parse_options->{IsSGML}
  78.          && $parse_options->{IsSGML}) {
  79.     my $declaration = (defined $parse_options->{Declaration})
  80.         ? " " . $parse_options->{Declaration} : "";
  81.     $nsgmls = $parse_options->{NSGMLS} = $NSGMLS_sgml;
  82.     $nsgmls_flags = $parse_options->{NSGMLS_FLAGS} = $NSGMLS_FLAGS_sgml;
  83.     $nsgmls_command = $parse_options->{NSGMLS_COMMAND} = "$nsgmls $nsgmls_flags $declaration";
  84.     } else {
  85.     my $declaration = (defined $parse_options->{Declaration})
  86.         ? $parse_options->{Declaration} : $XML_DECL;
  87.     $nsgmls = $parse_options->{NSGMLS} = $NSGMLS_xml;
  88.     $nsgmls_flags = $parse_options->{NSGMLS_FLAGS} = $NSGMLS_FLAGS_xml;
  89.     $nsgmls_command = $parse_options->{NSGMLS_COMMAND} = "$NSGMLS_ENV_xml $nsgmls $nsgmls_flags $declaration";
  90.     }
  91.     
  92.  
  93.     my $result;
  94.     if (defined $self->{ParseOptions}{Source}{ESISStream}) {
  95.     # read ESIS stream directly
  96.     my $system_id = (defined $self->{ParseOptions}{Source}{SystemId})
  97.         ? "\`$self->{ParseOptions}{Source}{SystemId}'" : 'ESIS Stream';
  98.     eval { $result = $self->parse_fh ($self->{ParseOptions}{Source}{ESISStream}) };
  99.     my $retval = $@;
  100.  
  101.     if ($retval) {
  102.         die "XML::ESISParser::parse: unable to parse \`$system_id'\n$retval";
  103.     }
  104.     } elsif (defined $self->{ParseOptions}{Source}{ByteStream}) {
  105.     # call nsgmls using file handle
  106.     # FIXME special case stdin?
  107.  
  108.     # For ByteStreams (Perl file handles) we create a sub-process
  109.     # that we feed the XML/SGML document and we get back the ESIS
  110.     # stream
  111.     my $retval;
  112.     my $system_id = (defined $self->{ParseOptions}{Source}{SystemId})
  113.         ? "\`$self->{ParseOptions}{Source}{SystemId}'" : 'Byte Stream';
  114.     my ($pid) = open (ESIS, "-|");
  115.     if ($pid == 0) {
  116.         # 20% speed increase if grep swipes implieds (only 8% if
  117.         # we do it in `parse_fh').  XXX use a C routine or patch SP
  118.         open (SGML, "| $nsgmls_command 2>&1 | egrep -v '^A.* IMPLIED\$'")
  119.             or die "XML::ESISParser::parse: can't run \`$nsgmls' on \`$system_id'\n";
  120.  
  121.         $self->{ParseOptions}{Source}{ByteStream}->print (*SGML);
  122.  
  123.         close (SGML)
  124.         or die "XML::ESISParser::parse: can't run \`$nsgmls' on \`$system_id'\n";
  125.  
  126.         exit 0;
  127.     } else {
  128.         eval { $result = $self->parse_fh (*ESIS) };
  129.         $retval = $@;
  130.         wait;        # clean up that process
  131.     }
  132.     close (ESIS);
  133.  
  134.     $self->{ParseOptions}{Source}{ByteStream}->close ();
  135.  
  136.     if ($retval) {
  137.         die "XML::ESISParser::parse: unable to parse \`$system_id'\n$retval";
  138.     }
  139.     } elsif (defined $self->{ParseOptions}{Source}{String}) {
  140.     # call nsgmls with a literal string
  141.     } elsif (defined $self->{ParseOptions}{Source}{SystemId}) {
  142.     # if SystemId is a file, call nsgmls with file name
  143.     # otherwise, open stream on SystemId and do ByteStream
  144.  
  145.     # FIXME this only handles file SystemIds right now
  146.     # 20% speed increase if grep swipes implieds (only 8% if
  147.     # we do it in `parse').  XXX use a C routine or patch SP
  148.     my $system_id = $self->{ParseOptions}{Source}{SystemId};
  149.     my ($fh) = IO::File->new
  150.         ("$nsgmls_command '$system_id' 2>&1 | egrep -v '^A.* IMPLIED\$' |");
  151.     die "XML::ESISParser::parse: can't run \`$nsgmls' on \`$system_id'\n"
  152.         if (!defined $fh);
  153.  
  154.     eval { $result = $self->parse_fh ($fh) };
  155.     my $retval = $@;
  156.  
  157.     close ($fh);
  158.  
  159.     if ($retval) {
  160.         die "XML::ESISParser::parse: unable to parse \`$system_id'\n$retval";
  161.     }
  162.     }
  163.     
  164.  
  165.     # clean up parser instance
  166.     delete $self->{ParseOptions};
  167.     delete $self->{DocumentHandler};
  168.     delete $self->{DTDHandler};
  169.     delete $self->{ErrorHandler};
  170.  
  171.     return $result;
  172. }
  173.  
  174. #
  175. # Parse the `ESIS' information coming from `file'
  176. #
  177.  
  178. sub parse_fh {
  179.     my ($self, $file) = @_;
  180.     my (@attributes, @properties, $files);
  181.  
  182.     my $doc_h = $self->{ParseOptions}{DocumentHandler};
  183.     my $dtd_h = $self->{ParseOptions}{DTDHandler};
  184.     my $err_h = $self->{ParseOptions}{ErrorHandler};
  185.  
  186.     # we cache these most commonly used `can()' calls
  187.     my $can_start_element = $doc_h->can('start_element');
  188.     my $can_end_element = $doc_h->can('end_element');
  189.     my $can_characters = $doc_h->can('characters');
  190.     my $can_record_end = $doc_h->can('record_end');
  191.  
  192.     my $line = 0;
  193.     $doc_h->start_document( { } )
  194.     if ($doc_h->can('start_document'));
  195.  
  196.     # 30% speed improvement by breaking the encapsulation
  197.     my ($is_filehandle) = (ref ($file) eq "FileHandle"
  198.                || ref ($file) eq "IO::File");
  199.     while ($_ = ($is_filehandle ? <$file> : $file->getline())) {
  200.     chop;
  201.  
  202.     if (/^A/) {        # attribute
  203.         # Note: the output of `nsgmls' is `grep -v'ed to get rid of
  204.         # IMPLIED attributes, if we do it here we only get an 8%
  205.         # speed boost
  206.  
  207.         my ($name, $type, $value) = split (/\s/, $', 3);
  208.  
  209.         push (@attributes, $name => $value);
  210.  
  211.         next;
  212.     }
  213.  
  214.     if (/^\(/) {        # start element
  215.         # break the encapsulation for an 8% boost
  216.         if ($#attributes >= 0) {
  217.         push (@properties, Attributes => { @attributes });
  218.         }
  219.         $doc_h->start_element ({ Name => $', @properties })
  220.         if ($can_start_element);
  221.  
  222.         @properties = (); @attributes = ();
  223.         next;
  224.     }
  225.  
  226.     if (/^\)/) {        # end element
  227.         $doc_h->end_element ({ Name => $' })
  228.         if ($can_end_element);
  229.  
  230.         next;
  231.     }
  232.  
  233.     if (/^L/) {        # line number
  234.         $line = $';
  235.  
  236.         next;
  237.     }
  238.  
  239.     if (/^-/) {        # data (including sdata entities)
  240.         # This section is derived from David Megginson's SGMLSpm
  241.         my $sdata_flag = 0;
  242.         my $out = '';
  243.         my $data = $';
  244.  
  245.         while ($data =~ /\\(\\|n|\||[0-7]{1,3})/) {
  246.         $out .= $`;
  247.         $data = $';
  248.  
  249.         if ($1 eq '|') {
  250.             # beginning or end of SDATA
  251.             if ("$out" ne '') {
  252.             if ($sdata_flag) {
  253.                 $doc_h->internal_entity_ref({ Name => $self->{'internal_entities_by_value'}{$out} })
  254.                 if ($doc_h->can('internal_entity_ref'));
  255.             } else {
  256.                 $doc_h->characters({ Data => $out })
  257.                 if ($can_characters);
  258.             }
  259.             $out = '';
  260.             }
  261.             $sdata_flag = !$sdata_flag;
  262.  
  263.         } elsif ($1 eq 'n') {
  264.             # record end
  265.             if ("$out" ne '') {
  266.             if ($sdata_flag) {
  267.                 $doc_h->internal_entity_ref({ Name => $self->{'internal_entities_by_value'}{$out} })
  268.                 if ($doc_h->can('internal_entity_ref'));
  269.             } else {
  270.                 $doc_h->characters({ Data => $out })
  271.                 if ($can_characters);
  272.             }
  273.             $out = '';
  274.             }
  275.             if ($can_record_end) {
  276.             $doc_h->record_end( { } );
  277.             } else {
  278.             $doc_h->characters({ Data => "\n" })
  279.                 if ($can_characters);
  280.             }
  281.         } elsif ($1 eq '\\') {
  282.             $out .= '\\';
  283.         } else {
  284.             $out .= chr(oct($1));
  285.         }
  286.         }
  287.         $out .= $data;
  288.         if ("$out" ne '') {
  289.         if ($sdata_flag) {
  290.             $doc_h->internal_entity_ref({ Name => $self->{'internal_entities_by_value'}{$out} })
  291.             if ($doc_h->can('internal_entity_ref'));
  292.         } else {
  293.             $doc_h->characters({ Data => $out })
  294.             if ($can_characters);
  295.         }
  296.         }
  297.  
  298.         next;
  299.     }
  300.  
  301.     if (/^s/) {        # sysid
  302.         push (@properties, SystemId => $');
  303.  
  304.         next;
  305.     }
  306.  
  307.     if (/^p/) {        # pubid
  308.         push (@properties, PublicId => $');
  309.  
  310.         next;
  311.     }
  312.  
  313.     if (/^f/) {        # file
  314.         if (!defined $files) {
  315.         $files = $';
  316.         } elsif (!ref $files) {
  317.         $files = [ $files, $' ];
  318.         } else {
  319.         push (@$files, $');
  320.         }
  321.  
  322.         next;
  323.     }
  324.  
  325.     if (/^E/) {        # external entity definition
  326.         my ($entity_data) = $';
  327.         $entity_data =~ /^(\S+) (\S+) (\S+)$/
  328.         or die "XML::ESISParser::parse_fh: bad external entity event data: $entity_data\n";
  329.         my ($name,$type,$notation) = ($1,$2,$3);
  330.         if (defined $files) {
  331.         push (@properties, GeneratedId => $files);
  332.         }
  333.         $dtd_h->external_entity_decl ({ Name => $name, Type => $type,
  334.                         Notation => $notation, @properties })
  335.         if ($dtd_h->can('external_entity_decl'));
  336.  
  337.         @properties = (); undef $files;
  338.         next;
  339.     }
  340.  
  341.     if (/^I/) {             # internal entity definition
  342.         my ($name, $type, $value) = split (/\s/, $', 3);
  343.         $self->{'internal_entities_by_value'}{$value} = $name;
  344.         $dtd_h->internal_entity_decl ({ Name => $name, Type => $type,
  345.                         Value => $value })
  346.         if ($dtd_h->can('internal_entity_decl'));
  347.  
  348.         next;
  349.     }
  350.  
  351.     if (/^&/) {        # external entity reference
  352.         my ($name) = $';
  353.         $doc_h->external_entity_ref({ Name => $name })
  354.         if ($doc_h->can('external_entity_ref'));
  355.  
  356.         next;
  357.     }
  358.  
  359.     if (/^\?/) {        # processing instruction (PI)
  360.         my ($data) = $';
  361.         if ($self->{ParseOptions}{IsSGML}) {
  362.         $doc_h->processing_instruction({ Data => $data })
  363.             if ($doc_h->can('processing_instruction'));
  364.         } else {
  365.         my ($target, $pi_data) = split (/\s+/, $data, 2);
  366.         $doc_h->processing_instruction({ Target => $target, Data => $pi_data })
  367.             if ($doc_h->can('processing_instruction'));
  368.         }
  369.  
  370.         next;
  371.     }
  372.  
  373.     if (/^N/) {        # notation definition
  374.         my ($name) = $';
  375.         if (defined $files) {
  376.         push (@properties, GeneratedId => $files);
  377.         }
  378.         $dtd_h->notation_decl ({ Name => $name, @properties })
  379.         if ($dtd_h->can('notation_decl'));
  380.  
  381.         @properties = (); undef $files;
  382.         next;
  383.     }
  384.  
  385.     if (/^S/) {        # subdoc definition
  386.         my ($name) = $';
  387.         if (defined $files) {
  388.         push (@properties, GeneratedId => $files);
  389.         }
  390.         $dtd_h->subdoc_entity_decl ({ Name => $name, @properties })
  391.         if ($dtd_h->can('subdoc_entity_decl'));
  392.  
  393.         @properties = (); undef $files;
  394.         next;
  395.     }
  396.  
  397.     if (/^T/) {        # external SGML text entity definition
  398.         my ($name) = $';
  399.         if (defined $files) {
  400.         push (@properties, GeneratedId => $files);
  401.         }
  402.         $dtd_h->external_sgml_entity_decl ({ Name => $name, @properties })
  403.         if ($dtd_h->can('external_sgml_entity_decl'));
  404.  
  405.         @properties = (); undef $files;
  406.         next;
  407.     }
  408.  
  409.     if (/^D/) {             # data attribute
  410.         # FIXME
  411.         my $message = "XML::ESISParser: can't handle data attributes yet\n";
  412.         if ($err_h->can('error')) {
  413.         $err_h->error ({ Message => $message });
  414.         } else {
  415.         die "$message";
  416.         }
  417.  
  418.         next;
  419.     }
  420.  
  421.     if (/^D/) {             # link attribute
  422.         # FIXME
  423.         my $message = "XML::ESISParser: can't handle link attributes yet\n";
  424.         if ($err_h->can('error')) {
  425.         $err_h->error ({ Message => $message });
  426.         } else {
  427.         die "$message";
  428.         }
  429.  
  430.         next;
  431.     }
  432.  
  433.     if (/^{/) {        # subdoc start
  434.         my ($name) = $';
  435.         $doc_h->start_subdoc ({ Name => $name })
  436.         if ($doc_h->can('start_subdoc'));
  437.  
  438.         next;
  439.     }
  440.  
  441.     if (/^}/) {        # subdoc end
  442.         my ($name) = $';
  443.         $doc_h->end_subdoc ({ Name => $name })
  444.         if ($doc_h->can('end_subdoc'));
  445.  
  446.         next;
  447.     }
  448.  
  449.     if (/^#/) {        # appinfo
  450.         my ($text) = $';
  451.         $doc_h->appinfo ({ Text => $text })
  452.             if ($doc_h->can('appinfo'));
  453.  
  454.         next;
  455.     }
  456.  
  457.     if (/^i/) {             # next element is an included subelement
  458.         push (@properties, IncludedSubelement => 1);
  459.  
  460.         next;
  461.     }
  462.  
  463.     if (/^e/) {             # next element is declared empty
  464.         push (@properties, Empty => 1);
  465.  
  466.         next;
  467.     }
  468.  
  469.     if (/^C/) {        # conforming
  470.         $doc_h->conforming({})
  471.         if ($doc_h->can('conforming'));
  472.  
  473.         next;
  474.     }
  475.  
  476.     if (/^$self->{ParseOptions}{NSGMLS}:/) {    # `nsgmls' error
  477.         my $message = $_;
  478.         if ($err_h->can('error')) {
  479.         $err_h->error ({ Message => $message });
  480.         } else {
  481.         die "$message\n";
  482.         }
  483.  
  484.         next;
  485.     }
  486.  
  487.     my ($op) = substr ($_, 0, 1);
  488.     my $message = "XML::ESISParser::parse_fh: ESIS command character \`$op' not recognized when reading line \`$_' around line $line ($.)";
  489.     if ($err_h->can('error')) {
  490.         $err_h->error ({ Message => $message });
  491.     } else {
  492.         die "$message";
  493.     }
  494.     }
  495.  
  496.     if ($doc_h->can('end_document')) {
  497.     return $doc_h->end_document({});
  498.     } else {
  499.     return ();
  500.     }
  501. }
  502.  
  503. 1;
  504.  
  505. __END__
  506.  
  507. =head1 NAME
  508.  
  509. XML::ESISParser - Perl SAX parser using nsgmls
  510.  
  511. =head1 SYNOPSIS
  512.  
  513.  use XML::ESISParser;
  514.  
  515.  $parser = XML::ESISParser->new( [OPTIONS] );
  516.  $result = $parser->parse( [OPTIONS] );
  517.  
  518.  $result = $parser->parse($string);
  519.  
  520. =head1 DESCRIPTION
  521.  
  522. C<XML::ESISParser> is a Perl SAX parser using the `nsgmls' command of
  523. James Clark's SGML Parser (SP), a validating XML and SGML parser.
  524. This man page summarizes the specific options, handlers, and
  525. properties supported by C<XML::ESISParser>; please refer to the Perl
  526. SAX standard in `C<SAX.pod>' for general usage information.
  527.  
  528. C<XML::ESISParser> defaults to parsing XML and has an option for
  529. parsing SGML.
  530.  
  531. `C<nsgmls>' source, and binaries for some platforms, is available from
  532. <http://www.jclark.com/>.  `C<nsgmls>' is included in both the SP and
  533. Jade packages.
  534.  
  535. =head1 METHODS
  536.  
  537. =over 4
  538.  
  539. =item new
  540.  
  541. Creates a new parser object.  Default options for parsing, described
  542. below, are passed as key-value pairs or as a single hash.  Options may
  543. be changed directly in the parser object unless stated otherwise.
  544. Options passed to `C<parse()>' override the default options in the
  545. parser object for the duration of the parse.
  546.  
  547. =back
  548.  
  549. =head1 OPTIONS
  550.  
  551. The following options are supported by C<XML::ESISParser>:
  552.  
  553.  Handler          default handler to receive events
  554.  DocumentHandler  handler to receive document events
  555.  DTDHandler       handler to receive DTD events
  556.  ErrorHandler     handler to receive error events
  557.  Source           hash containing the input source for parsing
  558.  IsSGML           the document to be parsed is in SGML
  559.  
  560. If no handlers are provided then all events will be silently ignored.
  561.  
  562. If a single string argument is passed to the `C<parse()>' method, it
  563. is treated as if a `C<Source>' option was given with a `C<String>'
  564. parameter.
  565.  
  566. The `C<Source>' hash may contain the following parameters:
  567.  
  568.  ByteStream       The raw byte stream (file handle) containing the
  569.                   document.
  570.  String           A string containing the document.
  571.  SystemId         The system identifier (URI) of the document.
  572.  
  573. If more than one of `C<ByteStream>', `C<String>', or `C<SystemId>',
  574. then preference is given first to `C<ByteStream>', then `C<String>',
  575. then `C<SystemId>'.
  576.  
  577. =head1 HANDLERS
  578.  
  579. The following handlers and properties are supported by
  580. C<XML::ESISParser>:
  581.  
  582. =head2 DocumentHandler methods
  583.  
  584. =over 4
  585.  
  586. =item start_document
  587.  
  588. Receive notification of the beginning of a document.
  589.  
  590. No properties defined.
  591.  
  592. =item end_document
  593.  
  594. Receive notification of the end of a document.
  595.  
  596. No properties defined.
  597.  
  598. =item start_element
  599.  
  600. Receive notification of the beginning of an element.
  601.  
  602.  Name             The element type name.
  603.  Attributes       A hash containing the attributes attached to the
  604.                   element, if any.
  605.  IncludedSubelement This element is an included subelement.
  606.  Empty            This element is declared empty.
  607.  
  608. The `C<Attributes>' hash contains only string values.  The `C<Empty>'
  609. flag is not set for an element that merely has no content, it is set
  610. only if the DTD declares it empty.
  611.  
  612. BETA: Attribute values currently do not expand SData entities into
  613. entity objects, they are still in the system data notation used by
  614. nsgmls (inside `|').  A future version of XML::ESISParser will also
  615. convert other types of attributes into their respective objects,
  616. currently just their notation or entity names are given.
  617.  
  618. =item end_element
  619.  
  620. Receive notification of the end of an element.
  621.  
  622.  Name             The element type name.
  623.  
  624. =item characters
  625.  
  626. Receive notification of character data.
  627.  
  628.  Data             The characters from the document.
  629.  
  630. =item record_end
  631.  
  632. Receive notification of a record end sequence.  XML applications
  633. should convert this to a new-line.
  634.  
  635. =item processing_instruction
  636.  
  637. Receive notification of a processing instruction. 
  638.  
  639.  Target           The processing instruction target in XML.
  640.  Data             The processing instruction data, if any.
  641.  
  642. =item internal_entity_ref
  643.  
  644. Receive notification of a system data (SData) internal entity
  645. reference.
  646.  
  647.  Name             The name of the internal entity reference.
  648.  
  649. =item external_entity_ref
  650.  
  651. Receive notification of a external entity reference.
  652.  
  653.  Name             The name of the external entity reference.
  654.  
  655. =item start_subdoc
  656.  
  657. Receive notification of the start of a sub document.
  658.  
  659.  Name             The name of the external entity reference.
  660.  
  661. =item end_subdoc
  662.  
  663. Receive notification of the end of a sub document.
  664.  
  665.  Name             The name of the external entity reference.
  666.  
  667. =item conforming
  668.  
  669. Receive notification that the document just parsed conforms to it's
  670. document type declaration (DTD).
  671.  
  672. No properties defined.
  673.  
  674. =back
  675.  
  676. =head2 DTDHandler methods
  677.  
  678. =over 4
  679.  
  680. =item external_entity_decl
  681.  
  682. Receive notification of an external entity declaration.
  683.  
  684.  Name             The entity's entity name.
  685.  Type             The entity's type (CDATA, NDATA, etc.)
  686.  SystemId         The entity's system identifier.
  687.  PublicId         The entity's public identifier, if any.
  688.  GeneratedId      Generated system identifiers, if any.
  689.  
  690. =item internal_entity_decl
  691.  
  692. Receive notification of an internal entity declaration.
  693.  
  694.  Name             The entity's entity name.
  695.  Type             The entity's type (CDATA, NDATA, etc.)
  696.  Value            The entity's character value.
  697.  
  698. =item notation_decl
  699.  
  700. Receive notification of a notation declaration.
  701.  
  702.  Name             The notation's name.
  703.  SystemId         The notation's system identifier.
  704.  PublicId         The notation's public identifier, if any.
  705.  GeneratedId      Generated system identifiers, if any.
  706.  
  707. =item subdoc_entity_decl
  708.  
  709. Receive notification of a subdocument entity declaration.
  710.  
  711.  Name             The entity's entity name.
  712.  SystemId         The entity's system identifier.
  713.  PublicId         The entity's public identifier, if any.
  714.  GeneratedId      Generated system identifiers, if any.
  715.  
  716. =item external_sgml_entity_decl
  717.  
  718. Receive notification of an external SGML-entity declaration.
  719.  
  720.  Name             The entity's entity name.
  721.  SystemId         The entity's system identifier.
  722.  PublicId         The entity's public identifier, if any.
  723.  GeneratedId      Generated system identifiers, if any.
  724.  
  725. =back
  726.  
  727. =head1 AUTHOR
  728.  
  729. Ken MacLeod, ken@bitsko.slc.ut.us
  730.  
  731. =head1 SEE ALSO
  732.  
  733. perl(1), PerlSAX.pod(3)
  734.  
  735.  Extensible Markup Language (XML) <http://www.w3c.org/XML/>
  736.  SAX 1.0: The Simple API for XML <http://www.megginson.com/SAX/>
  737.  SGML Parser (SP) <http://www.jclark.com/sp/>
  738.  
  739. =cut
  740.