An XSLTProcessor
applies an XSLT stylesheet transformation to an XML document to produce a new XML document as output. It has methods to load the XSLT stylesheet, to manipulate <xsl:param>
parameter values, and to apply the transformation to documents.
This are no properties for this interface.
const xsltProcessor = new XSLTProcessor();
const myXMLHTTPRequest = new XMLHttpRequest();
myXMLHTTPRequest.open("GET", "example.xsl", false);
myXMLHTTPRequest.send(null);
const xslRef = myXMLHTTPRequest.responseXML;
xsltProcessor.importStylesheet(xslRef);
For the actual transformation, XSLTProcessor
requires an XML document, which is used in conjunction with the imported XSL file to produce the final result. The XML document can be a separate XML file loaded as shown in figure 1, or it can be part of the existing page. To process part of a page's DOM, it is necessary to first create an XML document in memory. Assuming that the DOM to be processed is contained by an element with the id example
, that DOM can be "cloned" using the in-memory XML document's Document.importNode()
method. Document.importNode()
allows transferring a DOM fragment between documents, in this case from an HTML document to an XML document. The first parameter references the DOM node to clone. By making the second parameter "true", it will clone all descendants as well (a deep clone). The cloned DOM can then be easily inserted into the XML document using Node.appendChild()
, as shown in figure 2.
const xmlRef = document.implementation.createDocument("", "", null);
const myNode = document.getElementById("example");
const clonedNode = xmlRef.importNode(myNode, true);
xmlRef.appendChild(clonedNode);
Once the stylesheet has been imported, XSLTProcessor
has to perform two methods for the actual transformation, namely XSLTProcessor.transformToDocument()
and XSLTProcessor.transformToFragment()
. XSLTProcessor.transformToDocument()
returns a full XML document while XSLTProcessor.transformToFragment()
returns a document fragment that can be easily added to an existing document. Both take in the XML document as the first parameter that will be transformed. XSLTProcessor.transformToFragment()
requires a second parameter, namely the document object that will own the generated fragment. If the generated fragment will be inserted into the current HTML document, passing in document is enough.
You can use the DOMParser
to create an XML document from a string of XML.
const parser = new DOMParser();
const doc = parser.parseFromString(aStr, "text/xml");
const fragment = xsltProcessor.transformToFragment(xmlRef, document);
The basic example will load an XML file and apply a XSL transformation on it. These are the same files used in the Generating HTML example. The XML file describes an article and the XSL file formats the information for display.
XML
<?xml version="1.0"?>
<myNS:Article xmlns:myNS="http://devedge.netscape.com/2002/de">
<myNS:Title>My Article</myNS:Title>
<myNS:Authors>
<myNS:Author company="Foopy Corp.">Mr. Foo</myNS:Author>
<myNS:Author>Mr. Bar</myNS:Author>
</myNS:Authors>
<myNS:Body>
The <b>rain</b> in <u>Spain</u> stays mainly in the plains.
</myNS:Body>
</myNS:Article>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myNS="http://devedge.netscape.com/2002/de">
<xsl:output method="html" />
<xsl:template match="/">
<html>
<head>
<title>
<xsl:value-of select="/myNS:Article/myNS:Title"/>
</title>
<style>
.myBox {margin:10px 155px 0 50px; border: 1px dotted #639ACE; padding:0 5px 0 5px;}
</style>
</head>
<body>
<p class="myBox">
<span class="title">
<xsl:value-of select="/myNS:Article/myNS:Title"/>
</span> <br />
Authors: <br />
<xsl:apply-templates select="/myNS:Article/myNS:Authors/myNS:Author"/>
</p>
<p class="myBox">
<xsl:apply-templates select="//myNS:Body"/>
</p>
</body>
</html>
</xsl:template>
<xsl:template match="myNS:Author">
-- <xsl:value-of select="." />
<xsl:if test="@company">
:: <b> <xsl:value-of select="@company" /> </b>
</xsl:if>
<br />
</xsl:template>
<xsl:template match="myNS:Body">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The example loads using synchronous XMLHTTPRequest
both the .xsl (xslStylesheet
) and the .xml (xmlDoc
) files into memory. The .xsl file is then imported (xsltProcessor.importStylesheet(xslStylesheet)
) and the transformation run (xsltProcessor.transformToFragment(xmlDoc, document)
). This allows fetching of data after the page has been loaded, without initiating a fresh page load.
JavaScript
let xslStylesheet;
const xsltProcessor = new XSLTProcessor();
let myDOM;
let xmlDoc;
function Init() {
let myXMLHTTPRequest = new XMLHttpRequest();
myXMLHTTPRequest.open("GET", "example1.xsl", false);
myXMLHTTPRequest.send(null);
xslStylesheet = myXMLHTTPRequest.responseXML;
xsltProcessor.importStylesheet(xslStylesheet);
myXMLHTTPRequest = new XMLHttpRequest();
myXMLHTTPRequest.open("GET", "example1.xml", false);
myXMLHTTPRequest.send(null);
xmlDoc = myXMLHTTPRequest.responseXML;
const fragment = xsltProcessor.transformToFragment(xmlDoc, document);
myDOM = fragment;
document.getElementById("example").textContent = "";
document.getElementById("example").appendChild(fragment);
}
This advanced example sorts several divs based on their content. The example allows sorting the content multiple times, alternating between ascending and descending order. The JavaScript loads the .xsl file only on the first sort and sets the xslloaded
variable to true once it has finished loading the file. Using the XSLTProcessor.getParameter()
method, the code can figure whether to sort in ascending or descending order. It defaults to ascending if the parameter is empty (the first time the sorting happens, as there is no value for it in the XSLT file). The sorting value is set using XSLTProcessor.setParameter()
.
The XSLT file has a parameter called myOrder
that JavaScript sets to change the sorting method. The xsl:sort
element's order attribute can access the value of the parameter using $myOrder
. However, the value needs to be an XPATH expression and not a string, so {$myOrder}
is used. Using {} evaluates the content as an XPath expression.
Once the transformation is complete, the result is appended to the document, as shown in this example.
XHTML
<div id="example">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
</div>
JavaScript
let xslRef;
let xslloaded = false;
const xsltProcessor = new XSLTProcessor();
let myDOM;
let xmlRef = document.implementation.createDocument("", "", null);
function sort() {
if (!xslloaded) {
const p = new XMLHttpRequest();
p.open("GET", "example2.xsl", false);
p.send(null);
xslRef = p.responseXML;
xsltProcessor.importStylesheet(xslRef);
xslloaded = true;
}
xmlRef = document.implementation.createDocument("", "", null);
const myNode = document.getElementById("example");
const clonedNode = xmlRef.importNode(myNode, true);
xmlRef.appendChild(clonedNode);
const sortVal = xsltProcessor.getParameter(null, "myOrder");
if (sortVal === "" || sortVal === "descending") {
xsltProcessor.setParameter(null, "myOrder", "ascending");
} else {
xsltProcessor.setParameter(null, "myOrder", "descending");
}
const fragment = xsltProcessor.transformToFragment(xmlRef, document);
document.getElementById("example").textContent = "";
myDOM = fragment;
document.getElementById("example").appendChild(fragment);
}
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" />
<xsl:param name="myOrder" />
<xsl:template match="/">
<xsl:apply-templates select="/div//div">
<xsl:sort select="." data-type="number" order="{$myOrder}" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="div">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>