XML per AJAX in HTML einbinden

Hallo

Vielleich hat jemand von euch eine Idee oder Hinweis.

Ich möchte per AJAX die aktuellen Daten meines Arduino+Ethernet einbinden.
Ein direkter Zugriff per Browser klappt.
Ein xml testfile von meinen host per AJAX klappt auch

XML Daten von von Arduion per AJAX liefert mit Status=0 (quasi nix)

an was kann es liegen (ev. am Access-Control-Allow-Origin - erlaubt ajax direkten zugriff auf externen host)

Hier mein Quellcode

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4D, 0x97 };
byte ip[] = { 192, 168, 0, 12 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  Client client = server.available();
  if (client) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/xml");
  client.println("Access-Control-Allow-Origin: http://192.168.0.1/");
  client.println();
  client.print("<node id='IDNR'>");
  client.print("<sensor>1234</sensor>");
  client.print("</node>"); 
  delay(10);
  client.stop();
  }    
  delay(30);                            
}
<html>
<body>

<script type="text/javascript">
var xmlhttp;
var xmlDoc;
function callback(xhr)
{
    xmlDoc = xhr.responseXML;
	alert(xmlDoc);
}

if (window.XMLHttpRequest)
{
    xmlhttp = new XMLHttpRequest();
}
else
{
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp.open("GET", "http://192.168.0.12/", true);

xmlhttp.onreadystatechange = function ()
{
    if (xmlhttp.readyState != 4) return;
    if (xmlhttp.status != 200 && xmlhttp.status != 304) {
	alert(xmlhttp.status);
	return;
    }
	callback(xmlhttp);
};

xmlhttp.send(null);

</script>

</body>
</html>

Vielen Dank im Voraus

Vieleicht verrätst Du noch etwas mehr? Welcher Browser, welches OS, wie genau kann man das nachstellen? HastDu schon mal mit den üblichen Debugtools Firebug, Fiddler2 und was es sonst so gibt schon mal nachgeschaut?

Was mir gerade auffällt. Dein Output sieht nur aus wie XML, ist es aber nicht. XML fängt normalerweise so an:

<?XML>

Vielen Dank für deine Antwort

Welcher Browser, welches OS

Browser FF4.0; Windows XP

<?XML>

Glaube ich fast nicht, sollte nicht der Content-Type: text/xml ausreichen

Noch eine Anmerkung und Mögliche Vermutung:

Kann es am "same origin policy" liegen?
Die XML Daten liegen ja auf einen anderen host als die HTML/AJAX Seite.

(JavaScript: Sicherheit)

Also ich würde den Ansatz verwerfen mit XML.

Das müsstest du via Java, PHP, C# .... parsen um etwas ertägliches damit anfangen zu können. Dazu hast du es nicht als Datei vorliegen und ich befürchte das kostet dich deine letzten Haare.

In der Internetwelt schreiben wir sowas mal eben auf eine Terrabyte Platte, aber so ein kleines Arduinchen ist dann doch Matsche :wink:

Das ist nur ein Testbeispiel. Das Ergebnis sind dynamische XML Daten, und kein starres XML File. (Sensorwerte werden in einer klaren XML Struktur an den Browser geschickt).

Warum AJAX: HTML5 Template wird aufgebaut und jede Sekunde werden die neuen Daten von Arduino abgefragt. Es sollte nicht jedesmal die komplette Bildschirmmaske aufgebaut werden, sonder nur die Position mit den Sensorwerten.

mr_sol:
Kann es am "same origin policy" liegen?

Ich denke, dass das die Ursache sein könnte.

Selber habe ich das immer so gelöst, dass per AJAX ein lokales Script (PHP z.B.) aufgerufen wird, dieses lädt die XML Daten (ich ziehe JSON vor, ist weniger aufwändig) des Arduinos und reicht diese weiter.

Per PHP ist es problemlos. Ich möchte ohne apache und php auskommen (absoluter minimalismus).
Das Template wir zuerst von der SD Card gelesen, dann erfolgt die Datenaktuallisierung per ajax.

Ziel: Board an LAN anstecken - Browser starten - IP eingeben - losgehts....

Hallo zusammen,

um eine möglichst kleine Seite zu schreiben und den Speicher des Ardu zu entlasten, habe ich auf dem Ardu eine Funktion, die den PIN entgegen nimmt und als Text den Status zurück sendet.
Die Webseite hat eine Schleife, die dann alle relevanten Pins abfragt und schicke Ein/Aus-Schalter anzeigt, bzw. den aktuellen Wert des Analog pins.
Etwas Trickreich war eigentlich nur, das die Seite die Antwort des Ardu nicht als weitere Seite anzeigt, sondern richtig verarbeitet.

Das geht dann in etwa so:

  // the file to be read
  pageURL = new java.net.URL("www.MeinArdu.dyndns.oder.so");

  // step 1, open the URL
  var openConnection = pageURL.openConnection;
  theConnection = openConnection();

  // step 2, connect to server
  var t=theConnection.connect;
  t();

  // step 3, read the file using HTTP protocol
  var getContent = theConnection.getContent;
  var theURLStream = getContent();

  // step 4, get an handle and fetch the content length
  var readStream = theURLStream.read;
  var gcl = theConnection.getContentLength;
  gcLen = gcl();

  // and finally, read into a variable
  theText =""
  for (i = 1; i <gcLen; i++)
  {
   theText += new java.lang.Character(readStream())
  }

Der Code ist noch etwas veraltet. Habe die aktuellen Sourcen gerade nicht da.

mr_sol:

Welcher Browser, welches OS

Browser FF4.0; Windows XP

Firebug AddOn installieren => Netzwerk Tab => Entsprechenden Request aufklappen => Antwort Tab
Dann kannst Du erstmal sehen was und wie valide die ankommenden Daten sind.

Wenn Speicherplatz nicht das Problem ist, würde ich persönlich ein Framework wie jquery vorziehen. JSON ist für Ajax (trotz des Namens) durchaus auch gängiger und dürfte schon alleine wegen der geringeren Datenmenge einfacher mit dem Arduino zu generieren sein (letzendlich aber Geschmacksache).

Glaube ich fast nicht, sollte nicht der Content-Type: text/xml ausreichen

Der Content-Type ist höchstens ein Hinweis an den Browser, was er denn von dem Dokument halten soll. Wenn Du ein JPEG mit XML Content Type versendest, wird der XML-Parser schließlich auch nichts damit anfangen können.

(Edit: PS: Und XML-Parser sind schon bei allerkleinsten Fehlern ziemlich zickig...)

@mr_sol: Du schreibst "... glaube ich nicht ...". Hast Du es ausprobiert? Dein Program funktioniert nicht. Debuggen bedeutet systematisch Fehler auszuschliessen. Wie auch andere schon angemerkt haben sind XML Parser häufig sehr penibel.

Erstmal vielen dank für eure Ideen und Unterstützung

Hier die verbesserte pde:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4D, 0x97 };
byte ip[] = { 192, 168, 0, 12 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  Client client = server.available();
  if (client) {
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/xml");
    client.println();
    client.print("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
    client.print("<node id=\"IDNR\">");
    client.print("<sensor>1234</sensor>");
    client.print("</node>"); 
    delay(10);
    client.stop();
  }    
  delay(30);                            
}

JS habe ich auf Post umgestellt:

<html>
<body>

<script type="text/javascript">
var xmlhttp;
var xmlDoc;
function callback(xhr)
{
    xmlDoc = xhr.responseXML;
	alert(xmlDoc);
}

if (window.XMLHttpRequest)
{
    xmlhttp = new XMLHttpRequest();
}
else
{
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp.open("POST", "http://192.168.0.12/", true);

xmlhttp.onreadystatechange = function ()
{
    if (xmlhttp.readyState != 4) return;
    if (xmlhttp.status != 200 && xmlhttp.status != 304) {
	alert(xmlhttp.status);
	return;
    }
	callback(xmlhttp);
};

xmlhttp.send(null);

</script>

</body>
</html>

Leider Liefert ajax eine Status 0 Meldung (statt 200). Rufe ich Arduino direkt per BrowserURL auf klappt es einwandfrei (an der Firewall kann es nicht liegen)

Hier mit Firebug
ajax.jpg

Ich hatte was übersehen beim debugging - jetzt klappt Status 200

Es liegt am XML, bei Betrachtung mit FireBug -> XML zeigt er einen Fehler im XML an. Verstehe ich nicht

XML ist valid....woran kann's dann liegen?

Das Problem ist der Cross-Site-Schutz des Browsers.
Zum Umgehen gibt es versch. Möglichkeiten:

  • Cross-Site-Schutz ausschalten
  • PHP-Script auf dem Server als Umleitung benutzen
  • Yahoo YQL als Vermittler benutzen

Gruß
Andreas

Danke für die Antwort

  • Cross-Site-Schutz ausschalten - Wo ist die Einstellung?
  • PHP-Script auf dem Server als Umleitung benutzen - Möchte ich vermeiden
  • Yahoo YQL als Vermittler benutzen - Möchte ich vermeiden

Besser wäre den Access mitzuliefern - 192.168.0.1 IP des Rechners

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4D, 0x97 };
byte ip[] = { 192, 168, 0, 12 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  Client client = server.available();
  if (client) {
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/xml");      
    client.println();
    client.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    client.print("<?access-control allow=\"192.168.0.1\"?>");
    client.print("<node>test</node>");


    delay(10);
    client.stop();
  }    
  delay(30);                            
}

Klappt aber auch nicht -
Status 200 ist OK
XML-Verarbeitungsfehler: Kein Element gefunden Adresse: moz-nullprincipal:{980a6c3a.....

Hat nach jemand eine Idee?

  • Cross-Site-Schutz ausschalten - Wo ist die Einstellung?

In den neueren FF Versionen scheint das nur noch per HTTP Access Control zu gehen:
https://developer.mozilla.org/En/HTTP_access_control

Der Header + Daten müsste dann so aussehen:

println("HTTP/1.1 200 OK");
println("Access-Control-Allow-Origin: *");
println("Content-Type: application/xml");
println("");
println("[XML Data]");

Super es klappt:

Nochmals vielen Dank an alle.

Hier die komplette Lösung (Arduione+Ethernet) falls jemand XML Daten per Ajax in seine HTML Seite dynamisch einbinden möchte.

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4D, 0x97 };
byte ip[] = { 192, 168, 0, 12 };

Server server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  Client client = server.available();
  if (client) {
    client.println("HTTP/1.1 200 OK");
    client.println("Access-Control-Allow-Origin: *");    
    client.println("Content-Type: application/xml");
    client.println("");
    client.print("<node>test</node>");


    delay(10);
    client.stop();
  }    
  delay(30);                            
}

HMTL/JS/AXAJ

<html>
<body>

<script type="text/javascript">
var xmlhttp;
var xmlDoc;
function callback(xhr)
{
    xmlDoc = xhr.responseXML;
	alert(xmlDoc);
}

if (window.XMLHttpRequest)
{
    xmlhttp = new XMLHttpRequest();
}
else
{
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp.open("GET", "http://192.168.0.12/", true);

xmlhttp.onreadystatechange = function ()
{
    if (xmlhttp.readyState != 4) return;
    if (xmlhttp.status != 200 && xmlhttp.status != 304) return;

	callback(xmlhttp);
};

xmlhttp.send(null);

</script>

</body>
</html>

Der Code liefert in der function callback(xhr) ein xml Object zurück, dieses kann ausgewertet werden. Zu Testzecken FireBUG Netzwerk>alle>GET....>XML aufrufen hier sollte der XML Baum erscheinen.