2011-04-05 45 views
2

基于某些条件,使用XSLT列出或计算从当前节点到每个叶节点 的路径。例如对于例如 在具体情况下, 这里假设当前节点是“t” 以及从当前节点到没有 “trg”属性的每个叶节点的路径。 在下面例如从当前节点到具有某个属性的每个叶节点的列表或计数路径

<root> 
    <t> 
    <a1> 
    <b1 trg="rr"> 
     <c1></c1> 
    </b1> 
    <b2> 
     <c2></c2> 
    </b2> 
    </a1> 
    <a2> 
     <b3> 
     <c3></c3> 
     </b3> 
    </a2> 
    </t> 
</root> 

这里只与这个属性路径 吨/ A1/B2/C2吨/ A2/B3/C3

但不吨/ A1/B1/C1

回答

2

最简单的方法是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="text()"/> 
    <xsl:template match="text()" mode="search"/> 
    <xsl:template match="t"> 
     <xsl:apply-templates mode="search"> 
      <xsl:with-param name="pPath" select="name()"/> 
     </xsl:apply-templates> 
    </xsl:template> 
    <xsl:template match="*" mode="search"> 
     <xsl:param name="pPath"/> 
     <xsl:apply-templates mode="search"> 
      <xsl:with-param name="pPath" select="concat($pPath,'/',name())"/> 
     </xsl:apply-templates> 
    </xsl:template> 
    <xsl:template match="*[not(*)]" mode="search"> 
     <xsl:param name="pPath"/> 
     <xsl:value-of select="concat($pPath,'/',name(),'&#xA;')"/> 
    </xsl:template> 
    <xsl:template match="*[@trg]" mode="search" priority="1"/> 
</xsl:stylesheet> 

输出:

t/a1/b2/c2 
t/a2/b3/c3 

注意:完成拉风。开始路径搜索的规则(t patttern)。隧道参数规则(*模式)。输出叶子路径的规则(*[not(*)]模式)。递归中断条件的一个规则(*[@trg]模式)。

0

我可以想出一种方法来实现这一点,但它不好看,所以希望有人会想出更好的方式...

首先,我定义的变量与当前节点的电平

<xsl:variable name="level"> 
    <xsl:value-of select="count(ancestor::*)"/> 
</xsl:variable> 

接着,匹配碰巧是叶节点,并且不具有任何祖先(包括本身所有后代或当前节点,但只有当前级别),具有指定的属性@trg ='rr'。

<xsl:apply-templates select=".//*[not(node())][not(ancestor-or-self::*[count(ancestor::*) &gt; $level][@trg='rr'])]"> 
    <xsl:with-param name="currentLevel" select="$level"/> 
</xsl:apply-templates> 

匹配叶节点后,您应该能够获得父节点的路径备份到当前节点。

下面是完整的样式表

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

    <xsl:template match="/"> 
     <xsl:apply-templates select="root/t"/> 
    </xsl:template> 

    <xsl:template match="t"> 

     <!-- The level of the current node --> 
     <xsl:variable name="level"> 
     <xsl:value-of select="count(ancestor::*)"/> 
     </xsl:variable> 

     <paths> 
     <!-- Match all leaf nodes where there is not an ancestor (up to the current node) with the attribute @trg = 'rr' --> 
     <xsl:apply-templates select=".//*[not(node())][not(ancestor-or-self::*[count(ancestor::*) &gt; $level][@trg=&apos;rr&apos;])]"> 
      <xsl:with-param name="currentLevel" select="$level"/> 
     </xsl:apply-templates> 
     </paths> 
    </xsl:template> 

    <!-- For leaf nodes, write out the ancestor path to a specified level --> 
    <xsl:template match="*[not(node())]"> 
     <xsl:param name="currentLevel"/> 
     <path> 
     <xsl:for-each select="ancestor::*[count(ancestor::*) &gt;= $currentLevel]"> 
      <xsl:value-of select="name()"/> 
      <xsl:text>/</xsl:text> 
     </xsl:for-each> 
     <xsl:value-of select="name()"/> 
     </path> 
    </xsl:template> 

