DTD-Handler

(Auszug aus "Perl & XML" von Erik T. Ray & Jason McIntosh)

XML::Parser::PerlSAX unterstützt eine weitere Gruppe von Handlern, mit denen DTD-orientierte Events verarbeitet werden können . Diese Handler kümmern sich um alles, was vor dem Wurzelelement stehen kann, darunter die XML-Deklaration, die Dokumenttypdeklaration, den internen Bereich usw. Alles das zusammen bezeichnen wir als Prolog des Dokuments. Wenn man das Dokument wirklich komplett und originalgetreu wiedergeben will (zum Beispiel eben in einem Filter), dann muß man einige dieser Handler implementieren, um den Prolog zu reproduzieren. Das ist genau das, was uns im letzten Beispiel gefehlt hat.

Man kann diese Handler auch für andere Zwecke verwenden. Zum Beispiel wäre es denkbar, einige Entitydefinitionen vorzuladen, um sie gesondert zu behandeln. Im Normalfall würde man diese Arbeit dem Parser überlassen. Die DTD-orientierten Handler sehen Sie in der folgenden Tabelle.

Tabelle: DTD-Handler von PerlSAX

Methodenname Event Properties
entity_decl Der Parser hat eine Entitydeklaration gelesen. Dieses Event ist stets dasselbe, egal ob internes oder externes Entity oder vom Parser analysiert. Vom Parser nicht analysierte Entities werden eventuellnormalerweise auch über dieses Event gemeldet. Name, Value, PublicId, SystemId, Notation
notation_decl Der Parser meldet die Deklaration einer Notation. Name, PublicId, SystemId, Base
unparsed_entity_decl Der Parser hat die Deklaration eines nichtanalysierten Entity gefunden (zum Beispiel ein Entity mit Binärdaten). Fehlt dieser Handler, wird das Event mit Hilfe von entity_decl() gemeldet. Name, PublicId, SystemId, Base
element_decl Eine Elementdeklaration wurde gefunden. Name, Model
attlist_decl Eine Attributdeklaration wurde gefunden. Jedes Attribut wird einzeln gemeldet, auch wenn mehrere in einer Attributliste deklariert werden. ElementName, AttributeName, Type, Fixed
doctype_decl Die Dokumenttypdeklaration wird vom Parser gemeldet. Name, SystemId, PublicId, Internal
xml_decl Eine XML-Deklaration wurde gefunden. Version, Encoding, Standalone

Der Handler entity_decl( ) wird für alle Arten von Entitydeklarationen aufgerufen. Das gilt allerdings nur, wenn kein spezifischerer Handler vorhanden ist. Mit anderen Worten: Die Deklaration eines nicht vom Parser analysierten Entity bewirkt einen Aufruf des Handlers entity_decl( ), es sei denn, man hat auch den Handler unparsed_entity_decl( ) definiert, der in diesem Fall Vorrang genießt.

Die Parameter eines entity_decl( )-Handlers hängen vom Typ des Entity ab. Bei internen Entities ist die Property Value gesetzt, andernfalls fehlt sie. Ganz analog geben PublicId und SystemId dem XML-Prozessor an, wo man die Datei mit dem wirklichen Wert des Entity findet, wenn es sich um ein externes Entity handelt. Bei internen Entities gilt das dagegen nicht. Die Basis (Base) ist eine URL, die man als Ausgangspunkt verwenden kann, wenn die SystemId einen relativen Pfad enthält.

Notationsdeklarationen sind ein spezielles Feature der DTDs. Sie erlauben die Zuweisung eines speziellen Typbezeichners zu einem Entity. Zum Beispiel könnte man deklarieren, daß ein Entity den Typ »date« hat, und damit dem XML-Prozessor sagen, daß das Entity ein Datum enthält oder enthalten muß. Notationen werden in der Praxis so gut wie nie verwendet, so daß wir sie an dieser Stelle ruhigen Gewissens ignorieren können.

Die Property Model des Handlers element_decl( ) enthält die Grammatik des Elements, die als Inhaltsmodell (Content-Modell) bezeichnet wird. Die Grammatik beschreibt, was die DTD innerhalb dieses Elements erlaubt.

Wie der Name schon sagt, kann eine Attributlistendeklaration mehrere Attribute deklarieren. Glücklicherweise kümmert sich darum der Parser und übergibt dem Handler attlist_decl( ) nur jeweils genau ein Attribut.

