2009-09-30 9 views
3

je le bloc de code suivant qui obtient le nom des noeuds dans l'arbre, comme ceci:Obtention du noeud courant XSLT, formaté en tant que requête XPath?

section/page/subPage

Mais je voudrais être en mesure d'obtenir à ce qui suit (juste rendre up):

section[@id='someId']/page/subPage[@user='UserA']/@title

Je trouve le code suivant d'un de ces postes stackoverflow:


<xsl:attribute name="path"> <xsl:for-each select="ancestor-or-self::*"> <xsl:if test="name() != 'root'"> <xsl:value-of select="name()"> <xsl:if test="not(position()=last())"> <xsl:text>/</xsl:text> </xsl:if> </xsl:value-of> </xsl:if> </xsl:for-each> </xsl:attribute> 

Ce qui me donne le chemin droit, mais je voudrais lancer plus de logique pour le rendre ainsi il a inclus le @id (ou l'attribut pertinent), et peut-être plus de choses que je ne peux pas penser en ce moment .

Quelle est la meilleure façon de faire cela?

J'ai vérifié dans les fonctions EXSLT, ce qui peut fonctionner, mais peut-être que vous avez déjà résolu ce problème d'une meilleure façon.

Des idées? J'utilise le nokogiri de ruby ​​pour analyser xml/xslt si cela peut aider.

Merci beaucoup, Lance

Répondre

4

Cette solution fait ce que vous voulez:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" /> 

    <xsl:template match="/"> 
    <root> 
     <xsl:attribute name="path"> 
     <xsl:apply-templates select="(//@title)[1]" mode="make-path" /> 
     </xsl:attribute> 
    </root> 
    </xsl:template> 

    <xsl:template match="*|@*" mode="make-path"> 
    <xsl:apply-templates select="parent::*" mode="make-path" /> 
    <xsl:text>/</xsl:text> 
    <xsl:apply-templates select="." mode="make-name" /> 
    <xsl:choose> 
     <xsl:when test="self::section"> 
     <xsl:apply-templates select="@id" mode="make-predicate" /> 
     </xsl:when> 
     <xsl:when test="self::subPage"> 
     <xsl:apply-templates select="@user" mode="make-predicate" /> 
     </xsl:when> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="*|@*" mode="make-predicate"> 
    <xsl:text>[</xsl:text> 
    <xsl:apply-templates select="." mode="make-name" /> 
    <xsl:text> = '</xsl:text> 
    <xsl:value-of select="." /> 
    <xsl:text>']</xsl:text> 
    </xsl:template> 

    <xsl:template match="*" mode="make-name"> 
    <xsl:value-of select="name()" /> 
    </xsl:template> 

    <xsl:template match="@*" mode="make-name"> 
    <xsl:text>@</xsl:text> 
    <xsl:value-of select="name()" /> 
    </xsl:template> 

</xsl:stylesheet> 

Appliqué à

<section id="someId"> 
    <page> 
    <subPage user="UserA" title="test" /> 
    <subPage user="UserB" title="blah" /> 
    </page> 
    <page> 
    <subPage user="UserC" title="fooh" /> 
    </page> 
</section> 

vous obtenez:

<root path="/section[@id = 'someId']/page/subPage[@user = 'UserA']/@title" /> 

Le <xsl:choose> est l'endroit configurable (ajouter autant <xsl:when> s que vous le souhaitez):

<!-- test for element name --> 
<xsl:when test="self::section"> 
    <!-- make predicates out of selected attributes --> 
    <xsl:apply-templates select="@id" mode="make-predicate" /> 
</xsl:when> 

également possible :

<xsl:when test="self::section"> 
    <xsl:apply-templates select="@name|@category|subElement" mode="make-predicate" /> 
</xsl:when> 

qui conduirait à

<root path="/section[@name = 'someName'][@category = 'somecat'][subElement = 'xyz']/..." /> 

Le seul problème que je vois est avec des valeurs sous-jacentes qui contiennent des guillemets simples. Ils casseraient le XPath.

+0

Belle utilisation du mode –

+0

Hardcore man, merci pour cela. –

1

Pour chaque nœud ancêtre, vous pouvez boucler sur tous les attributs avec xsl simple: for-each

<xsl:for-each select="@*"> 

Vous pouvez ensuite utiliser les attributs pour construire la chaîne de XPath

<xsl:for-each select="ancestor-or-self::*"> 
    <xsl:if test="name() != 'root'"> 
     <xsl:value-of select="name()"/> 
     <xsl:if test="@*"> 
     <xsl:text>[</xsl:text> 
     <xsl:for-each select="@*"> 
      <xsl:text>@</xsl:text> 
      <xsl:value-of select="name()"/> 
      <xsl:text>='</xsl:text> 
      <xsl:value-of select="."/> 
      <xsl:text>'</xsl:text> 
      <xsl:if test="not(position()=last())"> 
       <xsl:text> and </xsl:text> 
      </xsl:if> 
     </xsl:for-each> 
     <xsl:text>]</xsl:text> 
     </xsl:if> 
     <xsl:if test="not(position()=last())"> 
     <xsl:text>/</xsl:text> 
     </xsl:if> 
    </xsl:if> 
</xsl:for-each> 
Questions connexes