Nous avons vu dans un article précédent comment former le nom d'un noeud XML dynamiquement, nous allons voir dans ce billet comment former une expression xPATH dynamiquement.
Pour illustrer l'explication, nous allons nous baser sur un flux XML à N niveaux matérialisant une arborescence de dossiers de 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>
En XSL, on aimerait pouvoir for-eacher comme en PHP avec un while readdir, ce n'est hélas nativement pas possible. On ne peut pas former un xPATH dynamiquement car ce n'est pas une string. Cependant un nouveau XMLNS permet de compenser ce manque :
<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">
Par la suite, nous pouvons former une expression xPATH dynamiquement à l'aide du prefixe dyn:evaluate.
Nous pouvons donc imaginer un select couplé à l'aide d'un template récursif pour réaliser le traitement :
<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>