Das Document Object Model
Nach obenJavascript und HTML
Javascript in HTML zu verwenden, macht meist nur dann Sinn, wenn es in der Lage ist, den Inhalt einer Seite anzupassen und zu verändern.
Zu diesem Zweck gibt es zwei gebräuchliche Methoden:
document.write()fügt Code an der aktuellen Position ins Dokument einobjekt.innerHTMLbietet Zugriff auf den HTML Code eines Elements
Beide Methoden funktionieren einwandfrei und sind mittlerweile auch sehr kompatibel.
Nach obenNachteile
Leider haben nur beide Methoden einen
großen Nachteil: Sie sind HTML spezifisch.
innerHTML
ist schon vom Namen her auf HTML bezogen.
Auf XML Dokumente lässt sich damit also nicht
zugreifen.
Das Document Object Model
Die w3c definiert das Document Object Model als "plattform- und sprachunabhängige Schnittstelle, die es Programmen und Scripten erlaubt, dynamisch Einfluss auf Inhalt, Struktur und Style von Dokumenten zu nehmen." Weiter heißt es, "Ein Dokument könne verarbeitet und das Resultat dieser Verarbeitung wieder in die präsentierte Seite einfließen."
Grob gesprochen ist das w3c DOM also der Versuch, eine einheitliche Schnittstelle für den Zugriff auf XML Dokumente zu erhalten. Wenngleich es vorrangig um (X)HTML geht, kann man es also auch zum Zugriff auf (andere) XML Daten verwenden.
Nach obenXHTML
Will ein Entwickler XHTML verwenden, ist er auf das Document Object Model angewiesen: Als XML Sprache verfügt XHTML nicht mehr über die überholten Methoden zur Veränderung von Inhalten.
Das DOM ist hier also nicht nur Option, sondern einzige sinnvolle Möglichkeit zur Änderung von Dokumenten.
Diese Inkompatibilität macht sich nur bemerkbar,
wenn man XHTML mit korrektem
Content-Type, also nicht als
text/html ausliefert.
Warum dieser Artikel?
Ich werde im Folgenden die Grundsätze des Document Object Models erläutern.
Ich werde dabei versuchen, Anfängern wie Fortgeschrittenen einen guten Zugang zur Materie zu verschaffen.
Minimale Javascript Kenntnisse sollten allerdings vorhanden sein.
Nach obenInhalt
- Knotenpunkte
- Zugriff auf Objekte
- Neue Objekte erstellen
- Objekte einfügen
- Objekte ändern
- Objekte löschen
- Weitere Funktionen
Knotenpunkte
Der Idee von XML entsprechend unterteilt
das DOM ein Dokument in Nodes (engl. Knoten)
- jedes Element eines Dokuments ist ein
eines Objekt.
Der Code
<p>
Text
</p>
Enthält 2 Nodes: Zum einen den Absatz "p", zum anderen die so genannte Textnode "Text".
Nach obenZugriff auf Objekte
Jeder dieser Knotenpunkte besitzt mehrere Möglichkeiten, auf Kind- und Elternelemente zuzugreifen:
objekt.parentNodeist das Elternelement eines Elementsobjekt.firstChildist das erste Kindelement eines Objektes.objekt.nextSiblinggibt das Element zurück, dassobjektauf gleicher Ebene folgt.objekt.previousSiblinggibt analog das vorhergehende Objekt zurück.objekt.lastChildist entsprechend das letzte Kindelement eines Objektes.objekt.childNodes[]ist ein Array, das alle Unterelemente enthält.
objekt.firstChild.parentNode würde
also wieder auf objekt verweisen.
Der Internet Explorer interpretiert bei
den Childnodes leider anders als andere
Browser: Für ihn sind Leerstellen zwischen
Tagnamen keine Textnodes. Das führt dazu,
dass Firefox und Opera
body.firstChild
meist eine Textnode darstellt (Mit den
Leerzeichen am Anfang eines HTML Body als
Wert), man im Internet Explorer dagegen
das erste Element zurückgegeben bekommt.
Eine Lösung dieses Problems werde ich im
unteren Beispiel aufführen.
Letztlich gibt es zwei sehr bekannte Methoden, auf Objekte zuzugreifen:
document.getElementById()gibt das Objekt mit der als Parameter übergebenen ID zurück.document.getElementsByTagName()gibt alle Elemente eines Typs (z.B.<p>) als Array zurück.
<body>
<div id="abs1">
<p>
Foobar
</p>
</div>
<script type="text/javascript">
var abs1 = document.getElementById("abs1");
// Das erste Kindelement laden, dass kein leeres
// Textelement ist
// 3 steht für eine Textnode
if(abs1.firstChild.nodeType == 3)
myChild = abs1.childNodes[1];
else
myChild = abs1.firstChild;
// myChild ist nun in jedem Fall das <p> Element
// Dessen erstes Kindelement ist eine Textnode,
// deren Wert "Foobar" sein sollte:
alert(myChild.firstChild.nodeValue);
// Wer aufgepasst hat, sollte nun auch wissen,
// dass der Inhalt eines Knotens in der
// Eigenschaft nodeValue steckt ;)
</script>
</body>
Nach obenNeue Objekte erstellen
Neue Objekte zu erstellen ist denkbar einfach: Man kann entweder völlig neue Elemente erstellen oder bestehende kopieren.
Neue Objekte erstellt man über
document.createElement(); als
Parameter übergibt man den Namen des zu
erstellenden Elements, z.B. p
Kopieren kann man Objekte über deren
cloneNode() Methode, der man als
Pareter übergeben kann, ob Kindknoten mitkopiert
werden sollten. Hier sollte fast immer
true angegeben werden.
neuerParagraph = document.createElement("p");
kopieDavon = neuerParagraph.cloneNode(true);
Auch TextNodes müssen erstellt werden,
dafür bietet das document
Objekt eine Funktion:
textNode = document.createTextNode("Text");
Als Parameter kann man einen Text übergeben.
Nach obenObjekte einfügen
Sowohl Textnodes als auch Absätze bringen wenig, wenn man sie nicht ineinander, bzw. den Absatz in das Dokument einbauen kann.
Hierfür bietet das DOM mehrere Funktionen:
objekt.appendChild()fügt ein Objekt hinten an ein anderes an.objekt.insertBefore()fügt das Objekt, das als erster Parameter übergeben wurde, vor dem Objekt, dass als zweiter Parameter übergeben wurde, an das Objektobjektan.objekt.insertAfter()funktioniert analog zuinsertBefore, fügt aber hinter dem anderen Element an.
Verwirrt? Vielleicht verhilft ein Beispiel zu besserem Verständnis:
<script type="text/javascript">
// Absatz erstellen
Absatz = document.createElement("p");
// Text für den Inhalt erstellen
Text = document.createTextNode("Inhalt von Absatz 1");
// Text einfügen
Absatz.appendChild(Text);
// Absatz in das Dokument einfügen
document.body.appendChild(Absatz);
// Einen neuen Absatz erstellen
Absatz2 = document.createElement("p");
// Wiederum einen Text einfügen
Absatz2.appendChild(document.createTextNode("Absatz 2"));
// Diesen Absatz vor dem ersten Absatz einfügen
document.body.insertBefore(Absatz2, Absatz);
// An den ersten Absatz eine weitere Textnode anfügen:
Absatz.appendChild(document.createTextNode("Text"));
</script>
Nach obenObjekte ändern
Natürlich kann man auch Objekte im Nachhinein ändern. Das geschieht über deren Eigenschaften.
Texte ändert man über die nodeValue
Eigenschaft.
Für weitere Attribute verwendet man die
bekannten JS Möglichkeiten.
Das folgende Beispiel orientiert sich am Beispiel aus dem vorherigen Abschnitt:
<script type="text/javascript">
// Referenz auf den ersten Textabschnitt des
// Absatzes holen
Text = Absatz.firstChild;
// Text ändern
Text.nodeValue = "Anderer Text";
// Dies ändert nichts am Text "Text", der später
// angefügt wurde, da er in einer anderen Node
// abgelegt ist!!
// Das Aussehen des Absatzes per CSS ändern
Absatz.style.fontFamily = "monospace";
</script>
Nach obenObjekte löschen
Um Objekte wieder zu löschen, muss man
sie an die removeChild Methode
des Elternelementes übergeben:
<script type="text/javascript">
Absatz.removeChild(Absatz.lastChild);
document.body.removeChild(Absatz2);
</script>
(Denkbar einfach, oder?)
Nach obenWeitere Funktionen
Das DOM bietet noch weitere Funktionen zum Zugriff auf Elemente, die jedoch weniger häufig genutzt werden. Hier eine Übersicht über weitere wichtige Funktionen des Document Objektes. Für noch mehr Funktionen lies dich am Besten durch die Links.
| Funktion | Beschreibung |
|---|---|
| setAttribute | Set ein Attribut für eine Node (z.B. href bei Links) |
| createElementNS | Erstellt ein Element in einem anderen Namespace |
| replaceChild | Ersetzt eine Node durch eine andere |
Aufwändig?
Wenn du das alles ziemlich aufwändig findest, muss ich dir leider recht geben: Das sehe ich auch so.
Dennoch macht das DOM der w3c Sinn; und in XHTML hat man ohnehin keine andere Wahl, als es zu nutzen.
Von daher lohnt es auch nicht, sich zu beschweren :)
Nach obenSprachliche Anmerkung
Auch die browserspezifischen Zugriffsmodelle werden im Sprachgebrauch DOM genannt. Korrekterweise ist auch das w3c DOM unterteilt in mehrere Ebenen. Wenn man von "dem DOM" redet, ist aber meist das XML Modell der w3c gemeint.
Nach oben
fphilipe
Super Artikel.
Jedoch finde ich wenn du schon von XML sprichst, solltest du auch die XML Variante von createElement(), nämlich createElementNS(), ansprechen.
Pberndt
createElementNS ist nicht die XML Variante sondern lediglich die Variante für das Erstellen von Objekten in anderen Namespaces.. Hast aber recht, ich sollte zumindest einen Verweis darauf anlegen. Genau so auf createAttribute und replaceChild. Ich bau wohl heut nachmittag noch eine Methodenreferenz für das Document Objekt ein.
curi
Zu dem Code sollte vielleicht jedesmal noch ein Beispiel (?).
Wäre dann vielleicht anschaulicher :)
dipser
Ich hab mal einen Konverter von XML zu DOM geschrieben. Ich dachte auch, dass die gängigen Methoden einfach zu kompliziert sind, daher dachte ich, man muss doch enfach XML/XHTML an eine Funktion übergeben können und diese erzeugt für einen den DOM Knoten, wie auch innerHTML das tut. (innerHTML ist aber kein anerkannter Standard... wers braucht :D)
- renegat.org