Parsing XML JQuery Ajax Response with Namespace - javascript

I'm executing a web service call using JQuery and it's ajax function and I'm unable to parse the data coming back. When I alert the data (alert($(data).find("return").text()) its empty. I see the server responding with xml data as outlined below and when I alert(data) I get [object XMLDocument]. Is txt = $(data).find("return").text() valid given my XML structure with a namespace below? I can see the full xml string in firebug. Any ideas?
var txt = $(data).find("ns1\:return").text(); works on Chrome and Firefox, but not Safari
index.js:
$(function () {
$.ajax({
url: url,
success: function (data) {
var ndx = 0,
row,
**txt = $(data).find("return").text(),**
xml = unescape(txt),
xmlDoc = $.parseXML(xml),
firstrow = $(xmlDoc).find(
"results").children(":first");
// populate the table based on the results returned by
// the web service
$("table.results thead").empty();
$("table.results tbody").empty();
row = $("<tr/>");
row.append($("<th/>").text("#").addClass("ndx"));
firstrow.children().each(function () {
row.append($("<th/>").text(this.nodeName));
});
row.appendTo($("table.results thead"));
$(xmlDoc).find("row").each(function () {
row = $("<tr/>");
row.append($("<td/>").text(ndx + 1).addClass("ndx"));
$(this).children().each(function () {
row.append($("<td/>").text($(this).text()));
});
row.appendTo($("table.results tbody"));
ndx++;
});
// clear the table if no results were returned
if (ndx == 0) {
// no rows returned
$("table.results thead").empty();
$("table.results tbody").empty();
}
statusNotice("Records Returned: " + ndx);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
// display the error returned by the web service
var xmlDoc = $(XMLHttpRequest.responseXML);
statusError(xmlDoc.find("Text").text());
},
complete: function(XMLHttpRequest, textStatus) {
// hide the busy dialog
$("#busy-dlg").dialog("close");
}
});
});
index.html:
Demo
<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-min.js"></script>
<script type="text/javascript" src="js/jquery.layout-latest.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</head>
<body>
//table displaying results from ajax call here
</body>
</html>
XML:
<ns1:executeResponse xmlns:ns1="http://sqlws.test.com">
<ns1:return>
<results>
<row>
<attribute1>value1</attribute1>
<attribute2>value2</attribute2>
</row>
<row>
<attribute1>value1</attribute1>
<attribute2>value2</attribute2>
</row>
</results>
</ns1:return>
</ns1:executeResponse>

When an element is prefixed by a namespace, you have to also add the namespace:
.find('ns1:return') does not work, because : is used by jQuery as pseudo-selectors.
.find('ns1\:return') does not work either, because a single backslash in a string is used as an escape character. "ns1\:return" becomes "ns1:return" which is equal to the previous one.
.find('ns1\\:return') should be used. The double backslash is used to escape the colon.
It appears that the last solution works fine in IE and Firefox, but not Opera, Chrome or Safari. To get maximum compatibility, use jQuery selectors with, and without fake prefix, ie. "ns1\\:return, return" instead of a plain ns1\\:return.
Demo: http://jsfiddle.net/5BQjv/51/
// For example, this is the result:
var data = '<ns1:executeResponse xmlns:ns1="http://sqlws.test.com">' +
'<ns1:return>' +
'<results> <row> ... </row> </results>' +
'</ns1:return>' +
'</ns1:executeResponse>';
// The very first thing is to parse the string as XML. NOT later!
var $xmlDoc = $($.parseXML(data));
// Then, look for the element with the namespace:
var $txt = $xmlDoc.find('ns1\\:return, return');
// No need to use unescape or something, just use DOM manipulation:
// `results` is the immediate child. Don't use .find, but .children
var $firstrow = $txt.children("results").children(":first");
As you may have noticed, I have prefixed some variables with a dollar sign. It's the convention to prefix variables which refer to jQuery objects with a dollar sign, to avoid confusion during/after development.

Related

Invalid XML format - How to avoid this

