Stymied by recent changes in browser javascript DOMParser and XSL - javascript

The following used to work on Firefox 3.5.x and 3.6.x but it no longer does in Firefox 11.x or Safari 5.1.x. Javascript isn't my specialty, so I'm not up to speed on recent changes.
Specifically, the Browse button apparently still 'successfully' loads a file (which should be an XML sequence export from FCP although this is not validated), but upon pressing the Process button the results of the XSLT no longer appear in the 'output' DIV as they used to with previous browser versions.
It can be seen in context at http://johnpilgrim.net/color/jProcess.html
An appropriate sample XML file for testing is available at http://johnpilgrim.net/color/sample.xml
Nothing changed in the html, javascript or xsl so it seems to be a change in the recent browsers. I only designed and tested it to work in Firefox, and so never tested it in anything else.
Thoughts? Solutions?
Thanks!
John
<head>
<script type="text/javascript">
function jProcess(){
// Get the file contents locally, using the nifty Firefox 3 nsIDOMFile interface
var file_contents = document.getElementById('xml_file').files.item(0).getAsText("utf8");
// Cast/Convert to an XML Document
var parser = new DOMParser();
xmlDoc = parser.parseFromString(file_contents, "text/xml");
// XSLT Transformation
var xslt = document.implementation.createDocument("", "", null);
xslt.async = false;
xslt.load("jProcess.xsl");
var process = new XSLTProcessor();
process.importStylesheet(xslt);
var result = process.transformToFragment(xmlDoc, document);
// Show the output
document.getElementById('output').innerHTML= " ";
document.getElementById('output').appendChild(result);
return false;
};
</script>
</head>
<body>
<form method="post" onsubmit="return jProcess();">
<fieldset>
<legend>Select the XML file for the FCP sequence you want to process into HTML.</legend>
<input type="file" size=100 name="xml_file" id="xml_file">
<input type="submit" value="Convert">
</fieldset>
</form>
<div id="output"></div>

I tried your sample with Firefox 12 on Windows, the error console shows an error
Timestamp: 01.05.2012 11:23:43
Error: document.getElementById("xml_file").files.item(0).getAsText is not a function
Source File: http://johnpilgrim.net/color/jProcess.html
Line: 40
so the code simply does not work any more due to changes in the API exposed on the input type="file" control respectively the File objects exposed in the FileList exposed by that control. Based on https://developer.mozilla.org/en/DOM/File the method getAsText was obsoleted in Gecko/FF 7 and probably removed later on. To read the contents of a file you are now supposed to use https://developer.mozilla.org/en/DOM/FileReader#readAsText%28%29. That seems to be a further asynchronous API so you will have to restructure your code: http://home.arcor.de/martin.honnen/xml/test2012050101.html (that sample works for me with current version of Firefox, Opera and Chrome).
So an example using FileReader looks like
function transform(file, sheetUrl) {
if (typeof FileReader !== 'undefined') {
var fileReader = new FileReader();
fileReader.onload = function(evt) {
var doc = new DOMParser().parseFromString(this.result, 'application/xml');
var proc = new XSLTProcessor();
var req = new XMLHttpRequest();
req.open('GET', sheetUrl, false);
req.send(null);
proc.importStylesheet(req.responseXML);
document.body.appendChild(proc.transformToFragment(doc, document));
};
fileReader.readAsText(file);
}
else {
console.log('No FileReader support.');
}
}

Related

XML transformation error. Working in IE8 but not an other browser. xmlDOM transformNode breaking newer browsers

