Platzhalter

 
Platzhalter PlatzhalterPlatzhalter

XML-Tutorial V: Dokumentenstrukturen mit DTDs validieren

Platzhalter
 
  Startseite
  eBook-Projekt
  Web-Lexikon
  Bücher bestellen
   
  Design-Theorie
  Design-Praxis
  Promotion
  HTML/XML-Praxis
  Projekt-Management
  Webmaster-Praxis
  Fragen & Antworten
  Technik-Ecke
   
  Portal/Links
  Buch-Rezensionen
  Software
  Impressum
PlatzhalterPlatzhalter







 

Platzhalter XML ermöglicht, Dokumente beliebiger Strukturen und Größen zu erstellen, all das praktisch ohne Einschränkungen. Manchmal ist es jedoch sinnvoll, sich selbst Einschränkungen aufzuerlegen: wenn Sie z.B. ein Buch in XML schreiben, ist es sinnvoll, für jedes Kapitel dieselben Element-Typen zu verwenden, die dann auch noch überall die gleiche Bedeutung haben sollen. Sie definieren dann sozusagen ein eigenes Datenformat für Ihr Buch, ähnlich, wie HTML ein Datenformat für Internet-Seiten ist.

Oder, ein anderes Beispiel: Sie wollen einige persönliche Daten Ihrer Mitarbeiter in einer Datenbank zusammenstellen. Der Einfachheit halber soll jeder Mitarbeiter seine Daten selbst eintragen und zwar in XML. Wenn Sie hier kein Format definieren, in dem die Angaben gemacht werden sollen, ergibt die Aktion nichts als Datenchaos, weil jeder Mitarbeiter die verschiedenen Elemente und Attribute unterschiedlich platzieren und verwenden würde.

Das Definieren der Regeln ist die eine Seite, das Überprüfen eine andere: Sie benötigen weiterhin einen Mechanismus, der XML-Dokumente auf Regelkonformität überprüft. Einen solchen Mechanismus gibt es: die "Document Type Definitions" (DTDs) und "XML Schema". Beides sind Methoden, genau anzugeben, welche Elemente wo stehen dürfen und welche Inhalte und Attribute sie haben dürfen. In unserem Tutorial beschränken wir uns jedoch auf die DTDs - XML Schema ist eine ziemlich komplizierte Angelegenheit.

Arbeitsabläufe


Zunächst sollten Sie Ihre Anforderungen an das Datenformat festlegen: welche Attribute und Elemente werden wo benötigt? Das ist nicht ganz so einfach, wie es sich anhört. Es geht schließlich darum, einen (meist vorhandenen) Datenhaufen in eine sinnvolle hierarchische Struktur zu bringen.

Element oder Attribut


Oft stellt sich dabei auch die Frage, ob ein bestimmter Informationsbaustein nun als Element oder Attribut gespeichert werden soll. Es empfiehlt sich, echte Informationen, insbesondere längere Textabschnitte, als Element zu speichern, wohingegen Teile, die keine eigene inhaltliche Information mitbringen, ruhig als Attribute gespeichert werden können. Wenn Sie beispielsweise verschiedene persönliche Daten wie Vorname oder Telefonnummer ablegen wollen, ist es sinnvoll, das in Elementen zu tun. Geht es dagegen darum, festzulegen, ob eine Aufzählungsliste nun runde oder eckige Symbole haben soll, kann dafür ruhig ein Attribut definiert werden.

Von der Struktur zur DTD


Nachdem Sie nun in etwa wissen, welche Attribute und Elemente Sie benötigen, geht es nun darum, die DTD an sich zu schreiben. Dazu später mehr.

Dokumente validieren


Verschicken Sie die DTD jetzt an die Personen, die die Daten eingeben sollen. Zusammen mit einem Dokumenten-Validator können diese feststellen, ob die von ihnen erstellten Dokumente Ihren Spezifikationen entsprechen. Dafür muss die DTD in das zu prüfende Dokument eingebunden werden:

