Sep 2008

Javascript :: Navigation im DOM-Baum und Analyse von Knoten

 
 

Die Eigenschaften von Knoten eignen sich hervorragend zur Analyse von Knoten mit Javascript (habe ich es hier mit einem Elementknoten oder mit einem Textknoten zu tun? Hat der Knoten Kinder und wenn ja, wer sind die Kinder?).

nodeNamenodeValuenodeTypechildNodes
parentNode firstChildlastChildnextSibling
previousSibling   

Die beiden Eigenschaften data und tagName fallen ein wenig aus der Rolle, denn sie sind Eigenschaften von Elementknoten, d.h. der Knoten muss sich einem XML/HTML-Tag zuordnen lassen.

node.nodeType

gibt den Typ des Knotens node zurück und ist eine der wichtigesten Analysefunktionen bei der Navigation und Manipulation des DOM-Baums mit Javascript.

node.nodeName

gibt den Namen des Knotens node als String zurück.

nodeName gibt bei Elementknoten den Namen des Tags zurück, den Namen des Attributs bei Attributknoten, den Namen eines Entites bei einem Entity oder EntityReference Knoten usw.

Knoten ohne Namen geben eine Stringkonstante zurück: Text => #text, CDATASection => , Comment => #comment, Document => #document und DocumentType =>.

Jetzt können wir uns einmal ansehen, wie unterschiedlich die Elemente eines Dokuments von den verschiedenen Browsern beurteilt werden.

var top = document.getElementsByTagName('body')[0].childNodes;
var text = '';
for (var i=0; i<top.length; i++) {
   text = text + top[i].nodeType + " " + top[i].nodeName + "\n";
}
alert(text);

Das Skript liest alle Kindknoten des BODY-Elements in das Array top. Die Anweisung im Block der for-Schleife schreibt nodeType und nodeName in die Variable text, die am Ende ausgegeben wird.

FireFox 3 #text 1 DIV 3 #text 1 DIV 3 #text 1 SCRIPT 1 SCRIPT 3 #text 1 SCRIPT 3 #text
IE 6 1 DIV 1 DIV 1 SCRIPT 1 SCRIPT 1 SCRIPT
Opera DIV #text #comment #text #comment #text DIV #text #comment #text DIV #text #text
Safari 3 #text 1 DIV 3 #text 1 DIV 3 #text 1 SCRIPT 1 SCRIPT 3 #text 1 SCRIPT 3 #text 3 #text 3 #text

node.tagName

gibt den Namen eines Elementknotens node zurück. Im Gegensatz zur allgemeineren Eigenschaft nodeName gibt tagName nur die Namen von Elementknoten wie DIV, P, IMG usw. zurück, wärend nodeName die Namen aller Knotentypen zurückgibt.

Dieses DIV-Element enthält ein P-Element und einen Kommentar

und ein Bild von Kong

kong.jpg
<div id="jsdomThisDiv">
<p>Dieses DIV-Element enthält ein P-Element und einen Kommentar</p>
<!-- einen Kommentar -->
<p>und ein Bild von Kong</p>
<img src="kong.jpg" width="152" height="145" alt="kong.jpg" />
</div>

Wenn es sich bei einem Knoten nicht um einen Elementknoten handelt, gibt tagName „undefined“ zurück, während nodeName mit allen Knotentypen klar kommt.

var jsdomThisDiv = document.getElementById('jsdomThisDiv');
var allNodes = jsdomThisDiv.childNodes;
var text = "";
for (var i=0; i<allNodes.length; i++) {
   text = text + allNodes[i].tagName + " " + allNodes[i].nodeName + "\n";
}
alert(text);

node.data

gibt Inhalt eines Textknotens node zurück

Ein bisschen Text

<p id="jsdomData">Ein bisschen Text</p>
var jsdomData = document.getElementById('jsdomData');
if (jsdomData.firstChild.nodeType == "3") {
   alert(jsdomData.firstChild.data);
}

node.nodeValue

gibt Inhalt eines Textknotens oder den Wert eines Attributknotens node zurück. nodeValue ist allgemeiner als die Eigenschaft data, die nur auf Textknoten angewendet werden kann.

<button id="jsdomF20" 
        style="background: silver; border: 1px solid gray" 
        class="someButton">nodeValue anzeigen</button>

Das Skript analysiert die Attributknoten des BUTTON-Elements und sammelt die Attribute des Elements mit der attributes-Eigenschaft in das Array attList. Der Block der for-Anweisung schreibt die Namen und den nodeValue jedes Attributs in die Variable text, die am Ende ausgegeben wird.

var jsdomValue = document.getElementById('jsdomF20');
var attList = jsdomValue.attributes;
var text = "";
for (var i=0; i<attList.length; i++) {
   text += attList[i].name + ": " + attList[i].nodeValue + "\n";
}
alert(text);

Während FireFox, Opera und Safari die Attribute anzeigen, die im HTML-Tag vorkommen, zeigt IE 6 / IE 7 alle Attribute an, die für das Tag in Frage kommen. IE 8 zeigt jetzt genauso wie alle modernen Browser nur noch die infrage kommenden Werte an.

node.childNodes

gibt ein Array aller Kindknoten von node zurück.

<div id="jsdomThisDiv">
<p>Dieses DIV-Element enthält ein P-Element und einen Kommentar</p>
<!-- einen Kommentar -->
<p>und ein Bild von Kong</p>
<img src="/jsb/repos/kong.jpg" width="152" height="145" alt="kong.jpg" />
</div>

