I'm trying to find the solution to load xml file and retrieve element value by tag name but stuck at the final step. Code is working in all other modern browsers except IE8.
function getXML(xmlStr) {
if (window.DOMParser) {
alert("window.DOMParser");
return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
} else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
alert("Microsoft.XMLDOM");
var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(xmlStr);
alert("xmlDoc");
return xmlDoc;
} else {
return null;
}
}
$(document).ready(function() {
var xmlStr = "<xml><elem>element1</elem><elem>element2</elem></xml>";
var xmlDoc = getXML(xmlStr);
$("#result").html("<b>Elemtent:</b> " + JSON.stringify(xmlDoc) + "<br/><br>");
});
I've created jsfiddle here which is the modification of the actual post answer by Tim Down.
I've tried many ways but no luck at all. Is it possible to load xml and get values in IE8?
Related
I wonder how to linearize or unindent an XML text using Javascript.
This post Unindent or linearize XML describes how to do it using Java, but I saw no example using JavaScript.
As I indicated in the comment on your answer, regex is not a reliable way to do this. A much more reliable approach is to parse the XML, remove any text nodes that are all whitespace, and then re-serialize it:
function parseXml(txt) {
var parser, xmlDoc;
if (window.DOMParser) {
parser = new DOMParser();
xmlDoc = parser.parseFromString(txt, "text/xml");
} else // Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(txt);
}
return xmlDoc;
}
function serializeXml(node) {
try {
// XMLSerializer exists in certain browsers
var serializer = new XMLSerializer();
return serializer.serializeToString(node);
} catch (e) {
// Internet Explorer has a different approach to serializing XML
return elem.xml;
}
}
function removeWhitespace(node) {
if (node.childNodes && node.childNodes.length) {
Array.prototype.slice.call(node.childNodes).forEach(removeWhitespace);
}
if ((node.nodeType === 3 || node.nodeType === 4) &&
/^[ \r\n\t]*$/.test(node.textContent)) {
node.parentNode.removeChild(node);
}
}
var startXml = '<products>\n\t<product>\n\t\t<code>1234</code>\n\t\t<name>Widget 3000</name>\n\t</product>\n</products>'
console.log('Before:');
console.log(startXml);
var dom = parseXml(startXml);
removeWhitespace(dom);
var endXml = serializeXml(dom);
console.log('After:');
console.log(endXml);
As tebs1200 suggested, I ported (and even improved) the regular expression from the Java post to Javascript.
Here it is:
// This Javascript function is to linearize and return the XML input String
function linearize(xml) {
return (xml!= null) ? xml.trim().replace(/(>|>){1,1}( |\t|\n|\r|\s)*(<|<){1,1}/g, "$1$3") : null;
}
I have a form where I get a XML, manipulate it as the user fill the form, and eventually transform this manipulated XML through a XSL. I need this solution to work in Chrome, Firefox and Internet Explorer 8 to 11 without compatibility mode.
I wrote a JSFiddle with the code I have working successfully to IE 9 (or at least without user complains), Chrome and Firefox. But I have an issue on IE 11. When my code tries to perform transformNode from ActiveXObject. I've tried some suggestions I've found in several sites, including here, but some simply doesn't worked or started throwing exceptions when my code tried to manipulate the XML. So I need help on getting this code working properly.
Here is the JSFiddle: https://jsfiddle.net/mfedatto/6nsc5bf1/
HTML
<div id="wrapper"></div>
<div id="console"></div>
JavaScript
try {
function getXmlDom(content) {
var xmlDom;
if (typeof window.DOMParser != "undefined") {
trace.push("Creating DOMParser");
xmlDom = (new window.DOMParser()).parseFromString(content, "text/xml");
trace.push("DOMParser created");
}
else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
try {
trace.push("Creating MSXML2.DOMDocument.6.0");
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
trace.push("MSXML2.DOMDocument.6.0 created");
}
catch (ex) {
trace.push("Creating Microsoft.XMLHTTP");
xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
trace.push("Microsoft.XMLHTTP created");
}
xmlDom.async = "false";
try { xmlDoc.responseType = "msxml-document"; } catch (ex) { }
trace.push("Loading XML content");
xmlDom.loadXML(content);
trace.push("XML content loaded");
}
else {
throw new Error("No XML parser found");
}
return xmlDom;
}
function xslTransformTo(xsl, xml, wrapper) {
if ((window.ActiveXObject) || "ActiveXObject" in window) {
trace.push("Transforming with ActiveXObject");
wrapper.innerHTML = xml.transformNode(xsl);
trace.push("Transformed with ActiveXObject");
}
else if (document.implementation && document.implementation.createDocument) {
trace.push("Transforming with XSLTProcessor");
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
trace.push("Transformed with XSLTProcessor");
}
else {
throw new Error("No XSL parser found");
}
}
function xmlString(xml) {
return (new XMLSerializer()).serializeToString(xml);
}
function showError(ex) {
var console = document.getElementById("console");
showTrace();
console.appendChild(document.createTextNode("ERROR!!! " + ex.message));
}
function showTrace() {
var console = document.getElementById("console");
for (var i = 0; i < trace.length; i++) {
console.appendChild(document.createTextNode(trace[i]));
console.appendChild(document.createElement("br"));
}
}
var trace = [];
var strXml = "<root>\n"
+ " <fc>\n"
+ " <sc>\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " </sc>\n"
+ " </fc>\n"
+ "</root>";
trace.push("XML string defined");
var strXsl = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ " <xsl:template match=\"/root\">\n"
+ " <ul>\n"
+ " <xsl:for-each select=\"fc/sc/i\">\n"
+ " <li>[<xsl:value-of select=\"position()\" />]</li>\n"
+ " </xsl:for-each>\n"
+ " </ul>\n"
+ " </xsl:template>\n"
+ "</xsl:stylesheet>";
trace.push("XSL string defined");
var strWrapperId = "wrapper";
trace.push("Parsing XML");
var xmlDoc = getXmlDom(strXml);
trace.push("XML parsed");
trace.push("Parsing XSL");
var xslDoc = getXmlDom(strXsl);
trace.push("XML parsed");
var domWrapper = document.getElementById(strWrapperId);
var xmlItemList = xmlDoc.getElementsByTagName("i");
trace.push("All variables loaded");
trace.push("Iterating item positions");
try {
for (var i = 0; i < xmlItemList.length; i++) {
xmlItemList[i].setAttribute("p", i);
}
}
catch (ex) {
showError(ex);
return;
}
trace.push("Itens positions iterared");
trace.push("Transforming XML with XSL to wrapper");
try {
xslTransformTo(xslDoc, xmlDoc, domWrapper);
}
catch (ex) {
showError(ex);
return;
}
showTrace();
}
catch (ex) {
alert(ex.message);
}
P.S.: The only difference with the code I use is the trace and the loadXML based on string content, as in fact I use load method with a accessible uri.
Edit 1 - 23/fev/16
I tried to run the JSFiddle posted by Martin Honnen on IE 11 and it shows ERROR!!! No XSL parser found. I did some refactoring using the instructions on MSDN page he suggested. That article instructs to try, not to test, because some plugins may be instantiated but not detected. And going that way my IE 11 creates and load my XML and XSL objects and content using DOMParser but fails to transform with both transformNode and XSLTProcessor. As done in: http://jsfiddle.net/mfedatto/6nsc5bf1/38
Edit 2 - 25/fev/16
For some reason the solution doesn't work on JSFiddle, I'll do some digging about it. But with Martin Honnen answer I could load my external XML and XSL files crossbrowser, including IE 11. Here is the final code I used:
function loadXmlFile(path) {
var xmlDoc;
if (loadXmlFile.cache === undefined) {
loadXmlFile.cache = { };
}
if (loadXmlFile.cache[path] === undefined) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
}
catch (e) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
}
catch (e2) {
xmlDoc = new XMLHttpRequest();
xmlDoc.responseType = "application/xml";
}
}
try {
xmlDoc.open("GET", path, false);
xmlDoc.send();
loadXmlFile.cache[path] = xmlDoc.responseXML;
}
catch (ex) {
xmlDoc.async = false;
xmlDoc.load(path);
loadXmlFile.cache[path] = xmlDoc;
}
}
return loadXmlFile.cache[path];
}
function xslTransformTo(xsl, xml, wrapper) {
if (typeof xml.transformNode != "undefined") {
wrapper.innerHTML = xml.transformNode(xsl);
}
else if (typeof XSLTProcessor != "undefined") {
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
}
}
See https://msdn.microsoft.com/en-us/library/dn423948(v=vs.85).aspx, in IE 11 you need to use new ActiveXObject('program.id') inside of a try/catch, the check for the window property does not work.
Furthermore, the native IE DOM documents you create with DOMParser in IE do not support transformNode, so if you know you need an XML DOM document in IE to do XSLT transformation then you need to make sure you create an MSXML DOM document with new ActiveXObject and you need to do try to do that first in your code with try/catch, before you try to instantiate DOMParser.
So for the XML parsing from a string I would use
function getXmlDom(content) {
var xmlDom;
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.6.0');
xmlDom.loadXML(content);
}
catch (e) {
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.3.0');
xmlDom.loadXML(content);
}
catch (e2) {
xmlDom = (new DOMParser()).parseFromString(content, 'application/xml');
}
}
return xmlDom;
}
as done in http://home.arcor.de/martin.honnen/javascript/2016/test2016022301.html.
The below code does not run in Chrome.
function parseXML(xmlstring) {
var dom;
if (window.ActiveXObject && window.GetObject) {
dom = new ActiveXObject('Microsoft.XMLDOM');
dom.loadXML(xmlstring);
return dom;
}
if (window.DOMParser) {
var xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", xmlstring, false);
xmlDoc.overrideMimeType('text/xml');
xmlDoc.onreadystatechange = function () {
if (xmlDoc.readyState == 4 && xmlDoc.status == 200) {
dom = xmlDoc.responseXML;
return dom;
}
};
xmlDoc.send("");
//return new DOMParser().parseFromString((xmlstring), 'text/xml');
}
}
I tried all posibility even used $.parseXML but did not work in Chrome
Your valuable input will be highly appreciated.
i got the dom properly but i was doing $(dom).find('') instead of $(dom.find(" ") dont know why this strange behavior in Chrome...Now it works in all browser...[:)]
I'm designing a client side script that will read an XML file and display it, like this:
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
function loadXML(xmlFile) {
xmlDoc.async = "false";
xmlDoc.onreadystatechange = verify;
xmlDoc.load(xmlFile);
}
function verify() {
if(xmlDoc.readyState != 4) {
return false;
}
}
function traverse(tree) {
if(tree.hasChildNodes()) {
document.write('<ul><li>');
document.write('<b>' + tree.tagName + ': </b>');
var nodes = tree.childNodes.length;
for(var i = 0; i < tree.childNodes.length; i++) {
traverse(tree.childNodes(i));
}
document.write('</il></ul>');
} else {
document.write(tree.text);
}
}
function initTraverse(file) {
loadXML(file);
var doc = xmlDoc.documentElement;
traverse(doc);
}
When I fired Safari I saw that nothing was displayed, then I've opened the Error Console and what I got was this:
ReferenceError: Can't find variable: ActiveXObject
What should I do to make this work?
PS: I would prefer if this page could be capable of running at Mobile Safari
ActiveXObject do not work outside of internet explorer.
There are a few alternative xml parser's and handlers like E4X. Although E4X is currently only done in firefox (https://developer.mozilla.org/En/E4X/Processing_XML_with_E4X).
If using jQuery is an option then you can look into marcgrabanski.com/articles/jquery-makes-parsing-xml-easy
Some interesting stuff going on there. Most interesting is the async = false line. You probably want to re-consider that bit. In order to change to an asynchronous request, you would have to re-write some other code and remove the document.write calls.
Regardless, here is a (untested but hopefully) drop in replacement for what you have using XMLHttpRequest instead of an xml document.
var xmlDoc = null;
function loadXML(xmlFile) {
var request = new XMLHttpRequest();
request.open('GET', xmlFile, false); // false is synchronous
request.send();
xmlDoc = request.responseXML;
}
You may have to do some debugging...
You should have something cross-browser compatible with either DOMParser or DOMDocument. Of course, I'm not sure if you're wanting to parse a XML URL or a XML string. For a XML URL, I recommend:
if (window.XMLHttpRequest) return new window.XMLHttpRequest();
else if (window.ActiveXObject) {
// the many versions of IE's XML fetchers
var AXOs = [
'MSXML2.XMLHTTP.6.0',
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP',
'MSXML.XMLHTTP'
];
for (var i = 0; i < AXOs.length; i++) {
try { return new ActiveXObject(AXOs[i]); }
catch() { continue; }
}
return null;
}
For a XML string, this code block would work better:
if (window.DOMParser) return (new DOMParser()).parseFromString(str, 'text/xml');
else if (window.ActiveXObject) {
var doc;
// the many versions of IE's DOM parsers
var AXOs = [
'MSXML2.DOMDocument.6.0',
'MSXML2.DOMDocument.5.0',
'MSXML2.DOMDocument.4.0',
'MSXML2.DOMDocument.3.0',
'MSXML2.DOMDocument',
'Microsoft.XMLDOM',
'MSXML.DOMDocument'
];
for (var i = 0; i < AXOs.length; i++) {
try { doc = new ActiveXObject(AXOs[i]); break; }
catch() { continue; }
}
if (!doc) return createElement('div', null);
if (doc.async) doc.async = false;
doc.loadXML(str);
return doc;
}
return createElement('div', null);
The DOMDocument objects do support a load() method for loading XML from a URL, but it's a different syntax than the XMLHttpRequest and XMLHTTP methods.
The DOMDocument appears (at least from the MSDN docs) to also contain the XMLHTTP methods, so you could interlace DOMDocument in the AXOs array, but I'm not certain about that. Plus, I can't imagine DOMDocument being in place without XMLHTTP.
Using jQuery I use the selector and the each function to itterate through named elements of an XML string.
e.g.
$("<xml><elem></elem><elem></elem></xml>").each(function()
{
alert("processing elem tag");
});
This works fine in FF/Chrome/IE<8 but in 9 fails. Presumably something in the IE doc no longer allows this.
It's not intended to take a string of XML directly, only from an AJAX response, e.g. .responseXML, in any case don't worry about it at this point.
IE9 has bugs, it's not RTM quality, they are mostly their bugs...I personally wouldn't waste time changing (or even debugging) your code until their's is more complete/stable. (Opinion) don't worry about the client with IE9 either...they signed on for a buggy experience when they installed pre-release software.
jQuery doesn't parse XML. What $("<xml><elem></elem><elem></elem></xml>") does is to create an element and set its innerHTML property to "<xml><elem></elem><elem></elem></xml>", which will have variable and unpredictable results.
You need to parse the XML using the browser's built-in XML parser. Here's a function that does this. I haven't tested it in IE 9 but I'd be surprised if it didn't work: they've implemented DOMParser, so unlike IE < 9 it will fall into the first branch and should work unless they've made a mess of it.
var parseXml;
if (window.DOMParser) {
parseXml = function(xmlStr) {
return ( new window.DOMParser() ).parseFromString(xmlStr, "text/xml");
};
} else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
parseXml = function(xmlStr) {
var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(xmlStr);
return xmlDoc;
};
} else {
parseXml = function() { return null; }
}
var xmlStr = "<xml><elem></elem><elem></elem></xml>";
var xmlDoc = parseXml(xmlStr);
$(xmlDoc).each(function() {
alert("processing elem tag");
});