2010-03-27 7 views
1

Comment appliquer un paramètre à un attribut select et order dans un élément xsl:sort? I'ld comme faire cette dynamique avec PHP avec quelque chose comme ceci:XSLT: utiliser les paramètres dans xls: attributs de tri (tri dynamique)

$xsl = new XSLTProcessor(); 
$xslDoc = new DOMDocument(); 
$xslDoc->load($this->_xslFilePath); 
$xsl->importStyleSheet($xslDoc); 
$xsl->setParameter('', 'sortBy', 'viewCount'); 
$xsl->setParameter('', 'order', 'descending'); 

Mais I'ld d'abord maintenant comment obtenir ce travail. J'ai essayé ce qui suit, mais cela me donne une 'erreur de compilation': 'valeur invalide $ order for order'. $sortBy ne semble pas faire quoi que ce soit soit:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes"/> 
<xsl:param name="sortBy" select="viewCount"/> 
<xsl:param name="order" select="descending"/> 
<xsl:template match="/"> 
    <media> 
    <xsl:for-each select="media/medium"> 
    <xsl:sort select="$sortBy" order="$order"/> 
     // <someoutput> 
    </xsl:for-each> 
    </media> 
</xsl:template> 
</xsl:stylesheet> 

Répondre

9

Vous êtes proche de la solution correcte, mais il y a quelques problèmes:

  1. <xsl:param name="sortBy" select="viewCount"/> Cela définit le paramètre $sortBy comme valeur de l'viewCount enfant du nœud actuel (le nœud de document). Parce que l'élément supérieur n'est pas nommé viewCount, le paramètre $sortBy ainsi défini n'a aucune valeur.

  2. <xsl:param name="order" select="descending"/> Ditto.

  3. <xsl:sort select="$sortBy" order="$order"/> Même si les problèmes 1. et 2. ci-dessus sont corrigés, cette instruction xslt est toujours problématique. Elle spécifie la valeur de l'attribut order en tant que chaîne littérale '$order' - et non en tant que valeur du paramètre $order. La façon de faire cela dans XSLT est en utilisant AVT (Template Value Value). Chaque fois que nous voulons que a spécifie que dans une valeur d'attribut, nous voulons qu'une chaîne particulière soit évaluée comme une expression XPath, cette chaîne doit être entourée d'accolades.

Ainsi, l'attribut order doit être spécifié comme: order = '{$order}'.

Malheureusement, les AVT ne peuvent pas être utilisés pour l'attribut select (une autre règle de la spécification XSLT).

La façon de spécifier la valeur de l'attribut select est un peu peu plus compliqué:

select='*[name()=$sortBy]' Ce dit: trier par l'élément enfant, dont le nom est le même que la valeur de la $sortBy variable.

Pour mettre tout cela ensemble, voici la transformation corrigée:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:strip-space elements="*"/> 

<xsl:param name="sortBy" select="'viewCount'"/> 
<xsl:param name="order" select="'descending'"/> 

<xsl:template match="/"> 
    <media> 
     <xsl:for-each select="media/medium"> 
     <xsl:sort select="*[name()=$sortBy]" order="{$order}"/> 

     <xsl:copy-of select="."/> 
     </xsl:for-each> 
    </media> 
</xsl:template> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML suivant:

<media> 
<medium> 
    <viewCount>2</viewCount> 
</medium> 
<medium> 
    <viewCount>1</viewCount> 
</medium> 
<medium> 
    <viewCount>5</viewCount> 
</medium> 
</media> 

Le résultat correct est produit:

<media> 
    <medium> 
     <viewCount>5</viewCount> 
    </medium> 
    <medium> 
     <viewCount>2</viewCount> 
    </medium> 
    <medium> 
     <viewCount>1</viewCount> 
    </medium> 
</media> 
+0

+1 Merci beaucoup pour l'explication détaillée. C'est génial. Cela fonctionne parfaitement! Et maintenant c'est logique. Je me suis cogné la tête contre le mur ces dernières heures. Je vous remercie. –

+0

Dimitre- Ceci est une excellente réponse m'a sauvé beaucoup de temps. J'ai une question puis-je passer une chaîne à ma variable locale a une expression xpath alors de sorte que cette variable locale sera utilisée pour for-each select = $ myLocalVar pour faire une boucle. .setParameters (null, filter, "*/person [contient (nom, 'John')] – tosi