I am trying to parse xml data with javascript in ajax call.But responseXML is returning null value.Here is my code
<script language="javascript">
if(window.addEventListener)
{
window.addEventListener("load",getXML,false);
}
else if(window.attachEvent)
{
window.attachEvent("onload",getXML);
}
function getXML()
{
var xhr = new XMLHttpRequest();
xhr.open("GET","myxml.xml",true);
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
//alert("got response");
var root = xhr.responseXML;
alert(root);
}
}
xhr.send(null);
}
</script>
Here is my "myxml.xml" file
<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<child-1>
<grandChild1_1>textOfGrandChild1_1</grandchild1_1>
<grandChild2_1>textOfGrandChild2_1</grandchild2_1>
<grandChild3_1>textOfGrandChild3_1</grandchild3_1>
</child-1>
<child-2>
<grandChild1_2>textOfGrandChild1_2</grandchild1_2>
<grandChild2_2>textOfGrandChild2_2</grandchild2_2>
<grandChild3_2>textOfGrandChild3_2</grandchild3_2>
</child-2>
<child-3>
<grandChild1_3>textOfGrandChild1_3</grandchild1_3>
<grandChild2_3>textOfGrandChild2_3</grandchild2_3>
<grandChild3_3>textOfGrandChild3_3</grandchild3_3>
</child-3>
</root>
When I tried with
alert(xhr.responseText)
it showed the xml file as it is.But when using responseXML it is giving null value.Where is the problem?
Your XML is invalid, Case matters
<grandChild1_1>textOfGrandChild1_1</grandchild1_1>
^ ^
All the closing tags have the wrong camel case in the names.
Your XML was incorrect, beacuse it is case sensitive, changed grandchild1_1 to grandChild1_1 and it worked.
<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<child-1>
<grandChild1_1>textOfGrandChild1_1</grandChild1_1>
<grandChild2_1>textOfGrandChild2_1</grandChild2_1>
<grandChild3_1>textOfGrandChild3_1</grandChild3_1>
</child-1>
<child-2>
<grandChild1_2>textOfGrandChild1_2</grandChild1_2>
<grandChild2_2>textOfGrandChild2_2</grandChild2_2>
<grandChild3_2>textOfGrandChild3_2</grandChild3_2>
</child-2>
<child-3>
<grandChild1_3>textOfGrandChild1_3</grandChild1_3>
<grandChild2_3>textOfGrandChild2_3</grandChild2_3>
<grandChild3_3>textOfGrandChild3_3</grandChild3_3>
</child-3>
Here is the Plunker
Thanks!
Related
I am having trouble loading values from an XML file and inserting them into a HTML table. It says that the html tag I am attempting to access is undefined "script.js:15 Uncaught TypeError: Cannot read property 'getElementsByTagName' of undefined". I am trying to insert the values of and into a html table from the loaded XML file.
// script.js
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "table.xml", true);
xmlhttp.send();
}
function myFunction() {
var xmlDoc = XMLHttpRequest.responseXML;
var table = '<tr><th>Name</th><th>Age</th></tr>';
var x = xmlDoc.getElementsByTagName('STUDENT');
for (i = 0; i < x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("NAME")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("AGE")[0].childNodes[0].nodeValue +
"</td></tr>";
}
document.getElementById("students") = table;
}
//relevant html
<body>
<br><br>
<table id="students"></table>
<script src="script.js"></script>
</body>
//XML Doc Contents
<CLASS ID=”Advanced Web Development”>
<STUDENT>
<NAME>Tom</NAME>
<AGE>19</AGE>
<HEIGHT>1.3</HEIGHT>
<SEX>M</SEX>
<GRADE>B</GRADE>
</STUDENT>
<STUDENT>
<NAME>Dick</NAME>
<AGE>29</AGE>
<HEIGHT>1.1</HEIGHT>
<SEX>M</SEX>
<GRADE>A</GRADE>
</STUDENT>
<STUDENT>
<NAME>Harry</NAME>
<AGE>39</AGE>
<HEIGHT>1.5</HEIGHT>
<SEX>M</SEX>
<GRADE>C</GRADE>
</STUDENT>
<STUDENT>
<NAME>Mary</NAME>
<AGE>30</AGE>
<HEIGHT>1.1</HEIGHT>
<SEX>F</SEX>
<GRADE>B+</GRADE>
</STUDENT>
</CLASS>
There appears to be a few things you aren't quite doing right here:
Firstly, the XMLHttpRequest class doesn't have a responseXML property: that isn't where to get the result of an asynchronous request. Instead, the responseXML property belongs to the individual XMLHttpRequest objects (or 'instances'). You create a new XMLHttpRequest instance in the variable xmlhttp in the line var xmlhttp = new XMLHttpRequest();, and it will be xmlhttp that contains the responseXML property.
Additionally, you are passing the value of this in your onreadystatechange handler to myFunction, but myFunction doesn't take any arguments. JavaScript has very lax restrictions on calling functions with the correct number of arguments: any surplus arguments are simply ignored.
Try changing the first couple of lines of this function from
function myFunction() {
var xmlDoc = XMLHttpRequest.responseXML;
to
function myFunction(result) {
var xmlDoc = result.responseXML;
This allows myFunction to receive the xmlhttp instance and pull the response XML out of it.
Secondly, at the end of the function you write:
document.getElementById("students") = table;
Your variable table contains an HTML string representing the contents of a table. However, you can't set an element to an HTML string. What you instead want to do is to assign this HTML string to the inner HTML of this element, using the innerHTML property of the element:
document.getElementById("students").innerHTML = table;
Finally, the XML document you include in your question isn't well-formed, in that the ID attribute of the root element uses smart quotes (”) to surround the value when it should use neutral quotes (") instead. If the XML isn't well-formed, the responseXML property of result will be null.
I made these changes to your code and it worked, in that I could load up the XML and have the table filled out with the data in the XML file.
I'm using Ajax/jQuery to pull in some content from an RSS feed, but it seems to be failing to read the content of an XML node with the name 'link'.
Here's a simplified version of the XML:
<?xml version="1.0" encoding="UTF-8"?>
<channel>
<item>
<title>Title one</title>
<link>https://example.com/</link>
<pubDate>Mon, 12 Feb 2019</pubDate>
</item>
<item>...</item>
<item>...</item>
</channel>
</xml>
And the code I'm using:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$('item', this.responseText).each(function(){
var thisPostData = {};
thisPostData.title = $(this).find('title').text();
thisPostData.link = $(this).find('link').text();
thisPostData.date = $(this).find('pubDate').text();
posts.push(thisPostData);
});
console.log(posts);
}
};
var posts = [];
xhttp.open('GET', 'https://example.com/rssfeed/', true);
xhttp.send();
You'll see I'm trying to add each 'item' to an object, and storing them inside the 'posts' array. 'Title' and 'pubDate' are stored fine but 'link' isn't.
The actual RSS feed in question contains a huge amount of extra data, all of which I can read except the 'link' nodes. Any suggestions why nodes called 'link' would act differently from all the others?
The problem is because you're attempting to parse XML as HTML. The <link> object in HTML is an inline element, not a block level one, so it has no textContent property for jQuery to read, hence the output is empty.
To fix this first read the XML using $.parseXML(), then put it in a jQuery object which you can traverse.
There's also a couple of things to note. Firstly you will need to remove the </xml> node at the end of the XML output as it's invalid and will cause an error when run through $.parseXML. Secondly you can use map() to build an array instead of manually calling push() on an array, and you can just return the object definition directly from that. Try this:
var responseText = '<?xml version="1.0" encoding="UTF-8"?><channel><item><title>Title one</title><link>https://example.com/</link><pubDate>Mon, 12 Feb 2019</pubDate></item><item><title>Title two</title><link>https://foo.com/</link><pubDate>Tue, 13 Feb 2019</pubDate></item></channel>';
var xmlDoc = $.parseXML(responseText)
var posts = $('item', xmlDoc).map(function() {
var $item = $(this);
return {
title: $item.find('title').text(),
link: $item.find('link').text(),
date: $item.find('pubDate').text()
};
}).get();
console.log(posts);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Lastly, you're using a rather odd mix of JS and jQuery. I'd suggest going with one or the other. As such, here's a full jQuery implementation with the AJAX request included too:
$.ajax({
url: 'https://example.com/rssfeed/',
success: function(responseText) {
var xmlDoc = $.parseXML(responseText)
var posts = $('item', xmlDoc).map(function() {
var $item = $(this);
return {
title: $item.find('title').text(),
link: $item.find('link').text(),
date: $item.find('pubDate').text()
};
}).get();
// work with posts here...
}
});
I'm trying to retrieve some data from an xml file using ajax
<?xml version="1.0" encoding=UTF-8"?>
<user>
<u_idno>1</u_idno>
<u_name>nobody</u_name>
<u_srnm>nothing</u_srnm>
<u_role>linux</u_role>
</user>
<user>
<u_idno>2</u_idno>
<u_name>yesbody</u_name>
<u_srnm>something</u_srnm>
<u_role>administrator</u_role>
</user>
but I am getting an error
Uncaught TypeError: Cannot read property 'getElementsByTagName' of null
I am unsure why it would say null and I've been googling furiously to find out what I've done wrong but I'm clueless. My javascript is as followed
function f_ajax() {
var lv_request;
try {
lv_request = new XMLHttpRequest();
} catch (error) {
lv_request = new ActiveXObject("Microsoft.XMLHTTP");
}
lv_request.onreadystatechange = function() {
if(lv_request.readyState == 4 && lv_request.status == 200) {
lv_xml = lv_request.responseXML;
lv_row = lv_xml.getElementsByTagName("user");
lv_output = null;
for (lv_cnt = 0; lv_cnt < lv_row.length; lv_cnt++) {
lv_output = lv_output + lv_row[lv_cnt].childNodes[0].nodeValue;
}
document.getElementById("h2_ajax").innerHTML = lv_row;
}
}
lv_request.open("GET", "data.xml", true);
lv_request.send();
};
f_ajax();
Your XML is not well formed. It is missing a root and has some other issues. Try this:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<user>
<u_idno>1</u_idno>
<u_name>nobody</u_name>
<u_srnm>nothing</u_srnm>
<u_role>linux</u_role>
</user>
<user>
<u_idno>2</u_idno>
<u_name>yesbody</u_name>
<u_srnm>something</u_srnm>
<u_role>administrator</u_role>
</user>
</root>
I am using IE9 and jquery-1.8.0.js. I am getting extra junk character in responseXML. The actual XML sent by server is as below,
<?xml version="1.0" encoding="UTF-8" ?><ResponseStatus><version>0.0.1</version><requestURL>myurl.com</requestURL><statusCode>-1</statusCode><statusString>success</statusString></ResponseStatus>
But when I check responseText it shows as below which is giving error with loadXML. Notice the spaces and \r\n- characters added unneeded,
" <?xml version=\"1.0\" encoding=\"UTF-8\" ?> \r\n- <ResponseStatus>\r\n <version>0.0.1</version> \r\n <requestURL>myurl.com</requestURL> \r\n <statusCode>-1</statusCode> \r\n <statusString>success</statusString> \r\n </ResponseStatus>"
below is the code snippet,
var options =
{
beforeSend:...
error:...
success: function (responseXML, statusText, xhr, $form)
{
var xmlobj = responseXML.documentElement.innerText;
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(xmlobj);
//xmlDoc.parseError.errorCode = -1072896682
//xmldoc.reason = "Invalid at the top level of the document.\r\n"
}
};
I am wondering who is changing the XML automatically. I appreciate your guidance resolving this.
Thanks,
Jdp
I don't know the exact reason about who is tampering the XML in between but I used below function to sanitize the XML and resolved my problem.
function sanitizeXML(xmlobj)
{
"use strict";
return xmlobj.replace("\r\n-","");
}
Appreciate if there is any good solution.
I have the following code that applies a XSLT style
Test.Xml.xslTransform = function(xml, xsl) {
try {
// code for IE
if (window.ActiveXObject) {
ex = xml.transformNode(xsl);
return ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument) {
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml, document);
return resultDocument;
}
} catch (exception) {
if (typeof (exception) == "object") {
if (exception.message) {
alert(exception.message);
}
} else {
alert(exception);
}
}
The code is working in IE and firefox but not in Chrome and Safari. Any ideas why?
Update
ResultDocument = xsltProcessor.transformToFragment(xml, document);
The line above is returning null. No error is being thrown.
Update
The code is not working as the xslt file contains xsl:include. Need to find a way to get the include working I will paste progress here
Update
It has been recomended that I use the http://plugins.jquery.com/project/Transform/ plugin. I am trying to use the client side libary as the example of include works here (http://daersystems.com/jquery/transform/).
The code works in IE but still not in chrome.
Test.Xml.xslTransform = function(xml, xsl) {
try {
$("body").append("<div id='test' style='display:none;'></div>");
var a = $("#test").transform({ xmlobj: xml, xslobj: xsl });
return a.html();
}
catch (exception) {
if (typeof (exception) == "object") {
if (exception.message) {
alert(exception.message);
}
} else {
alert(exception);
}
}
}
xml and xsl are both objects being passed in.
Update
I tried changing the XSL file to being something very simple with no include and Chrome is still not applying the stylesheet and IE is. The XSL that is being brought in as an object is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:spsoap="http://schemas.microsoft.com/sharepoint/soap/"
>
<xsl:output method="html"/>
<xsl:template match="/">
<h1>test</h1>
</xsl:template>
</xsl:stylesheet>
Update
The end result that I want is for the xsl to be applied to the xml file. The xsl file has in it includes. I want the trasnfer to happen on the client ideally.
Updated
Rupert could you update the question with the xml and how you're calling Test.Xml.xslTransform ?
I got the xml using ie8
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><SearchListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/"><SearchListItemsResult><listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<rs:data ItemCount="1">
<z:row ows_Title="Test" ows_FirstName="Test 4" ows_UniqueId="74;#{1A16CF3E-524D-4DEF-BE36-68A964CC24DF}" ows_FSObjType="74;#0" ows_MetaInfo="74;#" ows_ID="74" ows_owshiddenversion="10" ows_Created="2009-12-29 12:21:01" ows_FileRef="74;#Lists/My List Name/74_.000" ReadOnly="False" VerificationRequired="0"/>
</rs:data>
</listitems></SearchListItemsResult></SearchListItemsResponse></soap:Body></soap:Envelope>
The code is being called as follows:
xsl = Test.Xml.loadXMLDoc("/_layouts/xsl/xsl.xslt");
var doc = Test.Xml.xslTransform(xData.responseXML, xsl);
xData is the xml returned by a web service.
If your XSLT is using xsl:include you might receive weird unexplainable errors but always with the same end result: your transformation failing.
See this chromium bug report and please support it!
http://code.google.com/p/chromium/issues/detail?id=8441
The bug is actually in webkit though. For more info here's another link which goes into more detail why it doesn't work.
The only way around this is to pre-process the stylesheet so that it injects the included stylesheets. Which is what a crossbrowser XSLT library like Sarissa will do for you automatically.
If your looking for jQuery solution:
http://plugins.jquery.com/project/Transform/ is a cross browser XSL plug-in. I've succesfully used this to get xsl:include working in the past without much hassle. You don't have to rewrite your xsl's this plugin will pre-process them for you. Definitely worth looking at as it's more lightweight then Sarissa.
UPDATE:
<html>
<head>
<script language="javascript" src="jquery-1.3.2.min.js"></script>
<script language="javascript" src="jquery.transform.js"></script>
<script type="text/javascript">
function loadXML(file)
{
var xmlDoc = null;
try //Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load(file);
}
catch(e)
{
try //Firefox, Mozilla, Opera, etc.
{
xmlDoc=document.implementation.createDocument("","",null);
xmlDoc.async=false;
xmlDoc.load(file);
}
catch(e)
{
try //Google Chrome
{
var xmlhttp = new window.XMLHttpRequest();
xmlhttp.open("GET",file,false);
xmlhttp.send(null);
xmlDoc = xmlhttp.responseXML.documentElement;
}
catch(e)
{
error=e.message;
}
}
}
return xmlDoc;
}
function xslTransform(xmlObject, xslObject)
{
try
{
$("body").append("<div id='test'></div>");
var a = $("#test").transform({ xmlobj: xmlObject, xslobj: xslObject });
}
catch (exception)
{
if (typeof (exception) == "object" && exception.message)
alert(exception.message);
else alert(exception);
}
}
var xmlObject = loadXML("input.xml");
var xslObject = loadXML("transform.xsl");
$(document).ready(function()
{
xslTransform(xmlObject, xslObject);
});
</script>
</head>
<body>
</body>
</html>
This test html page works both in Chrome/FireFox/IE.
input.xml is just a simple xml file containing <root />
transform.xsl is the stripped down xsl you posted.
EDIT
It does however seem the $.transform has problems importing stylesheets from included files:
Here's how to fix this:
Locate
var safariimportincludefix = function(xObj,rootConfig) {
in jquery.transform.js and replace the entire function with this:
var safariimportincludefix = function(xObj,rootConfig) {
var vals = $.merge($.makeArray(xObj.getElementsByTagName("import")),$.makeArray(xObj.getElementsByTagName("include")));
for(var x=0;x<vals.length;x++) {
var node = vals[x];
$.ajax({
passData : { node : node, xObj : xObj, rootConfig : rootConfig},
dataType : "xml",
async : false,
url : replaceref(node.getAttribute("href"),rootConfig),
success : function(xhr) {
try {
var _ = this.passData;
xhr = safariimportincludefix(xhr,_.rootConfig);
var imports = $.merge(childNodes(xhr.getElementsByTagName("stylesheet")[0],"param"),childNodes(xhr.getElementsByTagName("stylesheet")[0],"template"));
var excistingNodes = [];
try
{
var sheet = _.xObj;
var params = childNodes(sheet,"param");
var stylesheets = childNodes(sheet,"template");
existingNodes = $.merge(params,stylesheets);
}
catch(exception)
{
var x = exception;
}
var existingNames = [];
var existingMatches = [];
for(var a=0;a<existingNodes.length;a++) {
if(existingNodes[a].getAttribute("name")) {
existingNames[existingNodes[a].getAttribute("name")] = true;
} else {
existingMatches[existingNodes[a].getAttribute("match")] = true;
}
}
var pn = _.node.parentNode;
for(var y=0;y<imports.length;y++) {
if(!existingNames[imports[y].getAttribute("name")] && !existingMatches[imports[y].getAttribute("match")]) {
var clonednode = _.xObj.ownerDocument.importNode(imports[y],true);
//pn.insertBefore(clonednode,_.xObj);
pn.insertBefore(clonednode,childNodes(_.xObj,"template")[0]);
}
}
pn.removeChild(_.node);
} catch(ex) {
}
}
});
}
return xObj;
};
Now using the previously pasted test index.html use this for transform.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:include href="include.xsl" />
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:call-template name="giveMeAnIncludedHeader" />
</xsl:template>
</xsl:stylesheet>
And this for include.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="giveMeAnIncludedHeader">
<h1>Test</h1>
</xsl:template>
</xsl:stylesheet>
With the previously posted fix in jquery.transform.js this will now insert the included <h1>Test</h1> on all the browsers.
You can see it in action here: http://www.mpdreamz.nl/xsltest
This is not an answer to the original question but during my search over internet looking for a sample xslt transformation that works on chrome I found links to this thread many times. I was looking for a solution that doesn't use any open-source or third party libraries/plugins and works well with silverlight.
The problem with chrome and safari is the limitation that prevents loading xml files directly. The suggested workaround at http://www.mindlence.com/WP/?p=308 is to load the xml file via any other method and pass it as a string to the xslt processor.
With this approach I was able to perform xsl transformations in javascript and pass on the result to silverlight app via HTML Bridge.