<!DOCTYPE adressen SYSTEM "test.dtd"> bindet test.dtd ein. Diese Steueranweisung sollte optimalerweise in der zweiten Zeile des Dokuments stehen. Es gibt noch andere Methoden, auf eine DTD zu verweisen, beispielsweise so:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Die erste Angabe ist dabei eine Verzeichnis-Angabe: der Parser soll sich damit an ein öffentliches Verzeichnis wenden und die genaue URL der DTD abfragen. Die zweite Angabe, eine tatsächliche URL, ist nur das Sicherungsseil: wenn das mit dem Verzeichnis nicht funktioniert, wird die DTD direkt von dieser URL geladen. De facto funktioniert dieses Verzeichnis-System aber nicht, wir können also im Moment noch wie im obigen Beispiel direkt auf die URL verweisen.

Nachdem die DTD nun eingebunden wurde, kann das Validator-Programm gestartet werden. Es wird der das Dokument bearbeitenden Person genaue Auskunft über eventuelle Fehler geben, diese werde korrigiert und im Endeffekt ist das Dokument genau so, wie es von der DTD spezifiziert wurde.

Achten Sie bitte darauf, dass das, was direkt hinter <!DOCTYPE steht, mit dem Wurzel-Element Ihres Dokuments identisch sein sollte.

Validator-Suche


In der Theorie jedenfalls. Das Problem sind die Validatoren: viele gibt es nicht gerade, und die meisten sind über die Kommandozeile zu bedienen. Die Browser, ja sogar der eigentlich XML-fitte Mozilla, enttäuschen hier fast auf ganzer Linie: der IE entdeckt selbst simpelste Fehler nicht, obwohl er anscheinend auf die DTD zugreift.