Das Skript sammelt alle Kindknoten des Elements mit der id jsdomThisDiv in ein Array elems. Der Block der for-Anweisung schreibt den Knotennamen jedes Kindknotens in die Stringvariable text, die am Ende ausgegeben wird.

var thisElem = document.getElementById('jsdomThisDiv');
var elems = thisElem.childNodes; 
var text = ""; 
for (var i=0; i<elems.length; i++) {
   text = text + elems[i].nodeName + "\n";
}
alert (text);

node.parentNode

gibt den Elternknoten von node zurück.

Sag mal Kleiner, wer sind denn deine Eltern?

<p id="jsdomP">Sag mal Kleiner, wer sind denn deine Eltern?</p>

Das P-Element wird nach dem Laden des Dokuments anhand seines id-Attributs identifiziert. Der Event Handler onclick aktiviert die Ausgabe, wenn das P-Element mit der Maus angeklickt wird.

addEvent(window, 'load', initParent);

function initParent() {
   var jsdomP = document.getElementById('jsdomP'); 
   jsdomP.style.color = "red";
   jsdomP.style.cursor = "pointer";
   jsdomP.onclick = function() {
      alert("parentNode ist " + this.parentNode.nodeName + "\n" + 
            'parentNode vom parentNode ist ' + this.parentNode.parentNode.nodeName);
      return false;
   }
}

node.hasChildNodes

gibt true zurück, wenn node Kindknoten hat und false, wenn der Knoten node keine Kindknoten hat.

<div id="jsdomHC"></div>

Das Skript prüft mit der Eigenschaft hasChildNodes von node, ob der Knoten mit der id jsdomHC Kinder hat.

var node = document.getElementById('jsdomHC');
if (node.hasChildNodes == true) {
   alert(node.nodeName + " hat Kindknoten");
} else {
   alert(node.nodeName + " hat keine Kinder");
}

node.firstChild

gibt den ersten Kindknoten von node zurück

kong.jpg

<img id="jsdomFC" src="kong.jpg" width="152" height="145" alt="kong.jpg" />

Das Skript prüft zuerst, ob ein Element mit der ID jsdomFC existiert und falls das Element existiert, ob das Element Kindknoten hat. Wenn das Element tatsächlich Kindknoten hat, gibt das Skript den Namen des Kindknotens aus.

function showFirstChild()
{
   if (document.getElementById('jsdomFC')) {
      var jsdomFC = document.getElementById('jsdomFC');
      if (jsdomFC.hasChildNodes == true) {
         alert(jsdomFC.firstChild.nodeName);
      } else {
         alert(jsdomFC.nodeName + " hat keine Kindknoten");
      }
   } else {
      alert ("Element existiert nicht");
   }
}

node.lastChild

gibt den letzten Kindknoten von node zurück

  • Montag
  • Dienstag
  • Mittwoch
<ul id="thisUl"><li>Montag</li><li>Dienstag</li><li>Mittwoch</li></ul>

Das Skript prüft, ob der Knoten mit der id thisUl Kindknoten hat (if (node.hasChildNodes))und wenn ja, dann gibt das Skript den Namen des letzten Kindknotens aus: node.lastChild.nodeName. Das letzte LI-Element erwischt das Skript aber nur zuverläßig, weil die Tags des UL-Elements ohne Leerraum in einer Zeile stehen.

function showLast()
{
   if (document.getElementById('thisUl')) {
      var node = document.getElementById('thisUl');
      if (node.hasChildNodes) {
         alert('Letzes Kind ' + node.lastChild.nodeName);
      } else {
         alert(node.nodeName + ' hat keine Kindknoten');
      }
   } else {
      alert ( "Ein Element mit der ID thisUl existiert nicht." ); 
   }
}

node.nextSibling

gibt den nächsten Knoten auf derselben Ebene zurück – einen Knoten, der am selben Elternknoten wie node hängt.

  • Montag
  • Dienstag
  • Mittwoch
<ul id="thisUl2">
   <li>Montag</li>
   <li>Dienstag</li>
   <li>Mittwoch</li>
</ul>

Das Skript prüft, ob das Element mit der id thisUl2 Kindknoten hat, und wenn ja, setzt die Anweisung node = node.firstChild die Variable node auf das erste Kind des Knotens – am Anfang also auf den ersten Kindknoten des UL-Elements. Solange es einen nextSilbling gibt (while (node.nextSibling)), setzt der Block der while-Schleife die Variable einen Sibling weiter: node = node.nextSibling;.

function showNextSibling()
{
   var node = document.getElementById('thisUl2');
   var text = '';
   if (node.hasChildNodes) {
      node = node.firstChild;    
      while (node.nextSibling) {
         text = text + node.nodeName + ' '; 
         node = node.nextSibling;
      }
   } else {
      text = 'Knoten ' + node.nodeName + ' hat keine Kinder';
   }
   alert(text);
   return false; 
}

node.previousSibling

gibt den vorangehenden Knoten auf derselben Ebene zurück – einen Knoten, der am selben Elternknoten wie node hängt.

Hinter den Kulissen: Trau keinem Tag

Wie weit darf man sich auf das Markup verlassen? Auf das HTML-Markup darf man sich also nicht zu sehr verlassen, außerdem können Zeilenumbrüche als neuer Knoten gelesen werden. Beim Auslesen von Klassen immer bedenken, dass ein Element mehrere Klassen in einem Klassen-Attribut enthalten kann.

   


Copyright © 2000 - 2010 Media Engineering Alle Rechte vorbehalten
Design + Programmierung Media Engineering U. Häßler 47506 Neukirchen-Vluyn • Impressum und Nutzungsbestimmungen