I am having browser issues running the following scripts. It's a very old application I inherited and I can find no references to this issue that is not more than 5, 7 and 10 years ago.
The script works only when running IE in IE7 compatibility mode, and does not work in any other browser.
gei("calUTA").innerHTML = "<td><xml id=\"calXSLUTA\"><xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:template match=\"/\"><xsl:for-each select=\"/root/month\"><xsl:if test=\"name=\'"+moName[showMo]+"\' and year=\'"+showYr+"\'\"><xsl:value-of select=\"uta\"/></xsl:if></xsl:for-each></xsl:template></xsl:stylesheet></xml></td>";
loopTrans("calXSLUTA","calUTA","big");
function loopTrans(f1,f2,z)
{ if (z == "big" || z == "stu") {
xmlDOM = gei(z + "XML").XMLDocument;
}
xslDOM = eval(f1 + ".XMLDocument");
gei(f2).innerHTML = xmlDOM.transformNode(xslDOM);
}
Newer browsers appear to be erroring out while executing the transformNode function. Any help will be appreciated.
The specific error message returned is "Unable to get property 'transformNode' of undefined or null reference".
The API to run client-side XSLT 1.0 by the browser from JavaScript in any other browsers but IE based ones is documented at https://developer.mozilla.org/en-US/docs/Web/API/XSLTProcessor. The whole IE legacy stuff like XML data islands is not even supported in the last IE versions, although they should still allow you to instantiate new ActiveXObject('Msxml2.DOMDocument.3.0') to have an XML DOM document to loadXML the XML input or the XSLT code from a string (or the load method to load from a URL) and then run transformNode on that created XML DOM.
So IE code would be like
var xmlDoc = new ActiveXObject('Msxml2.DOMDocument.3.0');
xmlDoc.loadXML('<root><month>..<\/month><\/root>');
var xsltDoc = new ActiveXObject('Msxml2.DOMDocument.3.0');
xsltDoc.loadXML('<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:template match=\"/\"><xsl:for-each select=\"/root/month\"><xsl:if test=\"name=\'"+moName[showMo]+"\' and year=\'"+showYr+"\'\"><xsl:value-of select=\"uta\"/></xsl:if></xsl:for-each></xsl:template></xsl:stylesheet>');
var transformationResult = xmlDoc.transformNode(xsltDoc); // assign the result string to innerHTML of an HTML element to render it
other browser like
var domParser = new DOMParser();
var xmlDoc = domParser.parseFromString('<root><month>..<\/month><\/root>', 'application/xml');
var xsltDoc = domParser.parseFromString('<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:template match=\"/\"><xsl:for-each select=\"/root/month\"><xsl:if test=\"name=\'"+moName[showMo]+"\' and year=\'"+showYr+"\'\"><xsl:value-of select=\"uta\"/></xsl:if></xsl:for-each></xsl:template></xsl:stylesheet>', 'application/xml');
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsltDoc);
var transformationResult = xsltProcessor.transformToFragment(xmlDoc, document); // insert this document fragment with e.g. appendChild to HTML element to render it
In any case, if you don't need IE support, I would consider ditching XSLT 1 and using Saxon-JS 2 and XSLT 3 instead. In any case, the use of an XSLT parameter with xsl:param instead of that string concatenation in <xsl:if test=\"name=\'"+moName[showMo]+"\' should make the code more robust.

Read XML File using Javascript from a Local Folder

