Javascript and XSLT
XSLT can be used as a means to create a web page from XML data. A better purpose for it is to work along side of AJAX. Use AJAX to retrieve the data in XML form, then use XSLT to format it for the screen. I’ve already covered the basics of AJAX, XML parsing, and some of the XSLT syntax; all thats left is to cover the Javascript functions for requesting XSLT transformations.
To do this we’ll need to make use of the XML parsing objects, I’ll be borrowing some functions from that tutorial. I’ll also be reusing the sample pages from the XSLT tutorials. I’ll copy in the code or provide appropriate links where they’re needed.
To start with we need to create XML objects to hold the XML data and the XSL transform, so you’ll need two different objects. They are both the same objects used when parsing the XML data. In Firefox its the DOMParser object, and in Internet Explorer use the ActiveX Microsoft.XMLDOM object. I’m going to reuse the function from my XML parser tutorial:
function CreateXMLStringParser(XMLString)
{//Function to create the XML objects
try
{
var xmlParser = new DOMParser();
var xmlDoc = xmlParser.parseFromString(XMLString, "text/xml");
}
catch(Err)
{
try
{
var xmlDoc= new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(XMLString);
}
catch(Err)
{
window.alert("Browser does not support XML parsing.");
return false;
}
}
return xmlDoc;
}
We’ll then need to make use of those objects to invoke an XSLT transform. This is done differently in both browsers.
In Firefox you’ll need to create another variable which is an XSLTProcessor object. You’ll then have to import the stylesheet using the object’s importStylesheet() method. Finally you’ll perform the transformation using the transformToFragment() method. Here is an example of all that:
//Create the objects
XML = CreateXMLStringParser("<XMLDataString />");
XSL = CreateXMLStringParser("<XSLTransformString />");
XSLTProcessor = new XSLTProcessor();
//Import the stylesheet
XSLTProcessor.importStylesheet(XSL);
//Perform the transform
TransformResults = XSLTProcessor.transformToFragment(XMLData, document);
As you can see the importStylesheet() method requires one parameter, which is the XSL stylesheet object. The transformToFragment() method requires two parameters; the first is the XML data object, the second is the parent for the resulting document. When Firefox completes the transformation it creates a new DOM document with the transformation results. I’m having it place this new DOM into the document object. Thats the same object that holds the web page, its not assigned to a visible element of the page so it won’t show up on screen. The DOM created will be stored in the TransformResults variable for when we need to use it.
Lets skip over to the Internet Explorer functions for a bit. The objects created to hold the XML/XSL strings have a transformNode() method which can be used to perform XSLT.
//Create the objects
XML = CreateXMLStringParser("<XMLDataString />");
XSL = CreateXMLStringParser("<XSLTransformString />");
//Perform the transform
TransformResults = XML.transformNode(XSL);
As shown in the example you’ll want to call the transformNode() method from the object holding the XML data. It will require one parameter, which is the XSL stylesheet. The biggest difference is how the results are returned. This does not provide a DOM, instead it is a string that holds the transformed XML.
The different formats of the resulting transformed XML makes it different to implement this on the different browsers. The easiest way is to wrap both implementations in a single function along with appending the results to a specific visible element in the document DOM object.
function XSLTTransform(XSLStyleSheet, XMLData, InsertElementID)
{//Function to perform the transform
if (window.ActiveXObject)
{//Code for internet explorer
TransformDoc = XMLData.transformNode(XSLStyleSheet);
document.getElementById(InsertElementID).innerHTML = TransformDoc;
}
else if (document.implementation && document.implementation.createDocument)
{//Code for mozilla
XSLTProcessor = new XSLTProcessor();
XSLTProcessor.importStylesheet(XSLStyleSheet);
TransformDoc = XSLTProcessor.transformToFragment(XMLData, document);
document.getElementById(InsertElementID).appendChild(TransformDoc);
}
else
{//Unknown browser
window.alert("Browser does not support XSLT.");
return false;
}
}
As a side note, I used a different means of handling the browser detection. Previously I wrapped all the implementations in try/catch blocks, where only the valid implementation would be executed. In this example I showed a way of specifically detecting the browser type by checking for specific objects. Both methods will work, so use whichever makes more sense to you.
I’ve created a sample page that shows all of this in action. I’ve told it to load this XML file and this XSL file. It should demonstrate how all the pieces work together.
Since both XML files, the XML data and the XSL stylesheet, are loaded as DOM objects they can be modified by the Javascript prior to the XSLT transformation. This allows you some amount of customization in the transform. Manipulating the XML DOM isn’t always a simple thing. An easier way to accomplish these sort of changes is via XSLT parameters. Similar to how you can set parameter values when applying templates inside of XSLT code, Javascript can set those values when invoking the XSLT transform. There is a big limitation however, Javascript can only change the parameters that are globally scoped. Parameters set inside xsl:template tags can not be changed.
Since each browser uses different objects to process the XSLT, once again we have different code to manipulate the parameters. In Firefox you use the setParameter() method of the XSLTProcessor object. You can adjust the parameters after importing the stylesheet, but before you do the transformation.
//Create the objects
XML = CreateXMLStringParser("<XMLDataString />");
XSL = CreateXMLStringParser("<XSLTransformString />");
XSLTProcessor = new XSLTProcessor();
//Import the stylesheet
XSLTProcessor.importStylesheet(XSL);
//Set the parameters
XSLTProcessor.setParameter(null, 'ParameterName', 'Parameter Value');
//Perform the transform
TransformResults = XSLTProcessor.transformToFragment(XMLData, document);
As you can see the setParameter() method requires three parameters. The first one is the namespace URI, which should be left blank. The second is the name of the parameter you’d like to set, this is the name as used in the XSL file. The third parameter is the new value to assign to that parameter.
Doing the same thing in Internet Explorer is a lot more complicated. The way I demonstrated it before is a quick and simple method that covers all the basic needs. There is a more robust implementation that includes the full XSLT functionality. That is the style we need to use in order to assign parameter values.
First we need to change how the XML data and XSL stylesheets are loaded. They need to change to MSXML2.FreeThreadedDomDocument objects.
var XML = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
XML.async = "false";
XML.load("XMLData.xml");
var XSL = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
XSL.async = "false";
XSL.load("XSLStylesheet.xsl");
Then we need to create an MSXML2.XSLTemplate object, which will hold the compiled version of the XSL stylesheet. Then store the XSL stylesheet data into the stylesheet attribute of the MSXML2.XSLTemplate object.
var XSLTCompiled = new ActiveXObject("MSXML2.XSLTemplate");
//Add the stylesheet information
XSLTCompiled.stylesheet = XSL.documentElement;
Now we need an XSLT processor object which will let us set parameters and perform the transformation. This is created with the var createProcessor() method of the MSXML2.XSLTemplate object. Then we can set the XSLT parameters using the addParameter() method of the XSLT processor object. Finally you perform the transformation using the transform() method.
//Create the XSLT processor
var XSLTProcessor = XSLTCompiled.createProcessor();
//Set the parameters
XSLTProcessor.addParameter("Parameter Name", "Parameter Value");
//Perform the transform
XSLTProcessor.transform();
In the example the addParameter() method requires two parameters; the first is the name of the parameter as its used in the XSL file and the second is the value to assign to that parameter. The transform() method does not require any parameters, its return value will be either true or false based on the success of the transformation. The transformed XML created is stored in the output attribute, its in a text string the same as the previous style demonstrated.
Its difficult to create a single function that will wrap the parameter functionality from both Firefox and Internet Explorer. The best idea I’ve had so far was to have the function accept an array which holds all of the parameters to set; the index is the parameter name and the value is the value to set the parameter to.
function CreateXMLFileParser(XMLFile)
{//Function to lead the XML/XSL files
try
{//Code for Firefox
var xmlDoc = document.implementation.createDocument("", "", null);
xmlDoc.load(XMLFile);
}
catch(Err)
{//Code for Internet Explorer
try
{
//Don't forget to change the object type here!
var xmlDoc= new ActiveXObject("MSXML2.FreeThreadedDomDocument");
xmlDoc.async = "false";
xmlDoc.load(XMLFile);
}
catch(Err)
{
window.alert("Browser does not support XML parsing.");
return false;
}
}
return xmlDoc;
}
function XSLTTransform(XSLStyleSheet, XMLData, InsertElementID, Parameters)
{//Function to perform the XSLT based transformation
if (window.ActiveXObject)
{//Code for internet explorer
var XSLTCompiled = new ActiveXObject("MSXML2.XSLTemplate");
XSLTCompiled.stylesheet = XSLStyleSheet.documentElement;
// create XSL-processor
var XSLTProc = XSLTCompiled.createProcessor();
XSLTProc.input = XMLData;
if (Parameters != "")
{//Loop through the parameters and apply each to the XSLT Processor
for ($Index in Parameters)
{
XSLTProc.addParameter(Index, Parameters[Index]);
}
}
XSLTProc.transform();
document.getElementById(InsertElementID).innerHTML = XSLTProcessor.output;
}
else if (document.implementation && document.implementation.createDocument)
{//Code for mozilla
XSLTProc = new XSLTProcessor();
XSLTProc.importStylesheet(XSLStyleSheet);
if (Parameters != "")
{//Loop through the parameters and apply each to the XSLT Processor
for ($Index in Parameters)
{
XSLTProc.setParameter("", Index, Parameters[Index]);
}
}
TransformDoc = XSLTProc.transformToFragment(XMLData, document);
document.getElementById(InsertElementID).appendChild(TransformDoc);
}
else
{
window.alert("Browser does not support XSLT.");
return false;
}
}
I created a sample page that shows these new functions in action. I’ve set it to load this XML file and this XSL file. It should demonstrate how to set the parameters. I added code to attempt to set a few locally scoped parameters as well, just for final proof that they won’t work.





