
Add Javascript in XSLT
Hello dear habrazhitel!
I would like to introduce you to my small project, which I think can be useful to many of you. XSR is a Saxon processor XSLT extension that allows you to use JavaScript directly in your XSLT code. So what we have:
Then add
There are two ways to define and use xsr: script.
Firstly, you can use the href attribute to connect (and immediately execute) an external JavaScript file. Here it is: This code will connect the external test.js file (which should be located relative to the location of the document) to your xsl - document and execute it. Secondly, you can write your JavaScript code directly in an XSLT document, in this simple way:
In some cases, you may need to pass parameters declared externally to your JavaScript code. For these purposes, you can use the special instruction: xsr: with-param. Example: Attention! At the moment, everything that was transferred to the script in the described way will be automatically converted to a string, so transferring fragments of an XML document in this way will not work.
You can mix JavaScript and XSLT by creating a situation where your JavaScript code is generated on the fly this way:
Use the following example to generate the resulting XML document using JavaScript: Generated XML document:
You can use any Java classes in your JavaScript code as follows: You can also use classes that are not a standard part of Java. The following example shows how you can use SQLiteJDBC (http://www.zentus.com/sqlitejdbc/) to connect and work with the SQLite database:
You may wonder why all this is necessary? The answer is very simple, XSLT, together with XML, is a very powerful bunch that can perform very many tasks, adding JavaScript and the ability to easily run it from the command line using Apache Ant, we get a powerful automation tool with an already built-in mechanism for generating the final result . Considering the fact that tons of code are written for JavaScript that perform various application tasks, this project (at least to me) no longer seems so crazy.
A more realistic example: we need to write something so that we can tear external resources over the HTTP protocol, do something with this text - and then drop the XML report into the database or to another server.
This is my first topic on Habré; therefore, any constructive criticism is welcome. I would also like to know from the community if this topic is of interest to you and should I publish something similar in the near future?
I would like to introduce you to my small project, which I think can be useful to many of you. XSR is a Saxon processor XSLT extension that allows you to use JavaScript directly in your XSLT code. So what we have:
- Saxon XSLT processor is a reasonable choice for those who want to use modern XSLT 2, and as far as I know, the most complete implementation is only in Saxon'e.
- Mozilla Rhino JavaScript engine is essentially a virtual JavaScript machine written in Java.
- Apache ant build tool is mainly used to automate routine operations (for example, deploying an application on a remote server, after automatically compressing all the files ...
- The desire to put it all together and get working JavaScript in XSLT runtime
Briefly about installation and configuration
- If you do not have ANT installed, then do this by reading the description for example here
- Take the trunk out of here . There you will find a project under NetBeans, sources, binaries and tests. Immediately make a reservation, I'm not a Java programmer, and therefore my code from the side of those of you who are professional in this field may seem hmm ... funny?
- We go to the test folder and verify that the paths in the build.xml file are correct
- We go to the console in the same folder test, write ant and watch how the examples from the file test.xsl / test.js are executed
xmlns:xsr="java:/xsr.XSRElementFactory"
Then add
extension-element-prefixes="xsr"
the same - i.e. to the attribute list of the root element. This instruction will tell Saxon that the xsr prefix defines an external extension. In other words, after the above manipulations, the root element will look something like this:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
* This source code was highlighted with Source Code Highlighter.
Using the xsr: script statement
There are two ways to define and use xsr: script.
Firstly, you can use the href attribute to connect (and immediately execute) an external JavaScript file. Here it is: This code will connect the external test.js file (which should be located relative to the location of the document) to your xsl - document and execute it. Secondly, you can write your JavaScript code directly in an XSLT document, in this simple way:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
* This source code was highlighted with Source Code Highlighter.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
message('The Obligatory Hello World Example:');
message('HELLO WORLD!');
]]>
* This source code was highlighted with Source Code Highlighter.
Passing parameters to a script using xsr: with-param
In some cases, you may need to pass parameters declared externally to your JavaScript code. For these purposes, you can use the special instruction: xsr: with-param. Example: Attention! At the moment, everything that was transferred to the script in the described way will be automatically converted to a string, so transferring fragments of an XML document in this way will not work.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
message('foo is:', getParam('foo'));
message('bar is:', getParam('bar'));
]]>
* This source code was highlighted with Source Code Highlighter.
Using xsr: body with XSL elements
You can mix JavaScript and XSLT by creating a situation where your JavaScript code is generated on the fly this way:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
message('\r');
message('Script generate itself:');
message('position() = ' + );
* This source code was highlighted with Source Code Highlighter.
Using JavaScript to generate the resulting XML document
Use the following example to generate the resulting XML document using JavaScript: Generated XML document:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
message();
startElement('test');
for (var c = 0; c < 10; c++) {
startElement('item_' + c);
characters('value_' + c);
endElement();
}
endElement();
]]>
* This source code was highlighted with Source Code Highlighter.
value_0
value_1
value_2
value_3
value_4
value_5
value_6
value_7
value_8
value_9
* This source code was highlighted with Source Code Highlighter.
Using Java classes in JavaScript code
You can use any Java classes in your JavaScript code as follows: You can also use classes that are not a standard part of Java. The following example shows how you can use SQLiteJDBC (http://www.zentus.com/sqlitejdbc/) to connect and work with the SQLite database:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
function buildDirectoryTree(sRootDirectory, sTrimDirectory) {
var aResultTree = [];
var aFiles = (new Packages.java.io.File(sRootDirectory)).listFiles();
for (var iFile = 0; iFile < aFiles.length; iFile++) {
var sFileName = String(aFiles[iFile]);
var bIsDirectory = aFiles[iFile].isDirectory();
if (!bIsDirectory) {
aResultTree.push(sFileName.substr((
sTrimDirectory ?
sTrimDirectory :
sRootDirectory
).length));
} else {
aResultTree = aResultTree.concat(
buildDirectoryTree(
sFileName,
sRootDirectory
)
);
}
}
return aResultTree;
}
// Build directory tree
var aDirectoryTree = buildDirectoryTree('.');
for (var c = 0; c < aDirectoryTree.length; c++) {
message('Found directory:', aDirectoryTree[c]);
}
]]>
* This source code was highlighted with Source Code Highlighter.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsr="java:/xsr.XSRElementFactory"
extension-element-prefixes="xsr">
function SQLite() {
Packages.java.lang.Class.forName('org.sqlite.JDBC');
this.connection = null;
this.connect = function(sDBFileName) {
this.connection = new Packages.java.sql.DriverManager.getConnection(
'jdbc:sqlite:' + sDBFileName
);
this.statement = this.connection.createStatement();
};
this.close = function() {
if (!this.connection) return;
this.connection.close();
this.statement.close();
this.connection = null;
this.statement = null;
};
this.query = function(sQuery) {
if (!this.statement) return;
var aResultSet = [];
try {
var oResultSet = this.statement.executeQuery(sQuery);
} catch (e) {}
if (oResultSet) {
while (oResultSet.next()) {
var aRowData = {};
for (var c = 1; c <= oResultSet.columnCount; c++) {
var sColumnName = oResultSet.getColumnName(c);
aRowData[sColumnName] = oResultSet.getString(
sColumnName
);
}
aResultSet.push(aRowData);
}
oResultSet.close();
}
return aResultSet;
};
};
]]>
message('SQLite example:\r\n');
var oSQLite = new SQLite();
oSQLite.connect('test.db');
oSQLite.query('\
CREATE TABLE if not exists test_table (\
id INTEGER PRIMARY KEY AUTOINCREMENT,\
name TEXT\
);\
');
for (var c = 0; c < 100; c++) {
oSQLite.query('INSERT INTO test_table (name) VALUES ("item_'+c+'")');
}
var aResult = oSQLite.query('SELECT * FROM test_table;');
for (var c = 0; c < aResult.length; c++) {
startElement('row');
for (var sCellName in aResult[c]) {
startElement(sCellName);
characters(aResult[c][sCellName]);
endElement();
}
endElement();
}
oSQLite.query('DROP TABLE test_table');
oSQLite.close();
]]>
* This source code was highlighted with Source Code Highlighter.
Conclusion
You may wonder why all this is necessary? The answer is very simple, XSLT, together with XML, is a very powerful bunch that can perform very many tasks, adding JavaScript and the ability to easily run it from the command line using Apache Ant, we get a powerful automation tool with an already built-in mechanism for generating the final result . Considering the fact that tons of code are written for JavaScript that perform various application tasks, this project (at least to me) no longer seems so crazy.
A more realistic example: we need to write something so that we can tear external resources over the HTTP protocol, do something with this text - and then drop the XML report into the database or to another server.
This is my first topic on Habré; therefore, any constructive criticism is welcome. I would also like to know from the community if this topic is of interest to you and should I publish something similar in the near future?
References
- Project Homepage: http://code.google.com/p/xsr/
- Read about the Mozilla Rhino JS Engine here: http://www.mozilla.org/rhino/
- XSLT2 documentation can be found here: http://www.saxonica.com/documentation/index.html and here: http://www.zvon.org/xxl/XSL-Ref/Tutorials/index.html
- Saxon - documentation related to the mechanism of extensions work is available here: http://www.saxonica.com/documentation/extensibility/intro.html