I am trying to learn how to read into a web page data in an XML file. This is a static HTML page. I do not want a web server and I cannot use Ajax. The XML file is local (in the same directory as the HTML file). I want this to work in a Chrome browser.
What I need to do is:
Read the XML file on the page onLoad event.
Use innerHTML to insert the XML data into a div.
My problem is in reading the XML file. All of the examples I have found I think will only work if there is a web server running, which I have to avoid.
If you're reading another file the only way to do that with front end JS is another request (ajax). If this were node.js it would be different because node can access the filesystem. Alternatively if you get the xml into a javascript string on the same page, you can manipulate it. There are a number of good libraries (jquery's parseXML).
Original answer here: https://stackoverflow.com/a/48633464/8612509
So, I might be a little late to the party, but this is to help anybody else who's been ripping his/her hair out looking for a solution to this.
First of all, CORS needs to be allowed in the browser if you're not running your HTML file off a server. Second, I found that the code snippets most people refer to in these kind of threads don't work for loading local XML-files. Try this (example taken from the official docs):
var xhr = new XMLHttpRequest();
xhr.open('GET', 'file.xml', true);
xhr.timeout = 2000; // time in milliseconds
xhr.onload = function () {
// Request finished. Do processing here.
var xmlDoc = this.responseXML; // <- Here's your XML file
};
xhr.ontimeout = function (e) {
// XMLHttpRequest timed out. Do something here.
};
xhr.send(null);
The method (1st arg) is ignored in xhr.open if you're referring to a local file, and async (3rd arg) is true by default, so you really just need to point to your file and then parse the result! =)
Good luck!
Since you're only targeting Chrome, you could take a look at the File API. You'd have to prompt the user to select the file or drop it into a specific area of the page though, which might be something you'd rather avoid, or not. The following HTML5 Rocks article should help.
Assuming the HTML, XML and browser are all on the same machine, you might try using an Iframe in the HTML that references the XML using a URL like file:\.
You could do something like this:
<html>
<head>
<script type="text/javascript">
//If using jQuery, select the tag using something like this to manipulate
//the look of the xml tags and stuff.
$('#xframe').attr('style', 'thisxmltag.....');
</script>
</head>
<body>
...
<frame id="xframe" src="the_xml_doc"></src>
</body>
</html>
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET", file_Location, false);
xmlhttp.send();
xmlDoc = xmlhttp.responseXML;
document.getElementById(your_div_id).value =
xmlDoc.getElementsByTagName(The_tag_in_xml_you_want_to_display)
[0].childNodes[0].nodeValue;
Works with IE11
<head>
// To be hidden with a better method than using width and height
<OBJECT id="data1" data="data.xml" width="1px" height="1px"></OBJECT>
// to work offline
<script src="lib/jquery-2.2.3.min.js"></script>
</head>
<body>
<script>
var TheDocument = document.getElementById("data1").contentDocument;
var Customers = TheDocument.getElementsByTagName("myListofCustomers");
var val1 = Customers[0].getElementsByTagName("Name")[0].childNodes[0].nodeValue;

Reading XML File, Run Correct At IE but Not At Firefox

I make program to read xml file by using traditional JavaScript.
<script type="text/javascript">
var xmlDoc;
function loadxml(sImportXML) {
if( window.ActiveXObject && /Win/.test(navigator.userAgent) ) {
xmlDoc = new ActiveXObject("Msxml.DOMDocument");
xmlDoc.async = false;
xmlDoc.onreadystatechange = function () {
if (xmlDoc.readyState == 4) readXML();
}
xmlDoc.load(sImportXML);
}
else if( document.implementation && document.implementation.createDocument ) {
xmlDoc = document.implementation.createDocument("","",null);
xmlDoc.async=false;
alert(sImportXML);
var loaded = xmlDoc.load(sImportXML);
if (loaded) {
readXML();
}
}
else {
alert("Your browser can\'t handle this script");
return;
}
}
 
<body onload="loadxml('../XML/Question.xml');">
Upper loadxml function run correctly at IE but not at firefox.
alert line display this value ../XML/Question.xml.
but xmlDoc.Load function did not run correctly.
It reply error Access to restricted URI denied
Please anyone help me.
In Firefox the javascript will not let you access files on the user's local file system; there's simply no way to do it. That would be a huge security breach.
This works in Internet Explorer with ActiveX because ActiveX is a plug-and-play application module system (kind of like mini browser plugins) where the apps, like 'Msxml.DOMDocument', have more power than just javascript and can access files on the user's local file system.
But document.implementation is regular javascript, so it has all normal security restrictions, a major one being that the user's file system is off limits.
If the XML file is on the server, you can embed in your html code like this:
<script id="the-xml" type="text/xml">
....your xml document contents here....
</script>
Then you can get the contents in javascript like this:
var sImportXML = document.getElementById('the-xml').text;
But depending on your application, it might make sense to not use the javascript xml at all. Usually, you'd parse the xml on the server side, and communicate with javascript in json or html snippets.

Can someone help me understand AJAX (JSON) problem?