Hi, thanks for this, it was very useful. One quirk on your page that caught me out, though, was the way you indent the code in the HTML. For some reason when I paste it into TextWrangler on OS X it looks fine, but then when I save it and look at it in vi or in view source from the browser, each line begins with a £ character. Just thought I’d give you a heads up from a temporarily confused Mac user. Cheers.
September 9th, 2008 at 12:00Glad it helped you. I had to use the non-breaking space in HTML ( ) to get the indents to work right. I never considered what it would become when copied into a text editor.
September 9th, 2008 at 12:30This seems to fail on Safari 3.1.2 on OS X 10.5. It gives me a Javascript alert about not supporting XML. I’ve actually run into this before, the parsing Snippit I use is at the end here.
I was digging around for ways to define the xslt Param values for IE and it appears you’ve got some good information here. Thanks!
try
September 9th, 2008 at 15:03{
if (window.ActiveXObject)
{
var errorHappendHere = “Check Browser and security settings”;
xmlDoc = new ActiveXObject(”Microsoft.XMLDOM”);
xmlDoc.async=false;
xmlDoc.load(”file.xml”)
xmlDoc=xmlDoc.documentElement;
}
else if(window.XMLHttpRequest)
{
var errorHappendHere = “Error handling XMLHttpRequest request”;
var d = new XMLHttpRequest();
d.open(”GET”, “file.xml”, false);
d.send(null);
xmlDoc=d.responseXML;
} else {
var errorHappendHere = “Error.”;
xmlDoc = document.implementation.createDocument(”",”",null);
xmlDoc.async=false;
xmlDoc.load(”file.xml”);
}
}
catch(e)
{
alert(errorHappendHere);
}
Thanks Nate! I had run into a similar problem in Google Chrome, which uses the same WebKit project as Safari. I ended up doing hte same thing as you (See this post: http://www.mindlence.com/WP/?p=308). I was curious if it would work in Safari, and I think you just answered that for me.
September 10th, 2008 at 7:09Hi, this is a great post, has been more than helpful. Thank you. If I may, I have an issue with IE in that the paramater does not seem to be passed. In fact, if I include the XSLTProcessor.transform(); it throws an error. The difference between your code and mine is that I am using one function to load the xml and xsl and another to transform. Does your code require that it all be part of the same function?
Thanks
November 20th, 2008 at 12:23It shouldn’t require it all to be in a single function. When you split it up you just have to be very careful that you pass all the objects correctly to each of the functions.
So long as you are using the exact same XSLTProcessor object in both functions it ought to work correctly. You might try making it global to ensure that its the same object in both functions.
November 20th, 2008 at 12:32Thanks for the reply Exile. The only objects being passed are the xml and xsl documents and the XSLTProcessor is only being used in the transform function. I appreciate that this is not a forum and wouldn’t want to impose on your time but below is a copy of the IE code just in case im missing anything obvious or being stupid (or a combination of both!). The error im getting in IE is “the required property does not have a valid value” for the xsltProcessor.transform() line. I presume this means that the Processor is not getting the xsl to Process but can’t figure out why
function loadXMLDoc(fname)
{
var xmlDoc;
// code for IE
if (window.ActiveXObject)
{
xmlDoc=new ActiveXObject(”MSXML2.FreeThreadedDomDocument”);
}
xmlDoc.async=false;
xmlDoc.load(fname);
return(xmlDoc);
}
function displayResult(kword){
if (kword==undefined){
kword=”someword”
}
xml=loadXMLDoc(”thexml.xml”);
xsl=loadXMLDoc(”thexsl.xsl”);
// code for IE
if (window.ActiveXObject)
{
xsltCompiled = new ActiveXObject(”MSXML2.XSLTemplate”);
xsltCompiled.stylesheet = xsl.documentElement;
xsltProcessor = xsltCompiled.createProcessor();
xsltProcessor.addParameter(’kwordC’,kword);
ex1=xsltProcessor.transform();
//ex1=xml.transformNode(xsl);
document.getElementById(”example”).innerHTML=ex1;
}
November 21st, 2008 at 7:17Sorry, ignore the above. I was being stupid as I was working off the top examples and didn’t notice that they were missing input and output commands for the processor! problem solved…Thanks again!
November 21st, 2008 at 10:05Hi ,
I am also getting this same error, and I am not able to figure out what the issue is. I am setting input as well as getting the output also. I am geting the error on call to createProcessor(). Can anyone pls help me out.
My code is : -
if (window.ActiveXObject)
{
var xslt = new ActiveXObject(”Msxml2.XSLTemplate.3.0″);
var xslproc;
xslProc = xslt.createProcessor();
xslt.stylesheet = xsl.documentElement;
xslproc.input = xml;
xslProc.addParameter(”filterField”, “*1*”);
xslProc.transform();
document.getElementById(”PopUpData”).innerHTML=xslproc.output;
}
Thanks in advance!!!!
December 29th, 2008 at 7:23We modifying our web application to suppor Window Mobile.
On Windows Mobile, we are getting problems with
Client side transformation using Javascript.
var xsltCompiled = new ActiveXObject(”MSXML2.XSLTemplate”); // Throws Object Error on Windows Mobile
var XML = new ActiveXObject(”MSXML2.FreeThreadedDomDocument”); // Throws Object Error on Windows Mobile
Looks like MSXML2.FreeThreadedDomDocument, MSXML2.XSLTemplate objects are not supported Windows Mobile. How can we use client side transformation for Windows Mobile?
Thanks in advance.
December 3rd, 2009 at 5:08Hello. This is kind of an “unconventional” question , but have other visitors asked you how get the menu bar to look like you’ve got it? I also have a blog and am really looking to alter around the theme, however am scared to death to mess with it for fear of the search engines punishing me. I am very new to all of this …so i am just not positive exactly how to try to to it all yet. I’ll just keep working on it one day at a time Thanks for any help you can offer here.
January 25th, 2010 at 5:33