I'm getting data from a database in PHP/mysql, which has invalid characters, such as &. I'm creating the XML as follows:
$stmt->bind_result($foo)|| fail('An error occurred: MySQL bind_result', $db->error);
$foo=htmlspecialchars($foo, ENT_XML1, 'UTF-8');
$xmlstr = "<?xml version="1.0" encoding="UTF-8" standalone="yes">
<xml>";
while ($stmt->fetch())
{ $xmlstr.="
<RECORD>
<FOO>$foo</FOO>
</RECORD>";}
$xmlstr.="
</xml>";
$stmt->close();
echo $xmlstr;
I'm trying to receive the data and put in an array with javascript - but it gives me the error Invalid XML format. I'm receiving random records and sometimes it does work. So it seems to me that the issue is in the characters coming from the database.
The error occurs here in JavaScript:
var foo;
var formData = "label="+label; //Name value Pair
$.ajax({
url: './php/foo.php',
type: 'POST',
data : formData,
dataType: 'xml',
success: function(returnedXMLResponse){
$('RECORD', returnedXMLResponse).each(function(){
foo = $('FOO', this).text();
})
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
console.log("Status: " + textStatus); console.log("Error: " + errorThrown);
}
});
You could use an XMLWriter to ensure correct encoding and such.
<?php
$stmt = new Dummy;
$stmt->bind_result($foo);
$xml = new XMLWriter();
$xml->openURI('php://output');
$xml->setIndent(true);
$xml->startDocument();
$xml->startElement("xml");
while ( $stmt->fetch() ) {
$xml->startElement("RECORD");
$xml->writeElement('FOO', $foo);
$xml->endElement(); // RECORD
}
$xml->endElement(); // xml
class Dummy {
public function bind_result(&$var) {
$this->var = &$var;
}
public function fetch() {
static $arr = array('Barnes & Noble', 'Barnum & Bailey', "Buy'n'Large");
if ( current($arr) ) {
$this->var = current($arr);
next($arr);
return true;
}
return false;
}
}
The characters you're getting from the database are not invalid. <, >, & and such are perfectly legal text and can be included in an XML document. However because they have special meaning to an XML parser they need to be escaped. That is:
& --> &
> --> >
< --> <
By far the easiest way to do this is not to build the XML by string concatenation as your code sample attempts to do. Instead use a library that automatically escapes characters as necessary as the document is constructed. XMLWriter has already been suggested. DOM is another option.
I got rid of the parse error by adding a header:
header('Content-type: text/xml');
$xml = new XMLWriter('UTF-8', '1.0');
$xml->openURI('php://output');
$xml->setIndent(true);
$xml->startDocument();
$xml->startElement("XML");
while ( $stmt->fetch() ) {
$xml->startElement("ITEM");
$xml->writeElement('ELEMENT', $reviewdate);
$xml->endElement(); // </ITEM>
}
$stmt->close();
$xml->endElement(); // xml
$xml->flush();
unset($xml);
I would start by looking in the browsers network traffic and analyzing the xhr response body to see what your browser is getting as far as the xml payload (data). You can do this in Chrome or IE using F12 developer tools, or if you want to catch it using another proxy, take a look at Fiddler:
http://www.telerik.com/fiddler
Hope this helps!

Javascript DOM errors

this is my javascript code , I am trying to create a dynamic list in HTML with data I recieve from the server , The data is of type "json"
My Javascript snippet
function addBooks(data) { // USing DOM to populate the tables
//var newdata=document.getElementById('addBooks');
//newdata.setattribute()
//get the unordered list
var newdata = document.getElementById('addBooks');
var parent = document.getElementById('gBookList');
//removeChildrenFromNode(parent);
//create list divider
var listdiv = document.createElement('li');
listdiv.setAttribute('id', 'gBookListDiv');
listdiv.innerHTML = ("Books Found:");
parent.appendChild(listdiv);
// (this is where the first error happens)
//create dynamic list
for (i = 0; i < data.length; i++) {
// (this is where the second error happens)
//create each list item
var listItem = document.createElement('li');
listItem.setAttribute('id', 'gBookListItem');
parent.appendChild(listItem);
//var link = document.createElement('a');
//link.setAttribute('onclick','displayBook(data[i])');
//link.setAttribute('href','#FindBook)');
//listItem.appendChild(link);
var pic = document.createElement('img');
pic.setAttribute('src', data[i].pictureURL);
pic.setAttribute('width', '80px');
pic.setAttribute('height', '100px');
pic.setAttribute('style', 'padding-left: 10px');
link.appendChild(pic);
var brk = document.createElement('br')
link.appendChild(brk);
var title = document.createElement('p');
title.innerHTML = data[i].title;
title.setAttribute = ('style', 'float:right');
link.appendChild(title);
var author = document.createElement('p');
author.innerHTML = data[i].author;
link.appendChild(author);
}
var list = document.getElementById('gBookList');
// $(list).listview("refresh");
}
/*function removeChildrenFromNode(node){
while (node.hasChildNodes()){
node.removeChild(node.firstChild);
}
//}*/
My html code is
<!DOCTYPE html>
<head>
<script ...>
<head>
<body onLoad="addBooks()">
<div id="addBooks" class="row-fluid">
<div id="gBookList">
</div>
</div>
</body>
</html>
I keep getting the following error which prevents me from populating the list , I am using chrome
1) Uncaught TypeError: Cannot call method 'appendChild' of null
2) Uncaught TypeError: Cannot read property 'length' of undefined
I do not understand why this should happen as the .length commands returns the correct integer ( amount of json objects) when I debug using a alert box .
the function that calls it
$.ajax({
type: 'GET',
url: ........,
dataType: "json",
complete: function (xhr, statusText) {
alert(xhr.status);
},
success: function (data, textStatus, jqXHR) {
alert(JSON.stringify(data));
window.location.replace("Page2_updated.html");
addBooks(data); // Passing JSON to be replaced on page
},
function (data, textStatus, jqXHR) {
alert(data);
alert('error');
},
});
Edit
I changed my HTML file to the following structure after advice on this forum
<html>
<head>
</head>
<body>
<div id="1" "display:block">
</div>
<div id="2" "display:none"> // no onLoad() anymore!!
</div>
</body>
</html>
I have edited this part int he calling function
$.ajax({
type: 'GET',
url: ........,
dataType: "json",
complete: function (xhr, statusText) {
alert(xhr.status);
},
success: function (data, textStatus, jqXHR) {
alert(JSON.stringify(data));
if(document.getElementById(1).style.display == "block"){
document.getElementById(1).style.display = "none";
document.getElementById(2).style.display = "block"; }
addBooks(data); // Passing JSON to be replaced on page
},
function (data, textStatus, jqXHR) {
alert(data);
alert('error');
},
});
But I still get the following errors
Uncaught TypeError: Cannot call method 'appendChild' of null
Uncaught TypeError: Cannot read property 'length' of undefined
Here is a working version of your code that builds a list. Compare with your version to see where you made the mistakes, in both mark up and code.
The source of your second error is incorrect data (most likely null) being passed to the addBooks function, so you would have to fix that.
Chrome and Firebug have excellent JavaScript debuggers with breakpoints, so use that to your advantage to identify the issues:
http://jsfiddle.net/tgth2/
EDIT:
Your problem is gleamingly obvious, after your comments and updates to the question:
Your first page is loading the JSON data from the service, but then does window.location.replace("Page2 Updated.html");, which sends the browser to the new page (notice that you're calling addBooks(data); immediately after. But that code is never executed because browser has already gone to another page
Your second page has <body onload="addBooks();"> in it, which will cause the function to be called with a null data. This is the cause of your problem.
SOLUTION:
Number one suggestion would be to start using jQuery for everything else you're doing, and not just for the AJAX call.
Secondly, you should have the ajax call and the results rendering in one page, as it does not make any sense to redirect the browser to another page. Because your javascript always works in the context of a single page. As soon as you do something like window.location.replace(..) you end up losing everything you've done in the current page.
If you make these changes, you will see that your list loads just fine!
This line in your loop creates multiple list items with the same ID:
listItem.setAttribute('id','gBookListItem');
try removing it - i don't think you need it.
That's an error :
title.setAttribute=('style','float:right');
do:
var title = document.createElement('p');
title.innerHTML = data[i].title;
title.style.cssFloat = 'right';
link.appendChild(title);
and
var pic = document.createElement('img');
pic.src = data[i].pictureURL;
pic.width = '80px';
pic.height = '100px';
pic.style.paddingLeft = '10px';
link.appendChild(pic);
etc......
Any chance that you're accidentally calling addBooks() somewhere in your code without any data?
I tried to cut it down to the barebones and I'm pretty sure the fact that link is undefined is the reason you get an error when you call appendChild. It's certainly the first error I found in the console in Firebug. The following barebones sequence works in Firefox (sorry I don't have Chrome):
var json =[
{"pictureURL":"/test1.jpg/","title":"test1"},
{"pictureURL":"/test2.jpg/", "title":"test2"},
{"pictureURL":"/test3.jpg", "title":"test3"}
];
function displayBook(title){
alert(title);
return false;
}
function addBooks(data) {
var newdata=document.getElementById('addBooks');
var parent = document.getElementById('gBookList');
var listdiv = document.createElement('li');
listdiv.id = 'gBookListDiv';
listdiv.innerHTML = "Books Found:";
parent.appendChild(listdiv);
for(var i=0;i<data.length;i++){
var listItem = document.createElement('li');
listItem.id = 'gBookListItem-' + i;
parent.appendChild(listItem);
var link = document.createElement('a');
link.id = listItem.id + "-link";
link.href = '#FindBook';
link.innerHTML = data[i].title;
listItem.appendChild(link);
link.setAttribute("onclick", "return displayBook('" + data[i].title + "');");
var pic = document.createElement('img');
pic.src = data[i].pictureURL;
}
var list = document.getElementById('gBookList');
}
I discovered from this answer JavaScript: changing the value of onclick with or without jQuery that I had to use setAttribute to add the onclick handler. I'm used to adding other attributes like id directly as mentioned by adeneo without calling setAttribute.

Output XML code with Jquery

Consider the following script for outputting some XML code:
var xmlAsString = '<?xml version="1.0"?><person><name gender="male"></name></person>';
$(document).ready(function(){
$(".generator").click(function(){
alert(xmlAsString);
$("#container").append("<div id='contXML'>"+xmlAsString+"</div>")
});
});
The alert outputs everything as I want but nothing shows later. If I put some random string variable (without the < > chars everything works fine).
That's because you have to html encode your xml otherwise the browser tries to parse it. I use this simple function.
var xmlAsString = '<?xml version="1.0"?><person><name gender="male"></name></person>';
function htmlEncode(value){
return $('<div/>').text(value).html();
}
$(document).ready(function() {
$(".generator").click(function() {
alert(xmlAsString);
$("#container").append("<div id='contXML'>" + htmlEncode(xmlAsString) + "</div>")
});
});
Fiddle here http://jsfiddle.net/DqDEU/

How can I get javascript to read from a .json file?

My script currently looks like this:
<script type="text/javascript">
function updateMe(){
var x = 0;
var jsonstr = '{"date":"July 4th", "event":"Independence Day"}';
var activity=JSON.parse(jsonstr);
while(x<10){
date = document.getElementById("date"+x).innerHTML = activity.date;
event = document.getElementById("event"+x).innerHTML = activity.event;
x++;
}
}
</script>
Where date"x" and event"x" are a series of html tags. This function runs when the page loads (onload). My goal is to do this exact same thing, only from a local .json file as opposed to the hard code that I've got above. I've already checked out http://api.jquery.com/jQuery.getJSON/.
The local .json file looks like this:
{"date":"July 4th", "event":"Independence Day"}
Any suggestions?
Assuming you mean "file on a local filesystem" when you say .json file.
You'll need to save the json data formatted as jsonp, and use a file:// url to access it.
Your HTML will look like this:
<script src="file://c:\\data\\activity.jsonp"></script>
<script type="text/javascript">
function updateMe(){
var x = 0;
var activity=jsonstr;
foreach (i in activity) {
date = document.getElementById(i.date).innerHTML = activity.date;
event = document.getElementById(i.event).innerHTML = activity.event;
}
}
</script>
And the file c:\data\activity.jsonp contains the following line:
jsonstr = [ {"date":"July 4th", "event":"Independence Day"} ];
NOTICE: AS OF JULY 12TH, 2018, THE OTHER ANSWERS ARE ALL OUTDATED. JSONP IS NOW CONSIDERED A TERRIBLE IDEA
If you have your JSON as a string, JSON.parse() will work fine. Since you are loading the json from a file, you will need to do a XMLHttpRequest to it. For example (This is w3schools.com example):
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myObj.name;
}
};
xmlhttp.open("GET", "json_demo.txt", true);
xmlhttp.send();
<!DOCTYPE html>
<html>
<body>
<h2>Use the XMLHttpRequest to get the content of a file.</h2>
<p>The content is written in JSON format, and can easily be converted into a JavaScript object.</p>
<p id="demo"></p>
<p>Take a look at json_demo.txt</p>
</body>
</html>
It will not work here as that file isn't located here. Go to this w3schools example though: https://www.w3schools.com/js/tryit.asp?filename=tryjson_ajax
Here is the documentation for JSON.parse(): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
Here's a summary:
The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string. An optional reviver function can be provided to perform a transformation on the resulting object before it is returned.
Here's the example used:
var json = '{"result":true, "count":42}';
obj = JSON.parse(json);
console.log(obj.count);
// expected output: 42
console.log(obj.result);
// expected output: true
Here is a summary on XMLHttpRequests from https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest:
Use XMLHttpRequest (XHR) objects to interact with servers. You can retrieve data from a URL without having to do a full page refresh. This enables a Web page to update just part of a page without disrupting what the user is doing. XMLHttpRequest is used heavily in Ajax programming.
If you don't want to use XMLHttpRequests, then a JQUERY way (which I'm not sure why it isn't working for you) is http://api.jquery.com/jQuery.getJSON/
Since it isn't working, I'd try using XMLHttpRequests
You could also try AJAX requests:
$.ajax({
'async': false,
'global': false,
'url': "/jsonfile.json",
'dataType': "json",
'success': function (data) {
// do stuff with data
}
});
Documentation: http://api.jquery.com/jquery.ajax/
You can do it like...
Just give the proper path of your json file...
<!doctype html>
<html>
<head>
<script type="text/javascript" src="abc.json"></script>
<script type="text/javascript" >
function load() {
var mydata = JSON.parse(data);
alert(mydata.length);
var div = document.getElementById('data');
for(var i = 0;i < mydata.length; i++)
{
div.innerHTML = div.innerHTML + "<p class='inner' id="+i+">"+ mydata[i].name +"</p>" + "<br>";
}
}
</script>
</head>
<body onload="load()">
<div id= "data">
</div>
</body>
</html>
Simply getting the data and appending it to a div... Initially printing the length in alert.
Here is my Json file: abc.json
data = '[{"name" : "Riyaz"},{"name" : "Javed"},{"name" : "Arun"},{"name" : "Sunil"},{"name" : "Rahul"},{"name" : "Anita"}]';
Actually, you are looking for the AJAX CALL, in which you will replace the URL parameter value with the link of the JSON file to get the JSON values.
$.ajax({
url: "File.json", //the path of the file is replaced by File.json
dataType: "json",
success: function (response) {
console.log(response); //it will return the json array
}
});
Instead of storing the data as pure JSON store it instead as a JavaScript Object Literal;
E.g.
window.portalData = [
{
"kpi" : "NDAR",
"data": [15,152,2,45,0,2,0,16,88,0,174,0,30,63,0,0,0,0,448,4,0,139,1,7,12,0,211,37,182,154]
},
{
"kpi" : "NTI",
"data" : [195,299,31,32,438,12,0,6,136,31,71,5,40,40,96,46,4,49,106,127,43,366,23,36,7,34,196,105,30,77]
},
{
"kpi" : "BS",
"data" : [745,2129,1775,1089,517,720,2269,334,1436,517,3219,1167,2286,266,1813,509,1409,988,1511,972,730,2039,1067,1102,1270,1629,845,1292,1107,1800]
},
{
"kpi" : "SISS",
"data" : [75,547,260,430,397,91,0,0,217,105,563,136,352,286,244,166,287,319,877,230,100,437,108,326,145,749,0,92,191,469]
},
{
"kpi" : "MID",
"data" : [6,17,14,8,13,7,4,6,8,5,72,15,6,3,1,13,17,32,9,3,25,21,7,49,23,10,13,18,36,9,12]
}
];
You can then do the following in your HTML
<script src="server_data.js"> </script>
function getServerData(kpiCode)
{
var elem = $(window.portalData).filter(function(idx){
return window.portalData[idx].kpi == kpiCode;
});
return elem[0].data;
};
var defData = getServerData('NDAR');

