Siri: AJAX - XML - IE

Hallo,

per Ajax lade ich ein HTML-Dokument in die Variable checkResponseXML:

  
try {  
	var http = null;  
	  
	if (window.XMLHttpRequest) {  
		http = new XMLHttpRequest();  
	} else if (window.ActiveXObject) {  
		http = new ActiveXObject("Microsoft.XMLHTTP");  
	}  
  
	if (http != null) {  
		http.open("GET", completeUrl, false);  
		http.onreadystatechange = function () {  
			if (http.readyState == 4) {					  
				checkResponseXML = http.responseXML;  
			}  
		}  
		http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');  
		http.send();  
	}  
	  
} catch(e) {  
  
}

Das Ergebnis von checkResponseXML ist ein gültiges HTML-Dokument mit Doctype-Deklaration:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
	<head>  
		<meta charset="utf-8"/>  
		<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>  
		<title>Index</title>  
		<meta http-equiv="cache-control" content="no-cache"/>  
		<meta http-equiv="pragma" content="no-cache"/>  
		<meta name="keywords" content=""/>  
		<meta name="description" content=""/>  
		<link rel="stylesheet" href="http://127.0.0.1/css/screenbasic.css" type="text/css"/>  
	</head>  
	<body>  
		<div id="additionalnav">  
			<ul class="obligatory">  
				<li class="obligatory">  
					<a href="#">Impressum</a>  
				</li>  
				<li class="obligatorysep">|</li>  
				<li class="obligatory">  
					<a href="#">Kontakt</a>  
				</li>  
			</ul>  
		</div>  
	</body>  
</html>

var newAdditionalnavNav = checkResponseXML.getElementById("additionalnav");
FF kann mit getElementById auf Elemente des HTML-Dokuments zugreifen, InternetExplorer (8) nicht...
IE8: Object doesn't support this property or method

Kann man checkResponseXML noch irgendwie umwandeln, damit das auch der IE kann?