</xsl:stylesheet> 

当给定的XML应用,下面的结果返回

<paths> 
    <path>t/a1/b2/c2</path> 
    <path>t/a2/b3/c3</path> 
</paths> 
0

这个问题最好用XSLT解决2.0/XPath 2.0中

非常初始的XSLT 1.0尝试

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

<xsl:template match="*[not(*)]"> 
    <xsl:call-template name="buildPath"> 
    <xsl:with-param name="pstartNode" select="/*/t"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template match="text()"/> 

<xsl:template name="buildPath"> 
    <xsl:param name="pstartNode" select="."/> 
    <xsl:param name="pendNode" select="."/> 

    <xsl:choose> 
    <xsl:when test= 
    "not(count($pstartNode | $pendNode/ancestor-or-self::node()) 
     = 
     count($pendNode/ancestor-or-self::node()) 
     ) 
    "> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:variable name="vPath" select= 
     "ancestor::* 
      [count(.|$pstartNode/descendant-or-self::*) 
      = 
      count($pstartNode/descendant-or-self::*) 
      ] 
     "/> 
    <xsl:if test="not($vPath[@trg])"> 
     <xsl:for-each select= 
     "ancestor::* 
      [count(.|$pstartNode/descendant-or-self::*) 
      = 
      count($pstartNode/descendant-or-self::*) 
      ]"> 
     <xsl:value-of select="concat(name(),'/')"/> 
     </xsl:for-each> 
     <xsl:value-of select="concat(name(), '&#xA;')"/> 
    </xsl:if> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

当所提供的XML文档施加:

<root> 
    <t> 
     <a1> 
      <b1 trg="rr"> 
       <c1></c1> 
      </b1> 
      <b2> 
       <c2></c2> 
      </b2> 
     </a1> 
     <a2> 
      <b3> 
       <c3></c3> 
      </b3> 
     </a2> 
    </t> 
</root> 

产生想要的,正确的结果

t/a1/b2/c2 
t/a2/b3/c3 
0

这里是样式表:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <paths> 
      <xsl:apply-templates select="root/t"> 
       <xsl:with-param name="path"/> 
      </xsl:apply-templates> 
     </paths> 
    </xsl:template> 

    <xsl:template name="path"> 
     <xsl:param name="path"/> 
     <xsl:choose> 
      <xsl:when test="string-length($path)"> 
       <xsl:value-of select="$path"/>/<xsl:value-of select="name()"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="name()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template match="*"> 
     <xsl:param name="path"/> 
     <xsl:if test="not(@trg)"> 
      <xsl:if test="not(count(*))"> 
       <path> 
        <xsl:call-template name="path"> 
         <xsl:with-param name="path"> 
          <xsl:value-of select="$path"/> 
         </xsl:with-param> 
        </xsl:call-template> 
       </path> 
      </xsl:if> 
      <xsl:apply-templates select="*"> 
       <xsl:with-param name="path"> 
        <xsl:call-template name="path"> 
         <xsl:with-param name="path"> 
          <xsl:value-of select="$path"/> 
         </xsl:with-param> 
        </xsl:call-template> 
       </xsl:with-param> 
      </xsl:apply-templates> 
     </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

的想法是非常简单 - 主处理模板(math="*")是适用于每个节点的递归函数。它有一个参数 - path,它是从搜索根节点(t)到此节点的实际路径。一旦节点没有孩子 - 它可以输出。

另一个名为path的模板是一个简单的辅助函数,用于正确生成路径。如果您可以在您的XSLT处理器中注册XPath函数,我宁愿这样做,并摆脱详细的call-template结构。整个call-template ...电话可能是简单的<xsl:value-of select="myfn:path($path)"/>这会大大增加可读性,这就是对XSLT非常重要;)

反正我觉得有太多路径话在我的解释:),所以不要”毫不犹豫地问,如果有什么不明确的。

相关问题