Die Dokumenttypdeklaration ist ein optionaler Teil des Dokuments, der direkt auf die XML-Deklaration folgt, falls er vorhanden ist. Der Parameter Name ist der Name des Wurzelelements. PublicId und SystemId geben dem Prozessor an, von wo er eine eventuelle externe DTD laden soll. Der Parameter Internal enthält den gesamten internen Bereich als String, falls man die einzelnen Entity- und Elementdeklarationen überspringen will.

Nehmen wir beispielsweise an, wir wollten das Filterbeispiel so erweitern, daß der Dokumentprolog unverändert durchgereicht wird. Dazu könnten wir die Handler aus folgendem Beispiel benutzen.

Beispiel: Ein verbesserter Filter

# Behandlung von XML-Deklarationen     
#
sub xml_decl {
     my( $self, $properties ) = @_;
     output( "<?xml version=\"" . $properties->{'Version'} . "\"" );
     my $encoding = $properties->{'Encoding'};
     output( " encoding=\"$encoding\"" ) if( $encoding );
     my $standalone = $properties->{'Standalone'};
     output( " standalone=\"$standalone\"" ) if( $standalone );
     output( "?>\n" );
}

#
# Behandlung von Dokumenttypdeklarationen:
# Duplikation des Originals, so gut wie möglich
#
sub doctype_decl {
     my( $self, $properties ) = @_;
     output( "\n<!DOCTYPE " . $properties->{'Name'} . "\n" );
     my $pubid = $properties->{'PublicId'};
     if( $pubid ) {
     output( " PUBLIC \"$pubid\"\n" );
     output( " \"" . $properties->{'SystemId'} . "\"\n" );
     } else {
     output( " SYSTEM \"" . $properties->{'SystemId'} . "\"\n" );
     }
     my $intset = $properties->{'Internal'};
     if( $intset ) {
     $in_intset = 1;
     output( "[\n" );
     } else {
    output( ">\n" );
  }
}

#
# Behandlung von Entitydeklarationen im internen Bereich:
# Stelle die ursprüngliche Deklaration wieder her
#
sub entity_decl {
     my( $self, $properties ) = @_;
     my $name = $properties->{'Name'};
     output( "<!ENTITY $name " );
     my $pubid = $properties->{'PublicId'};
     my $sysid = $properties->{'SystemId'};
     if( $pubid ) {
     output( "PUBLIC \"$pubid\" \"$sysid\"" );
     } elsif( $sysid ) {
     output( "SYSTEM \"$sysid\"" );
     } else {
     output( "\"" . $properties->{'Value'} . "\"" );
     }
     output( ">\n" );
}

Betrachten Sie die Ausgabe des verbesserten Filterprogramms, die Sie im nächsten Beispiel finden.

Beispiel: Ausgabe des verbesserten Filters

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE book
SYSTEM "/usr/local/prod/sgml/db.dtd"
[
<!ENTITY schwachsinn "hoo hah blah blah">
]>
<book id="mybook">
    <title>Einführung in GRXL</title>
    <chapter id="intro">
        <title>Was ist GRXL?</title>
        <comment> Der Titel sollte schmissiger werden. </comment>
        <para>
            Einfach ein weiteres Akronym. Das war unsere ursprüngliche Absicht, aber dann stellte
            sich mehr und mehr heraus, wie verblüffend nützlich diese neue Technologie namens
            <literal>GRXL</literal> ist. Betrachten Sie das folgende Programm:
        </para>
        <programlisting>AH aof -- %%%%
{{{{{{ let x = 0 }}}}}}
print! <lineannotation>wow</lineannotation>
oder nicht!</programlisting>
        <comment> Welchen Font sollten wir hier benutzen? </comment>
        <para>
            Was das Programm macht? Wen kümmert’s? Es sieht einfach cool aus, oder nicht?
            Wirklich, ich kann echt nur eines sagen: "&schwachsinn;".
        </para>
    </chapter>
</book>

Das ist schon viel besser. Damit haben wir ein komplettes Filterprogramm. Der Basishandler kümmert sich um die Elemente und ihren Inhalt. Die DTD-Handler sind für das zuständig, was außerhalb des Wurzelelements so abgeht.

  

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Perl & XML bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2003 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Perl & XML" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de