Parameterized sorting in XSLT
XSLT is used frequently for presentation purposes, for example to turn a data payload into a browser-ready HTML page. A good presentation layer is culture-aware, and this is where things get interesting.
By default, the xsl:sort element will sort based on the system default. This may not be what you want; your front-end, middle-tier and back-end might have very different default settings, and you'll want to pick the right one.
Thankfully this is straightforward to accomplish with stylesheets. You can simply use a parameter to indicate which language you want to use for sorting, and then refer to that parameter in your xsl:sort elements.
You can save the following content to a .js file and try it out using cscript.exe. The bold bits show how console input makes its way to the transformed stylesheet.
I've included a "sample session" in the comments below. Note how in traditional Spanish, "choza" sorts aftoer "cosa", because the 'ch' as a pair sorts after 'c', but in modern Spanish (eg Argentina) and English, 'h' sorts before 'o' on its own.
function createDocumentFromText(xmlText) {
var result = new ActiveXObject("Msxml2.DOMDocument.6.0");
result.async = false;
result.loadXML(xmlText);
return result;
}
function createXslProcessorFromText(xmlText) {
var doc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.6.0");
doc.async = false;
doc.loadXML(xmlText);
var result = new ActiveXObject("Msxml2.XSLTemplate.6.0");
result.stylesheet = doc;
return result;
}
// Main.
WScript.Echo("Write the language code for the transform; empty to quit");
var doc = createDocumentFromText("<a><b>cosa</b><b>choza</b></a>");
var xsl = createXslProcessorFromText(
"<xsl:stylesheet version='1.0' xmlns:xsl='https://www.w3.org/1999/XSL/Transform'>" +
" <xsl:param name='sort' />" +
" <xsl:template match='/'>" +
" <a>" +
" <xsl:for-each select='a/b'> <xsl:sort select='text()' lang='{$sort}' /> " +
" <b><xsl:value-of select='text()' /></b>" +
" </xsl:for-each>" +
" </a>" +
" </xsl:template>" +
"</xsl:stylesheet>");
var done = false;
do {
var line = WScript.StdIn.ReadLine();
if (line.length == 0) {
done = true;
} else {
try {
var processor = xsl.createProcessor();
processor.input = doc;
processor.addParameter("sort", line, "");
processor.transform();
WScript.Echo(processor.output);
} catch (e) {
WScript.Echo(e.message);
}
WScript.Echo("");
}
} while (!done);
// Output:
// Write the language code for the transform; empty to quit
// en
// <?xml version="1.0"?><a><b>choza</b><b>cosa</b></a>
//
// es
// <?xml version="1.0"?><a><b>cosa</b><b>choza</b></a>
//
// es-ar
// <?xml version="1.0"?><a><b>choza</b><b>cosa</b></a>
Enjoy!