Ein recht praktischer Parser ist im Programm XMLSpy enthalten, das kostet in der Suite-Version dann allerdings auch 399 US-Dollar. Frei erhältlich ist dagegen das Programm nsgmls (herunterzuladen von http://www.jclark.com/sp/howtoget.htm). Nach dem Download entpacken Sie alle Dateien in ein Verzeichnis, öffnen die Eingabeaufforderung, wechseln in das Verzeichnis, in das Sie nsgmls entpackt haben, und geben dort ein:

bin\nsgmls -sv pubtext\xml.dcl c:\temp\test.xml

... wobei letzterer Pfad natürlich durch den Pfad zur zu überprüfenden Datei ersetzt werden muss. Wenn keine Fehlermeldung ausgegeben wird, ist alles in Ordnung.

DTDs schreiben


Nach diesen Erläuterungen jetzt zum technischen Teil: wie wird eine DTD geschrieben? Eigentlich ist es ganz einfach: zunächst definieren Sie, welche Elemente erlaubt sind. Dann, was diese Elemente enthalten dürfen (neue Elemente? normalen Text?). Schließlich kümmern Sie sich noch um die erlaubten Attribute.

Elemente


Ein erlaubtes Element wird innerhalb der DTD so definiert:

<!ELEMENT element_name erlaubte_inhalte>

element_name ist recht frei wählbar. erlaubte_inhalte muss entweder ersetzt werden durch ein EMPTY (für leere Elemente, wie das XHTML-<br />) oder durch eine von Klammern eingeschlossene Liste von erlaubten Inhalten.

Das Schlüsselwort #PCDATA steht für Zeichendaten, also für Text. So sieht ein Element aus, das nur Text enthalten darf:

<!ELEMENT name (#PCDATA)>

Darf ein Element auch andere Elemente enthalten, dann werden diese Element-Namen, durch Kommata getrennt, in die Klammern eingefügt:

<!ELEMENT person (name, telefon)> bedeutet, dass person-Elemente ein name- und ein telefon-Element enthalten müssen (!), und zwar genau in dieser Reihenfolge.

Wenn es möglich sein soll, verschiedene Elemente mehrmals zu verwenden oder als optional zu deklarieren, können Sie dafür verschiedene Operatoren verwenden, die immer hinter einem Element stehen. Hinweis: durch erneutes Einklammern kann man eine Gruppe von Elementen so zusammenfassen, dass Operatoren auf sie so reagieren, als wäre sie ein einzelnes Element.

Den Komma-Operator kennen Sie schon: er schreibt vor, dass bestimmte Elemente in einer bestimmten Reihenfolge verwendet werden müssen. Der Fragezeichen-Operator macht ein Element optional. Der Plus-Operator hat die Bedeutung "mindestens einmal", und der Sternchen-Operator bedeutet, dass die Verwendung völlig frei ist.

Schließlich gibt es noch den OR-Operator (|). Er bedeutet, dass von verschiedenen Elementen genau eines akzeptiert wird. (hund | katze | vogel) erlaubt also entweder eine katze, einen hund oder einen vogel.

Alle Operatoren lassen sich miteinander kombinieren. Wir demonstrieren das an einigen Beispielen:

(Absatz | Kapitel) - entweder ein Absatz oder ein Kapitel.

(Name, Telefon, Handy?, Mitarbeiter*) - ein Name, ein Telefon, eventuell ein Handy, beliebig viele (auch null) Mitarbeiter.

(Telefon | Handy | Email)* - beliebig viele Telefon-, Handy- und Email-Elemente in beliebiger Reihenfolge.

Es ist auch möglich, Elemente zu definieren, die gemischten Inhalt akzeptieren, also z.B. Text, dann ein Tag, dann wieder Text etc.:

(#PCDATA | fettschrift)*

Attribute


Attribut-Deklarationen verlaufen sehr ähnlich:

<!ATTLIST element_name liste_der_attribute>
element_name ist der Name des Elements, dem die Attribute zugeordnet werden sollen. liste_der_attribute könnte folgendermaßen aussehen:

Name    CDATA    #REQUIRED
Aktiviert    (ja | nein)    "nein"
Alternativname    NMTOKEN    #IMPLIED
Farbe    NMTOKEN    #FIXED "schwarz"


Hinweis: Sie können in DTDs praktisch beliebig Leerräume einfügen, solange Sie damit keine Wörter auseinanderreißen. Es ist also durchaus empfehlenswert, innerhalb von <!ATTLIST eigene Zeilen für jedes Attribut zu reservieren.

Diese Zeilen sind dann nach folgendem Muster aufgebaut: Name des Attributs, Typ des Attributs, Sonstiges.

Der Name ist ziemlich frei wählbar, solange Sie nicht unbedingt Sonderzeichen verwenden wollen. Der Typ spezifiziert, welche Werte dem Attribut gegeben werden dürfen:

  • CDATA - alle Zeichendaten, also auch z.B. Sonderzeichen

  • NMTOKEN - mit einem Buchstaben beginnende Zeichenkette, die nur Buchstaben, Zahlen und einige Sonderzeichen enthalten darf.

  • NMTOKENS - durch Leerzeichen getrennte NMTOKEN-Werte

  • ID
  • - ein eindeutiger Bezeichner. Der Parser meckert, wenn diese Eindeutigkeit im Dokument nicht gewährleistet ist.
  • IDREF - ein ID-Wert eines anderen Elements im Dokument. Kann für Beziehungen zwischen Elementen verwenden werden.

  • IDREFS - eine Liste von IDREF-Werten, durch Leerzeichen getrennt.

  • (x | y | z) - erlaubt als Werte nur entweder x, y oder z



Dahinter werden verschiedene Zeichenketten platziert, um das Verhalten des Attributs festzulegen. #REQUIRED bedeutet, dass der Datenverarbeiter das Attribut festlegen muss. #IMPLIED dagegen macht das Attribut optional. Ein Wert in Anführungszeichen macht das Attribut optional und setzt zugleich einen Standardwert für den Fall, dass es nicht angegeben wird. Und schließlich: #FIXED "fester_wert" legt einen festen Wert für das Attribut fest.

Tipp: um die Übersichtlichkeit zu erhöhen, können Sie mehrere Attribut-Listen für ein Element festlegen. Sie werden dann bei der Verarbeitung zusammengeführt.

Entities


Erinnern Sie sich an die Entities? So wurden sie definiert:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE inhalt
[
    <!ENTITY test "Test-String <a>test</a>">
]>
<inhalt>
&test;
</inhalt>


Der Bereich, in dem Entities im vorangegangenen Teil unseres Tutorials definiert wurden, nennt sich "interne Teilmenge" - der, Überraschung! - DTD. Sie können solche Entities auch im Haupt-Teil der DTD deklarieren, wenn Sie möchten, und sie dann genauso wie die Entities aus der internen Teilmenge verwenden. Interne Teilmenge mit externem DTD-Aufruf verbunden sieht übrigens so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE inhalt SYSTEM "irgendeine_dtd.dtd"
[
    <!ENTITY test "Test-String <a>test</a>">
]>
<inhalt>
&test;
</inhalt>


Beispiel


Wir wollen die Daten von verschiedenen Mitarbeitern einer Abteilung in einer Datenbank zusammenführen. Enthalten sein sollen der Name, die Telefon-Durchwahl und die Hierarchien der Abteilung: wer ist wessen Vorgesetzter? Attribute definieren wir hier übrigens nicht, denn die zu speichernden Daten haben für sich selbst eine eigene inhaltliche Bedeutung, was sie optimal geeignet für Speicherung in Elementen macht.

Zunächst einmal das XML-Dokument:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE mb-datenbank SYSTEM "test.dtd">
<mb-datenbank>

<abteilung>
    <name>
        IT-Abteilung
    </name>
    <angehoerige>
        <mitarbeiter>
            <nachname>Meier</nachname>
            <telefon>3421</telefon>
        </mitarbeiter>
        <mitarbeiter>
            <nachname>Müller</nachname>
            <telefon>5564</telefon>
        </mitarbeiter>        
        <mitarbeiter>
            <nachname>Hinkelstein</nachname>
            <telefon>3456</telefon>
            <untergebene>
                <mitarbeiter>
                    <nachname>Schulz</nachname>
                    <telefon>3321</telefon>
                </mitarbeiter>        
                <mitarbeiter>
                    <nachname>Zupul</nachname>
                    <telefon>6768</telefon>
                    <untergebene>
                        <mitarbeiter>
                            <nachname>Arletz</nachname>
                            <telefon>7593</telefon>
                        </mitarbeiter>                    
                    </untergebene>
                </mitarbeiter>                        
            </untergebene>
        </mitarbeiter>        
    </angehoerige>
</abteilung>

</mb-datenbank>


Die zugehörige DTD sieht so aus:

<!ELEMENT mb-datenbank (abteilung)+>
<!ELEMENT abteilung (name, angehoerige)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT angehoerige (mitarbeiter)+>
<!ELEMENT mitarbeiter (nachname, telefon, untergebene?)>
<!ELEMENT nachname (#PCDATA)>
<!ELEMENT telefon (#PCDATA)>
<!ELEMENT untergebene (mitarbeiter)+>


Autor: Alexander Dilthey | Erstmalig veröffentlicht: 06.08.2002 | Einen Artikel schreiben?

 

Artikelreihe XML
XML-Tutorial I: Allgemeines
XML-Tutorial II: Entities
XML-Tutorial III: Namensräume
XML-Tutorial IV: Style Sheets
XML-Tutorial VI: XLinks & XPointer
XML-Tutorial VII: Transformationen mit XSLT & XPath
Rezension: Einführung in XML

Neue Artikel

Rezension: Entwurfsmuster von Kopf bis Fuß
Rezension: Webdesign mit CSS
AJAX - XML und JavaScript in Schönheit vereint?
Rich Email - Flash im Newsletter
Screen Reader Usability
Comment Spam und CAPTCHAs
Logfile-Analyse selbst gemacht - ein Perl-Beispiel

Partnerprogramm




Kommentar

Ist die Freiheit der Informationsgesellschaft in Gefahr?
Derzeit leben wir in einer relativ freien Welt. Doch sind derzeit Tendenzen erkennbar, die Freiheit des Individuums den Interessen der Großindustrie zu opfern. Ein Kommentar.

Druckversion
Sie wollen diese Seite ausdrucken? Dafür haben wir eine spezielle Druckversion ohne grafische Elemente entwickelt!



Einführung in CSS bei HTMLWorld.