Viele Grüße
Siri

  1. Hallo Siri,

    da ich mich auf den korrekten Mime-Type nicht verlassen kann, werte ich responseText aus. Mein Parser sieht so aus:

      function xmlParse(str) {  
        str = str.replace(/>\s+</g,"><");  
        if (typeof ActiveXObject != 'undefined' && typeof GetObject != 'undefined') {  
          var doc = new ActiveXObject('Microsoft.XMLDOM');  
          doc.loadXML(str);  
          return doc;  
        }  
        if (typeof DOMParser != 'undefined') {  
          return (new DOMParser()).parseFromString(str, 'text/xml');  
        }  
        return document.createElement("div");  
      } // xmlParse  
    
    

    auf den Returnwert greife ich dann mit DOM-Methoden zu.

    Gruß, Jürgen

    1. Hallo Jürgen,

      auch nach dem parsen bleibt es im IE8 ein IXMDOMDocument2 (was auch immer das ist?!) und die Methode getElementById liefert die Eingangs beschriebene Fehlermeldung zurück.

      Grüße
      Siri

      1. Hallo Siri,

        ich greife mit

        var gpxmetadata = xml.documentElement.getElementsByTagName("metadata");

        auf die Daten zu. xml ist der Rückgabewert von xmlParse.

        Gruß, Jürgen

        1. Hallo

          var gpxmetadata = xml.documentElement.getElementsByTagName("metadata")

          auf die Daten zu. xml ist der Rückgabewert von xmlParse.

          Kansnt Du dann gpxmetadata in den DOM-Baum des Documents einhängen? Wenn ich versuche document.getElementById("xy").appendChild(gpxmetadata) anzufügen, muss ich feststellen (im IE), dass gpxmetadata ein [Object] und kein [HTMLElement] ist. Weißt Du was ich meine? Oder kann man das umwandeln?

          Grüße
          Siri

          1. Wenn ich versuche document.getElementById("xy").appendChild(gpxmetadata) anzufügen, muss ich feststellen (im IE), dass gpxmetadata ein [Object] und kein [HTMLElement] ist. Weißt Du was ich meine? Oder kann man das umwandeln?

            Es ist ja auch kein HTML was zurückgeliefert wird, sondern XML.
            Du kannst den responseText einfach in einen (nicht eingehangenen) iframe als innerHTML einfügen, dann wird dieser als HTML geparst und du kannst darauf zugreifen.

            1. Hallo,

              Es ist ja auch kein HTML was zurückgeliefert wird, sondern XML.
              Du kannst den responseText einfach in einen (nicht eingehangenen) iframe als innerHTML einfügen, dann wird dieser als HTML geparst und du kannst darauf zugreifen.

              Naja... Es ist schon HTML mit einer Doctype-Deklaration... FF akzeptiert das, IE nicht.

              var allElements = checkResponseXML.getElementsByTagName("*");  
              for (var i = 0; i < allElements.length; i++) {  
              	var loopElement = allElements[i];  
              	var loopElementId =loopElement.getAttribute("id")  
              	if (loopElementId != null) {  
              		  
              		if (loopElementId == "abc") {  
              				var virtualIframe = document.createElement("iframe");  
              				virtualIframe.innerHTML = loopElement;								  
              				newGalleryNav = virtualIfram.getElementById("gallerynav") ;							  
              		}  
              	}  
              }
              

              Meinst du so? virtualIframe.innerHTML = loopElement; wirft im IE einen "Unknown runtime error"

              Viele Grüße
              Siri

              1. Meinst du so? virtualIframe.innerHTML = loopElement; wirft im IE einen "Unknown runtime error"

                Nein, ich meine virtualIframe.innerHTML = XMLHttpRequestObjekt.responseText

                1. Hallo,

                  Meinst du so? virtualIframe.innerHTML = loopElement; wirft im IE einen "Unknown runtime error"
                  Nein, ich meine virtualIframe.innerHTML = XMLHttpRequestObjekt.responseText

                  virtualIframe.innerHTML ist dann im Debugger des IE8 ein leerer String. Kann das daran liegen, dass es ein komplettes Dokument ist? Irgendeine Lösung muss es doch geben. Es ist doch naheliegend, dass man per AJAX HTML ausliefert und die entsprechenden Elemente der aktuellen Seite mit neuen Elementen ersetzt. Oder ist das so ungewöhnlich?

                  Viele Grüße
                  Siri

                  1. Hallo Siri,

                    vielleicht haben die Experten ja noch eine bessere Idee. Ich würde den AJAX-Response als String behandeln (responseText), mit den Stringmethoden den benötigten Teil ausschneiden und ihn dann per innerHTML in die Seite einbauen.

                    Gruß, Jürgen

                    1. Hallo,

                      vielleicht haben die Experten ja noch eine bessere Idee. Ich würde den AJAX-Response als String behandeln (responseText), mit den Stringmethoden den benötigten Teil ausschneiden und ihn dann per innerHTML in die Seite einbauen.

                      Danke! Aber es ist doch irgendwie nicht einsehbar, dass ich ein gültiges HTML-Dokument in einer Variable habe und nicht mit den üblichen DOM-Methoden (im IE) darauf zugreifen kann!?!

                      Viele Grüße
                      Siri

                      1. Hallo Siri,

                        Danke! Aber es ist doch irgendwie nicht einsehbar, dass ich ein gültiges HTML-Dokument in einer Variable habe und nicht mit den üblichen DOM-Methoden (im IE) darauf zugreifen kann!?!

                        du kannst ja mit den "üblichen DOM-Methoden" auf die Inhalte zugreifen. Nur für das Kopieren eines Knotens aus einem DOM-Baum in einen anderen benötigst du eben "spezielle Methoden", s. Beitrag von ChrisB. Da diese vom IE 8 und älter nicht unterstützt werden, würde ich den Weg über die Stringmethoden wählen. Außerdem habe ich bei einem nicht repräsentativen Test (zwei Server :) ) festgestellt, das jeder zweite Server ein xml-Dokument als Text ausliefert.

                        Gruß, Jürgen

                  2. virtualIframe.innerHTML ist dann im Debugger des IE8 ein leerer String.

                    Hmm, das ist nicht so schön, sollte laut Docu eig. auch gehen.

                    Kann das daran liegen, dass es ein komplettes Dokument ist?

                    Vermutlich eher, weil innerHTML readonly ist bei iframes.

                    Irgendeine Lösung muss es doch geben. Es ist doch naheliegend, dass man per AJAX HTML ausliefert und die entsprechenden Elemente der aktuellen Seite mit neuen Elementen ersetzt. Oder ist das so ungewöhnlich?

                    HTML-Teile kann man einfach in ein div hängen und so wie es aussieht geht es mit einem komplettes Dokument nicht so einfach. Bleibt eigentlich nur, den Inhalt des body extrahieren und wieder in ein div stecken.

          2. Hallo Siri,

            var gpxmetadata = xml.documentElement.getElementsByTagName("metadata")

            auf die Daten zu. xml ist der Rückgabewert von xmlParse.

            Kansnt Du dann gpxmetadata in den DOM-Baum des Documents einhängen?

            das habe ich noch nie versucht, ist ja auch kein HTML-Element, sondern xml.

            Hast du schon mal versucht, die Elemente vor dem Einhängen zu Clonen?

            Gruß, Jürgen

            1. Hallo,

              Hast du schon mal versucht, die Elemente vor dem Einhängen zu Clonen?

              Ja. Leider bleibt ein [Object] auch nach dem Clonen ein [Object].

              Viele Grüße
              Siri

              1. Hallo Siri,

                Hast du schon mal versucht, die Elemente vor dem Einhängen zu Clonen?
                Ja. Leider bleibt ein [Object] auch nach dem Clonen ein [Object].

                natürlich.

                So weit ich weiß, wird ein vorhandenes Element bei appendChild aus dem DOM-Baum genommen und neu eingehängt, also verschoben. Innerhalb eines Dokuments ist das kein Problem, aber von einem Dokument (das eingelesene XML-Dokument) zum anderen (deine Seite) geht das nicht. Daher meine Idee, erst zu Klonen und dann den Klon einzuhängen.

                Gruß, Jürgen

                1. Hi,

                  So weit ich weiß, wird ein vorhandenes Element bei appendChild aus dem DOM-Baum genommen und neu eingehängt, also verschoben.

                  Korrekt.

                  Innerhalb eines Dokuments ist das kein Problem, aber von einem Dokument (das eingelesene XML-Dokument) zum anderen (deine Seite) geht das nicht.

                  Doch, das geht …

                  Daher meine Idee, erst zu Klonen und dann den Klon einzuhängen.

                  … aber nicht mit node.clone, weil damit ein Node erzeugt wird, der immer noch das gleiche ownerDocument hat.

                  Dafür, eine Kopie eines Nodes aus einem Dokument innerhalb eines anderen bereitzustellen, ist importNode gedacht. Unterstützt der IE laut Kompabilitätsliste dort ab Version 9.

                  MfG ChrisB

                  --
                  RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
  2. Hi,

    Das Ergebnis von checkResponseXML ist ein gültiges HTML-Dokument mit Doctype-Deklaration:

    Das mit welchem Content-Type vom Server ausgeliefert wird?

    var newAdditionalnavNav = checkResponseXML.getElementById("additionalnav");
    FF kann mit getElementById auf Elemente des HTML-Dokuments zugreifen,

    Dann ist der Content-Type vermutlich text/html, und nicht einer für XML – denn in XML funktioniert getElementById generell nicht, da das id-Attribut dort ein „stinknormales“ Attribut ist, und keine Eindeutigkeit bietet, wie sie in HTML definiert ist. (xml:id bietet diese Eindeutigkeit in XML).

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    1. Hallo,

      Das mit welchem Content-Type vom Server ausgeliefert wird?

      response.setHeader("Content-Type", "text/xml");
      response.setContentType("text/xml; charset=UTF-8");

      Sonst hättes es auch im FF nicht funktioniert.

      Grüße
      Siri

  3. Hallo,

    gibts vielleicht einen Workaraound mit new ActiveXOpject("htmlfile")?

    Viele Grüße
    Siri

  4. Hallo,

    inzwischen ist es mir gelungen, unter IE8 ein Dokument zu erzeugen, in dem man mit getElementById suchen kann:

    var tempResponseXML = http.responseText;	  
    checkResponseXML=new ActiveXObject("htmlfile");		  
    checkResponseXML.write(tempResponseXML);		  
    checkResponseXML.close();  
      
    newABCElement = checkResponseXML.getElementById("abc");			  
    var newABCElementClone = newABCElement.cloneNode(false)
    

    Allerdings kann ich das geclonte Element nicht anfügen:
    top.document.getElementsByTagName('body')[0].appendChild(newABCElementClone);

    Meldet: "Inavlid argument"

    Gibt es einen Weg Elemente ziwschen Dokumenten auszutauschen?

    Viele Grüße
    Siri

    1. Hallo Siri,

      Allerdings kann ich das geclonte Element nicht anfügen:

      der Grund wurde auch schon erläutert. Auch deine Lösung erzeugt nur einen neuen DOM-Baum, und Klonen von Baum zu Baum geht nun mal nicht.

      Gibt es einen Weg Elemente ziwschen Dokumenten auszutauschen?

      Bis etwas besseres kommt, bleibe ich bei meiner Idee.

      Gruß, Jürgen

      1. Hallo,

        Allerdings kann ich das geclonte Element nicht anfügen:

        der Grund wurde auch schon erläutert. Auch deine Lösung erzeugt nur einen neuen DOM-Baum, und Klonen von Baum zu Baum geht nun mal nicht.

        Nein, das tut sie nicht! Dass seh ich

        a) am Dokumententyp im Debugger und
        b) daran, dass das neue  Dokument mit document.getElementById durchsuchbar ist.

        Deine Idee habe ich zur Kenntnis genommen, bin aber auf der Suche nach einer anderen Lösung. Es muss doch möglich sein, einen Knoten/ein Element notfalls zu-Fuß zu klonen für alle Browser die importNode noch nicht unterstützen.

        Viele Grüße
        Siri

        1. Hi,

          Auch deine Lösung erzeugt nur einen neuen DOM-Baum, und Klonen von Baum zu Baum geht nun mal nicht.

          Nein, das tut sie nicht! Dass seh ich

          a) am Dokumententyp im Debugger und
          b) daran, dass das neue  Dokument mit document.getElementById durchsuchbar ist.

          Beides widerspricht nicht der Aussage, dass du einen DOM-Baum erzeugt hast – im Gegenteil, es stützt sie, denn sonst könntest du gar kein getElementById benutzen.

          Es muss doch möglich sein, einen Knoten/ein Element notfalls zu-Fuß zu klonen für alle Browser die importNode noch nicht unterstützen.

          „Notfalls zu Fuss“ = alle relevanten Eigenschaften auslesen, und Element mit DOM-Methoden im Zieldokument neu erzeugen. Natürlich rekursiv für Kindelemente.

          MfG ChrisB

          --
          RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
          1. Hallo,

            Beides widerspricht nicht der Aussage, dass du einen DOM-Baum erzeugt hast – im Gegenteil, es stützt sie, denn sonst könntest du gar kein getElementById benutzen.

            Ja, ein HTML-Document ist natürlich auch ein DOM-Baum, aber ich habe jetzt aus Sicht des IE einen anderen Typ.

            Es muss doch möglich sein, einen Knoten/ein Element notfalls zu-Fuß zu klonen für alle Browser die importNode noch nicht unterstützen.

            „Notfalls zu Fuss“ = alle relevanten Eigenschaften auslesen, und Element mit DOM-Methoden im Zieldokument neu erzeugen. Natürlich rekursiv für Kindelemente.

            Ja, ist wohl die einzige Möglichkeit.

            Viele Grüße
            Siri