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:
    • 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
    So, let's proceed directly to the installation and use in order to show everything with live examples. To get started, you can get acquainted with the main features of my crafts on this page: Description (English) .

    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
    To use the extension, you will need to add the following namespace definition to the root element of the XSLT document:
    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


    Also popular now: