Sven Jacobs: JavaScript, AJAX, DOM

Hallo zusammen!

Ich hänge hier was auf dem Schlauch... Stellt euch folgende Situation vor: Per JavaScript lade ich mit Hilfe des XMLHttpRequest Objekts Daten asynchron im Hintergrund nach (AJAX). Der Server bearbeitet die Anfrage und liefert mir die Antwort in Form von HTML zurück (beispielsweise eine Tabelle). Nun möchte ich mit Hilfe von JavaScript den Inhalt eines speziellen Nodes (z.B. ein div namens "results", welches zu Anfang leer ist) mit der Antwort des Servers befüllen.

Leider werden die Eigenschaften nodeValue bzw data als reiner Text interpretiert... Ich bekomme also nicht die Tabelle dargestellt, sondern nur den HTML-Code.

Muss ich jetzt wirklich die Tabelle mit createElement() und appendChild() über das DOM manuell aufbauen??

Falls ja, gibt es eventuell bereits einen JavaScript Parser, der z.B. aus einem speziellen XML-Dokument Teile der DOM-Struktur manipulieren kann? Vielleicht gibt es dafür ja auch schon einen Standard und eine DTD?

  1. 你好 Sven,

    Leider werden die Eigenschaften nodeValue bzw data als reiner Text
    interpretiert... Ich bekomme also nicht die Tabelle dargestellt, sondern
    nur den HTML-Code.

    Muss ich jetzt wirklich die Tabelle mit createElement() und appendChild()
    über das DOM manuell aufbauen??

    Ich habe das in der Version 3.4 des Forums so gelöst:

      
    var cnt = xmlhttp_get_contents(xmlhttp,forum_base_url+'?oc_t='+tid+'&t='+tid+'&a='+action+'&mode=xmlhttp&unique='+date.getTime(),null,null);  
      
    var el = document.createElement('div');  
    el.innerHTML = cnt;  
      
    list.replaceChild(el.firstChild,litem);  
    
    

    xmlhttp_get_contents() liefert dabei responseText zurück. Eine
    Schummel-Lösung, aber sie funktioniert in allen Browsern, die
    XMLHttpRequest unterstützen ;-)

    再见,
    克里斯蒂安

    --
    Kommt ein Vektor zur Drogenberatung: "Hilfe, ich bin linear abhaengig!"
    http://wwwtech.de/
    1. Hi,

      Eine
      Schummel-Lösung, aber sie funktioniert in allen Browsern, die
      XMLHttpRequest unterstützen ;-)

      echt? innerHTML wurde in Mozilla IIRC verhältnismäßig spät (1.2?) eingeführt; war das tatsächlich noch vor XMLHttpRequest?

      Cheatah

      --
      X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
      X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
      X-Will-Answer-Email: No
      X-Please-Search-Archive-First: Absolutely Yes
      1. 你好 Cheatah,

        Eine Schummel-Lösung, aber sie funktioniert in allen Browsern, die
        XMLHttpRequest unterstützen ;-)

        echt? innerHTML wurde in Mozilla IIRC verhältnismäßig spät (1.2?)
        eingeführt; war das tatsächlich noch vor XMLHttpRequest?

        Eh, da musst du dich vertun. Ich habe bis 1.0 heruntergetestet, innerHTML
        geht bereits in der 1.0. Weiter wollte ich nicht testen, sehe ich keinen Sinn
        drin.

        再见,
        克里斯蒂安

        --
        Echte Hacker benutzen Aexte. (Thomas Walter in de.org.ccc)
        http://wwwtech.de/
        1. Hi,

          Eh, da musst du dich vertun. Ich habe bis 1.0 heruntergetestet, innerHTML
          geht bereits in der 1.0.

          okay, dann stimmt meine Erinnerung nicht. Danke für die Aufklärung.

          Weiter wollte ich nicht testen, sehe ich keinen Sinn drin.

          Zustimmung :-)

          Cheatah

          --
          X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
          X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
          X-Will-Answer-Email: No
          X-Please-Search-Archive-First: Absolutely Yes
    2. Na klar, an innerHTML hatte ich nicht gedacht! Vielen Dank! Aber wieso der Umweg mit replaceChild()? Wieso nicht direkt

        
        // data wird weiter oben mit dem responseText befüllt ...  
        document.getElementById( 'test' ).innerHTML = data;  
      
      
      1. 你好 Sven,

        Na klar, an innerHTML hatte ich nicht gedacht! Vielen Dank! Aber wieso der
        Umweg mit replaceChild()? Wieso nicht direkt

        // data wird weiter oben mit dem responseText befüllt ...
          document.getElementById( 'test' ).innerHTML = data;

          
        Ich ersetze ein bestimmtes Element aus einer <ol>-Liste. Würde ich direkt  
        mit innerHTML arbeiten, hätte die Liste danach nur noch ein Element :)  
          
        再见,  
         克里斯蒂安  
        
        -- 
        Es ist uns nicht möglich, in einem Bereich unseres Lebens richtig zu verhalten, wenn wir in allen anderen falsch handeln. Das Leben ist ein unteilbares Ganzes.  
          
        <http://wwwtech.de/>  
        
        
  2. Hallo,

    Per JavaScript lade ich mit Hilfe des XMLHttpRequest Objekts Daten asynchron im Hintergrund nach (AJAX). Der Server bearbeitet die Anfrage und liefert mir die Antwort in Form von HTML zurück (beispielsweise eine Tabelle). Nun möchte ich mit Hilfe von JavaScript den Inhalt eines speziellen Nodes (..) mit der Antwort des Servers befüllen.

    Muss ich jetzt wirklich die Tabelle mit createElement() und appendChild() über das DOM manuell aufbauen??

    Ich verstehe nicht recht, was dein Problem ist.

    Der Server liefert HTML (text/html) zurück. Dieses kannst du nur über responseText auslesen. Das kennst du ja.

    Der Sinn von XMLHttpRequest ist die Übertragung von XML-Dokumenten. Wenn dein Server ein XML-Dokument zurückgibt (z.B. mit dem MIME-Typ application/xml), wird es geparst und du kannst über die Eigenschaft responseXML des XMLHttpRequest-Objekts darauf gemäß dem DOM zugreifen (responseXML ist ein Document-Objekt). (DOM HTML ist dann übrigens nicht verwendbar.)

    Das XML-Dokument muss kein vollständiges (X)HTML-Dokument sein, sondern muss nur irgendwelche Elemente aus dem XHTML-Namespace enthalten. Sinnvollerweise nimmt man ein div-Element als Wurzelelement. Etwa so:
    <?xml version="1.0" encoding="utf-8" ?>
    <div xmlns="http://www.w3.org/1999/xhtml">
    <p>foo</p>
    <p>bar</p>
    <p>baz</p>
    </div>

    Das bastelt man nun z.B. so in ein Dokument ein:

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

    <script type="text/javascript">
    function load (e) {
        if (request.readyState != 4) return;
        if (!request.responseXML) {
            window.alert("responseXML nicht verfügbar");
            return false;
        }
        var doc = request.responseXML;
        if (!doc.documentElement) {
            window.alert("document.documentElement nicht vergübar");
            return false;
        }
        var root = doc.documentElement;
        var node;
        if (document.importNode) {
            node = document.importNode(root, true);
        } else if (root.cloneNode) {
            node = root.cloneNode(true);
        }
        document.getElementById("div").appendChild(node);
    }
    var request = new XMLHttpRequest();
    request.open("GET", "test.xml");
    request.onreadystatechange = load;
    request.send(null);
    </script>

    Der Elementknoten muss über importNode bzw. cloneNode für MSIE importiert werden. (Siehe auch </archiv/2005/3/t104297/#m643227> und </archiv/2005/2/t101046/#m620024>.)
    Obiges Script im MSIE ungetestet, die Abfragen in der Funktion sollten den IE aber berücksichtigen, bis auf new XMLHttpRequest, wo man im MSIE eben über new ActiveXObject geht.
    Den appendChild-Methodenaufruf kann man zur Sicherheit in einem try-catch-Statement unterbringen.

    Falls ja, gibt es eventuell bereits einen JavaScript Parser, der z.B. aus einem speziellen XML-Dokument Teile der DOM-Struktur manipulieren kann? Vielleicht gibt es dafür ja auch schon einen Standard und eine DTD?

    Was meinst du? Du hast ganz normal DOM-Core-Zugriff auf das XML-Dokument. DTDs bzw. Dokumenttyp-Angaben sind nicht notwendig.

    Mathias

    1. Wenn dein Server ein XML-Dokument zurückgibt (z.B. mit dem MIME-Typ application/xml), wird es geparst und du kannst über die Eigenschaft responseXML des XMLHttpRequest-Objekts darauf gemäß dem DOM zugreifen (responseXML ist ein Document-Objekt). (DOM HTML ist dann übrigens nicht verwendbar.)

      Übrigens kannst du, wenn du keinesfalls HTML als XML senden willst (denn es muss freilich wohlgeformte XML-Syntax verwenden, also es muss quasi ein XHTML-Schnipsel sein) oder unbedingt das HTML-DOM verwenden willst, auch klassisch einen unsichtbaren iframe verwenden, in dem du das HTML-Dokument lädst. Dazu siehe wie gesagt </archiv/2005/2/t101046/#m620024>.

    2. if (document.importNode) {
              node = document.importNode(root, true);
          } else if (root.cloneNode) {
              node = root.cloneNode(true);
          }

      Das geht nicht, wie ich mir das dachte. Im MSIE 6 ist importNode undefined, aber auch root.cloneNode steht nicht zur Verfügung, zumindest springt MSIE nicht in den zweiten Block. Ich suche einmal weiter.

      1. node = root.cloneNode(true);

        Das geht nicht, wie ich mir das dachte.

        Ich krieg's nicht hin. Diese Zeile führt im MSIE immer zu einem Fehler »Schnittstelle nicht unterstützt«. Dasselbe, wenn ich den fremden Knoten direkt einhängen will. Keine Ahnung, woran das liegt. Die AJAX-Bibliotheken, die ich mir angeschaut habe, arbeiten auch nur mit cloneNode.

        Mathias

    3. Der Sinn von XMLHttpRequest ist die Übertragung von XML-Dokumenten.

      Richtig! Aber dieses Objekt kann man ja nun "missbrauchen", um z.B. auch text/html zurückzuliefern. Das Verfahren nennt man dann AJAX (http://de.wikipedia.org/wiki/AJAX).

      1. Hallo,

        Der Sinn von XMLHttpRequest ist die Übertragung von XML-Dokumenten.

        Richtig! Aber dieses Objekt kann man ja nun "missbrauchen", um z.B. auch text/html zurückzuliefern. Das Verfahren nennt man dann AJAX (http://de.wikipedia.org/wiki/AJAX).

        Äh. Was willst du mir sagen?

        Ich weiß, was AJAX ist. Den Wikipedia-Artikel habe ich übrigens mitgeschrieben.

        AJAX heißt nicht notwendigerweise »Zurückliefern von HTML«. Viele verstehen unter AJAX sogar ausdrücklich nicht das Übertragen von Daten in fertigem HTML, sondern in schlankem XML, was dann clientseitig transformiert wird. Im Wikipedia-Artikel stand einmal »Der Server antwortet mit XML-Daten, die dann vom Browser in das DOM eingefügt und dann angezeigt werden«. Das habe ich abgeschwächt, weil mir klar ist, dass viele HTML-Schnipsel nachladen und mit innerHTML einmontieren. Das kann man als Missbrauch sehen, weil HTML je nach Daten nicht das optimale Austauschformat ist.

        Im Übrigen ist es ja HTML, wovon wir reden, es wird nur als XML ausgeliefert und hat XML-Syntax.

        Wie auch immer, das Ausliefern als XML-Schnipsel aus dem XHTML-Namespace ermöglicht den DOM-Zugriff über responseXML. Wenn du darauf nicht eingehen willst, meinetwegen, innerHTML funktioniert ja.

        Mathias

        1. Ich weiß, was AJAX ist. Den Wikipedia-Artikel habe ich übrigens mitgeschrieben.

          Entschuldigung.

          AJAX heißt nicht notwendigerweise »Zurückliefern von HTML«. Viele verstehen unter AJAX sogar ausdrücklich nicht das Übertragen von Daten in fertigem HTML, sondern in schlankem XML, was dann clientseitig transformiert wird.

          Es kommt immer auf die Situation an. Ob XML nun schlanker als HTML ist, darüber lässt sich auch streiten. Denn wenn ich eine Seite über mehrere XML-Requests zusammenstricke, ist immer ein unnötiger Overhead dabei (z.B. die XML-Deklaration). Eine clientseitige Transformation kann dann sinnvoll sein, wenn viele Daten formatiert werden müssen. Dann erstellt erst der Client das fertige HTML. Nachteil ist hier natürlich, wie bei allen Client-Lösungen, dass es viele verschiedene Implementierungen (=Browser) gibt und somit Bugs und Eigenheiten, auf die ich achten muss. Wenn ich mir mein HTML über Templates auf dem Server zusammenstricke und das Produkt an den Client schicke, weiss ich wenigstens, dass es funktioniert.

          Für eine eigene AJAX-Implementierung in PHP5 benutze ich zum Beispiel das kompaktere JSON-Format, um Datentypen zwischen JavaScript und PHP5 auszutauschen. Dies wird im Moment jedoch nur für einfache Rückgabewerte aus PHP5-Funktionen und -Methoden benutzt. Jetzt suche ich nach einer Möglichkeit, wie ich direkt ganze Teile einer Seite über einen AJAX-Request ersetzen/erneuern kann, welche auf PHP-Seite generiert wurden. Möglicherweise ist Deine XML-Lösung hier die eleganteste...