jQuery .find() doesn't return data in IE but does in Firefox and Chrome

I helped a friend out by doing a little web work for him. Part of what he needed was an easy way to change a couple pieces of text on his site. Rather than having him edit the HTML I decided to provide an XML file with the messages in it and I used jQuery to pull them out of the file and insert them into the page.
It works great... In Firefox and Chrome, not so great in IE7. I was hoping one of you could tell me why. I did a fair but of googling but couldn't find what I'm looking for.
Here's the XML:
<?xml version="1.0" encoding="utf-8" ?>
<messages>
<message type="HeaderMessage">
This message is put up in the header area.
</message>
<message type="FooterMessage">
This message is put in the lower left cell.
</message>
</messages>
And here's my jQuery call:
<script type="text/javascript">
$(document).ready(function() {
$.get('messages.xml', function(d) {
//I have confirmed that it gets to here in IE
//and it has the xml loaded.
//alert(d); gives me a message box with the xml text in it
//alert($(d).find('message')); gives me "[object Object]"
//alert($(d).find('message')[0]); gives me "undefined"
//alert($(d).find('message').Length); gives me "undefined"
$(d).find('message').each(function() {
//But it never gets to here in IE
var $msg = $(this);
var type = $msg.attr("type");
var message = $msg.text();
switch (type) {
case "HeaderMessage":
$("#HeaderMessageDiv").html(message);
break;
case "FooterMessage":
$("#footermessagecell").html(message);
break;
default:
}
});
});
});
</script>
Is there something I need to do differently in IE? Based on the message box with [object Object] I'm assumed that .find was working in IE but since I can't index into the array with [0] or check it's Length I'm guessing that means .find isn't returning any results. Any reason why that would work perfectly in Firefox and Chrome but fail in IE?
I'm a total newbie with jQuery so I hope I haven't just done something stupid. That code above was scraped out of a forum and modified to suit my needs. Since jQuery is cross-platform I figured I wouldn't have to deal with this mess.
Edit: I've found that if I load the page in Visual Studio 2008 and run it then it will work in IE. So it turns out it always works when run through the development web server. Now I'm thinking IE just doesn't like doing .find in XML loaded off of my local drive so maybe when this is on an actual web server it will work OK.
I have confirmed that it works fine when browsed from a web server. Must be a peculiarity with IE. I'm guessing it's because the web server sets the mime type for the xml data file transfer and without that IE doesn't parse the xml correctly.
Since IE's problem is its xml parser chokes on xml files that are not passed down using the correct "text/xml" header, you can include a bit of code in the Ajax complete event:
complete: function( xhr, status )
{
alert( "COMPLETE. You got:\n\n" + xhr.responseText ) ;
if( status == 'parsererror' )
{
alert( "There was a PARSERERROR. Luckily, we know how to fix that.\n\n" +
"The complete server response text was " + xhr.responseText ) ;
xmlDoc = null;
// Create the xml document from the responseText string.
// This uses the w3schools method.
// see also
if( window.DOMParser )
{
parser=new DOMParser();
xmlDoc=parser.parseFromString( xhr.responseText,"text/xml" ) ;
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject( "Microsoft.XMLDOM" ) ;
xmlDoc.async = "false" ;
xmlDoc.loadXML( xhr.responseText ) ;
}
$( '#response' ).append( '<p>complete event/xmlDoc: ' + xmlDoc + '</p>' ) ;
$( '#response' ).append( '<p>complete event/status: ' + status + '</p>' ) ;
processXMLDoc( xmlDoc ) ;
}
},
here's a more complete example
<!DOCTYPE html>
<html>
<head>
<title>Reading XML with jQuery</title>
<style>
#response
{
border: solid 1px black;
padding: 5px;
}
</style>
<script src="jquery-1.3.2.min.js"></script>
<script>
function processXMLDoc( xmlDoc )
{
var heading = $(xmlDoc).find('heading').text() ;
$( '#response' ).append( '<h1>' + heading + '</h1>' ) ;
var bodyText = $(xmlDoc).find('body').text() ;
$( '#response' ).append( '<p>' + bodyText + '</p>' ) ;
}
$(document).ready(function()
{
jQuery.ajax({
type: "GET",
url: "a.xml", // ! watch out for same
// origin type problems
dataType: "xml", // 'xml' passes it through the browser's xml parser
success: function( xmlDoc, status )
{
// The SUCCESS EVENT means that the xml document
// came down from the server AND got parsed successfully
// using the browser's own xml parsing caps.
processXMLDoc( xmlDoc );
// IE gets very upset when
// the mime-type of the document that
// gets passed down isn't text/xml.
// If you are missing the text/xml header
// apparently the xml parse fails,
// and in IE you don't get to execute this function AT ALL.
},
complete: function( xhr, status )
{
alert( "COMPLETE. You got:\n\n" + xhr.responseText ) ;
if( status == 'parsererror' )
{
alert( "There was a PARSERERROR. Luckily, we know how to fix that.\n\n" +
"The complete server response text was " + xhr.responseText ) ;
xmlDoc = null;
// Create the xml document from the responseText string.
// This uses the w3schools method.
// see also
if( window.DOMParser )
{
parser=new DOMParser();
xmlDoc=parser.parseFromString( xhr.responseText,"text/xml" ) ;
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject( "Microsoft.XMLDOM" ) ;
xmlDoc.async = "false" ;
xmlDoc.loadXML( xhr.responseText ) ;
}
$( '#response' ).append( '<p>complete event/xmlDoc: ' + xmlDoc + '</p>' ) ;
$( '#response' ).append( '<p>complete event/status: ' + status + '</p>' ) ;
processXMLDoc( xmlDoc ) ;
}
},
error: function( xhr, status, error )
{
alert( 'ERROR: ' + status ) ;
alert( xhr.responseText ) ;
}
});
});
</script>
</head>
<body>
<div>
<h1>Reading XML with jQuery</h1>
<p>
#1 jQuery.ajax ref
</p>
</div>
<p>Server says:</p>
<pre id="response">
</pre>
</body>
</html>
contents of a.xml
<?xml version="1.0"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
It extends this example.
Check the content type of the response. If you get messages.xml as the wrong mime type, Internet Explorer won't parse it as XML.
To check the content type, you need access to the XMLHttpRequest object. The normal success callback doesn't pass it as a parameter, so you need to add a generic ajaxComplete or ajaxSuccess event handler. The second parameter for those events is the XMLHttpRequest object. You can call the getResponseHeader method on it to get the content type.
$(document).ajaxComplete(function(e, x) {
alert(x.getResponseHeader("Content-Type"));
});
Unfortunately there's no way that I know of in Internet Explorer to override what the server sends, so if it's wrong you need to change the server to send "text/xml" for the content type.
Some browsers have a overrideMimeType method that you can call before send to force it to use "text/xml", but Internet Explorer doesn't support that as far as I know.
The dataType :"xml" does not fix this issue in IE8, rather it throughs a "TypeError" expection.
Quick & Dirty fix, is to wrap the xml response in a html element, like div:
$("<div>" + xml + "</div>").find("something");
(works in all browsers)
You may find that if you pass the data type into your get call, it may parse as XML properly. IE's quirks could stop jQuery autodetecting it as XML, resulting in the wrong data type being passed to the callback function.
<script type="text/javascript">
$(document).ready(function() {
$.get('messages.xml', function(d) {
//I have confirmed that it gets to here in IE
//and it has the xml loaded.
//alert(d); gives me a message box with the xml text in it
//alert($(d).find('message')); gives me "[object Object]"
//alert($(d).find('message')[0]); gives me "undefined"
//alert($(d).find('message').Length); gives me "undefined"
$(d).find('message').each(function() {
//But it never gets to here in IE
var $msg = $(this);
var type = $msg.attr("type");
var message = $msg.text();
switch (type) {
case "HeaderMessage":
$("#HeaderMessageDiv").html(message);
break;
case "FooterMessage":
$("#footermessagecell").html(message);
break;
default:
}
});
}, "xml");
});
</script>
EDIT:
I have actually just experienced .find() not working for a project in any browser but I was able to use .filter() instead. It's annoying that I had to resort to this but if it works....
$(d).filter('message').each(......);
I also had an same problem but I had fixed the IE jQuery XML .find() issue using below code.
Note: Use .text() instead of .html().
jQuery.ajax({
type: "GET",
url: "textxml.php",
success: function(msg){
data = parseXml(msg);
//alert(data);
var final_price = jQuery(data).find("price1").text();
alert(final_price);
}
});
function parseXml(xml) {
if (jQuery.browser.msie) {
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.loadXML(xml);
xml = xmlDoc;
}
return xml;
}
You can do
<a>
<messages>
<message type="HeaderMessage">
This message is put up in the header area.
</message>
<message type="FooterMessage">
This message is put in the lower left cell.
</message>
</messages>
</a>
and use find(). It works for IE8 and for firefox v.3.6.3
Sometimes IE reads line breaks as extra nodes. Try removing the extra white space up to the tags, or try encasing it as CDATA.
I ran into the same problem when I was retrieving data from an XML document. After googling a lot on the Internet, I came up finding this website but with no proper answer to the issue. But one answer helped me solving the problem though:
"Since IE's problem is its xml parser chokes on xml files that are not passed down using the correct "text/xml" header, you can include a bit of code in the Ajax complete event:"
I have identified two problems with IE when making the $.ajax(...) and $.get(...) calls:
The xml parameter value must be in upper case ('XML' not 'xml') for both calls - $.ajax(..., dataType: "XML") and $.get(xmlDataFilePath, function(d){...}, "xml")
When the ajax call succeeds, the xml argument of the callback function is actually a string not an XML DOM object
The second issue is solved this way:
$(document).ready(function()
{
$.ajax(
{
type: "GET",
url: "messages.xml",
dataType: "XML", /* this parameter MUST BE UPPER CASE for it to work in IE */
success: function(xml)
{
processXmlDoc( createXmlDOMObject ( xml ) );
}, /* success: */
error: function(xhr, textStatus, errorThrown)
{
alert(textStatus + ' ' + errorThrown);
} /* error: */
});/* $.ajax */
function createXmlDOMObject(xmlString)
{
var xmlDoc = null;
if( ! window.DOMParser )
{
// the xml string cannot be directly manipulated by browsers
// such as Internet Explorer because they rely on an external
// DOM parsing framework...
// create and load an XML document object through the DOM
// ActiveXObject that it can deal with
xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
xmlDoc.async = false;
xmlDoc.loadXML( xmlString );
}
else
{
// the current browser is capable of creating its own DOM parser
parser = new DOMParser();
xmlDoc = parser.parseFromString( xmlString, "text/xml" ) ;
}
return xmlDoc;
}
function processXmlDoc(xmlDoc)
{
// write here your XML processing logic for the document object...
}
}); // $(document).ready
$.ajax({
url: 'messages.xml',
success: function(data){
$(d).find('message').each(function(){
//But it never gets to here in IE
var $msg = $(this);
var type = $msg.attr("type");
var message = $msg.text();
switch (type) {
case "HeaderMessage":
$("#HeaderMessageDiv").html(message);
break;
case "FooterMessage":
$("#footermessagecell").html(message);
break;
}
});
},
dataType: 'xml'
});
Try telling jQuery what dataType its getting so that it uses the correct methods to process your request .
Change the following content.
dataType :"text/xml",
to
dataType :"xml",
No need to change the find().
I also had an same problem while importing email contacts. I was able to import contacts and display in all the browsers except in IE, as .find() was not working.
So, I assigned "text/xml" to response.contentType.
i.e. response.contentType = "text/xml" and it worked.
earlier it was "text/html"
I had the same problem, I am developing an application which is web-based, but I need it to deploy it offline, inside a CD. I found solution in this page which is the same solution you can se above http://docs.jquery.com/Specifying_the_Data_Type_for_AJAX_Requests
and the code is very simple:
$.ajax({
url: "data.xml",
dataType: ($.browser.msie) ? "text" : "xml",
success: function(data){
var xml;
if (typeof data == "string") {
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = false;
xml.loadXML(data);
} else {
xml = data;
}
// write here your XML processing logic for the document object...
}
});
I have the same problem...
Resolved with this :
http://www.w3schools.com/dom/dom_parser.asp
if (window.DOMParser)
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(text,"text/xml");
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(text);
}
use it to transform your var to xml object...
It's working fine!!! Try this,
Chrome/Firefox:
xml.children[0].childNodes[1].innerHTML;
IE8+/Safari:
xml.childNodes[0].childNodes[1].textContent;
IE8:
xml.documentElement.childNodes[1].text;
Sample code here,
var xml = $.parseXML(XMLDOC);
Var xmlNodeValue = "";
if(userAgent.match("msie 8.0")){
xmlNodeValue = xml.children[0].childNodes[1].innerHTML;
}else{ // IE8+
xmlNodeValue = xml.childNodes[0].childNodes[1].textContent;
}
If the XML is generated by a PHP script you can do
<?php
header("Content-type: text/xml");
echo '<myxml></myxml>';
?>
Then the find method works on every browser

Categories