My goal is to create an personal application out of my ActionScript3 video player. I want to be able to hold keep the single .swf file in my browser and through AJAX, pass the .swf the url to my videos. I've chosen to use JSON as my data.
I'm new to JSON and I've hit a wall. It seems completely easy, but at first I wasn't even able to even get my locally hosted .json file into my webapp. It was working when I tried to do this with XML. After a bunch of trouble shooting, it is now in fact getting my XMLHttpRequest.
I'm trying to keep with backwards compatibility as much as possible, and thus I'm using the json2.js library to secure that notion.
My current issue is not being able to parse my XMLHTTPRequest. To be honest, I'm not even sure if what I'm doing is right as everywhere I look for examples, they're almost all pointing to a solution that writes the JSON into the actual webpage.
My external JSON file: test.json.
{ "video":"test.f4v", "thumb":"test.jpg", "title":"The test", "caption":"TEST TEST TEST TEST TEST", "minutes":01, "seconds":43 }
I'm positive the JSON file is valid.
Here is my html/javascript:
<script type="text/javascript" src="js/json2.js"></script>
<script type="text/javascript">
window.onload = initAll();
function initAll(){
var jsonData = {};
var xhr = false;
if(window.XMLHttpRequest){ //Chrome, Firefox, Opera, Safari, IE7+
xhr = new XMLHttpRequest();
} else if(window.ActiveXObject){ //IE5 + IE6
try{
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e){
try{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
alert("Could not make XMLHttpRequest");
}
}
}
if(xhr){
xhr.open("GET", "js/ajax/test.json", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200){
try{
jsonData = JSON.parse(xhr.responseText);
alert(jsonData.title);
document.getElementById("vidtitle").innerHTML = xhr.responseText.title;
document.getElementById("vidcaption").innerHTML = jsonData.caption;
} catch(e){
alert("Unable to parse jsonData.");
}
}
};
xhr.send(null);
}
}
</script>
</head>
<body><div class="vidcontent">
<h2 id="vidtitle"></h2>
<p id="vidcaption"></p>
I'm doing this locally on my server, but I have uploaded the files to my web host and still get the same issues.
Firebug tells me it has the data and I can even read it through the console. Now, The code works in Firefox, but not Chrome or IE8 (IE8 Works occasionally when I put it into compatibility mode, but not always <.< ) I can't test on Safari or Opera right now.
Is there any way I can get this working in these browsers? I have attempted $.parseJSON in the JQuery library, but I was having issues with that as well. I am interested in JQuery as well if anyone can explain the solution with it.
Your JSON is invalid: http://www.jsonlint.com/
Leading 0's are not allowed in numbers apparently.

mozilla client side XSLT not displaying. (Using jQuery too)

I want to use firebug to debug and help be quickly finish some XSLT layout issues, but I cannot get the following code to perform and display the client side XSLT in Firefox (everything is fine in IE):
$().ready(function() {
var oXMLHTTP
var oXSLT
if ($.browser.mozilla){
oXMLHTTP = document.implementation.createDocument("","",null);
oXSLT = document.implementation.createDocument("","",null);
}else{
oXMLHTTP = new ActiveXObject("Microsoft.XMLDOM");
oXSLT = new ActiveXObject("Microsoft.XMLDOM");
}
oXMLHTTP.async = false;
oXSLT.async = false;
oXSLT.load('Layout.xslt');
var sURL = "somepage"
/**/
$.get(sURL,function(data){
var sTranformedXML = "";
if ($.browser.mozilla){
oXMLHTTP.load(data);
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(oXSLT);
var mDoc = document.implementation.createDocument("","",null);
sTranformedXML = xsltProcessor.transformToFragment(oXMLHTTP,mDoc);
}else{
oXMLHTTP.loadXML(data);
sTranformedXML = oXMLHTTP.transformNode(oXSLT)
}
$("#main").html(sTranformedXML);
$("#tbl_Not Grouped").insertAfter("tbl_Social Sciences");
})// $.get
})
Is there something that I have overlooked here?
I really only need the Firefox code testing. So, it does not need to be pretty.
Gecko's XSL-T implementation is known to handle default namespaces wrongly. Try prefixing elements in your XML document and/or prefix elements in XPath queries in XSL document (do not forget to bind new prefixes)
This does not really answer your question per se, but you might consider taking a look at Google AJAXSLT, which wraps the various browsers' capabilities and "fills in the gaps:" link

Categories