XSL : Form XPath expression dynamically

2013-05-17
Laurent Bientz

We saw in a previous article how to form the name of an XML node dynamically, we will see in this post how to form XPath expression dynamically.

To illustrate the explanation we will base ourselves on an XML stream N levels materializing a folder tree type TreeView:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <View>
        <dirs>
            <dir>
                <name>var</name>
                <dirs>
                    <dir>
                        <name>lib</name>
                        <dirs>
                            <dir>
                                <name>apt</name>
                                <!-- ... -->
                            </dir>
                        </dirs>
                    </dir>
                    <div>
                        <name>log</name>
                        <dirs>
                            <dir>
                                <name>apache2</name>
                                <!-- ... -->
                            </dir>
                        </dirs>
                    </div>
                </dirs>
            </dir>
            <dir>
                <name>home</name>
                <!-- ... -->
            </dir>
        </dirs>
    </View>
</root>

In XSL, one would like to for-eacher as PHP readdir with a while, this is unfortunately not possible natively. We can not form a dynamically XPath because it is not a string. However a new XMLNS compensates this lack:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" xmlns="http://www.w3.org/1999/xhtml" xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">

Thereafter, we can form XPath expression dynamically using the prefix dyn:evaluate.

We can imagine a select coupled with a recursive template to effect treatment:

<select name="directory_id" id="directory_id" size="2">
    <option value="0" selected="selected">Répertoire</option>
    <xsl:call-template name="RecursiveDirsSelect">
        <xsl:with-param name="path">dirs/dir</xsl:with-param>
    </xsl:call-template>
</select>
<xsl:template name="RecursiveDirsSelect">
    <xsl:param name="path" />                
    <xsl:for-each select="dyn:evaluate(concat('//View/', $path))">
        <xsl:variable name="position" select="position()" />
        <option><xsl:value-of select="name" /></option>
        <xsl:if test="count(dirs/dir) > 0">
            <xsl:call-template name="RecursiveDirsSelect">
                <xsl:with-param name="path"><xsl:value-of select="concat($path,'[',$position,']/dirs/dir')" /></xsl:with-param>                    
            </xsl:call-template>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

 

Drake - 2013-10-09 08:52:50
Is there any chance that XProc will be surptpoed? I think it's great that we can now get rid of the DOM boilerplate code, but there is still the code to prepare, execute and examine results of an XSLT or XPath or XQuery.This still leaves the door open for imperative pollution in XML applications.I have been a user of Apache Cocoon for a long time, and its pipelines do away completely with all the Java boilerplate, making XML applications completely declarative. XProc is supposed to do the same thing.

Comment

USER EXPERIENCE

Wandi invites you to discover a new approach to navigating a website...
Are you ready?

Launch the experience