XSL递归轴故障?

时间:2010-11-01 09:22:48

标签: xml xslt

我有以下xml站点地图文件:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="NewSiteMap.xsl"?>
<siteMap>
  <siteMapNode
    url="~/UsingMasterTemplate.aspx?id=1"
    title="Home"
    description="AAAAAAAAAAAAAAAAAAA">
    <siteMapNode
      url="~/UsingMasterTemplate.aspx?id=2"
      title="Profile"
      description="BBBBBBBBBBBBBBBBBB" />
    <siteMapNode
      url="~/UsingMasterTemplate.aspx?id=3"
      title="People"
      description="CCCCCCCCCCCCCCCCCCCCCCCC" />
    <siteMapNode
      url="~/UsingMasterTemplate.aspx?id=5"
      title="New Page"
      description="DDDDDDDDDDDDDDDDDDDD" />
  </siteMapNode>
</siteMap>

以下xsl文件做递归并输出到ul:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' version='1.0' omit-xml-declaration="yes" encoding='UTF-8' indent='yes'/>

<xsl:template match="siteMap">
<!--  
<xsl:variable name='siteMapNode'>
 <xsl:value-of select='siteMap/siteMapNode'/>
</xsl:variable> 
-->
<html>
  <head>
     <link rel="stylesheet" href="xSiteMap.css" type="text/css" />  
  </head>

  <body>
       <h2>SiteMap:</h2>
   <ul>
    <!-- Check for empty sitemap -->
    <xsl:if test='siteMapNode'>
     <xsl:call-template name='BuildNavList'>
      <xsl:with-param name='siteMapNode' select='siteMapNode'/>
     </xsl:call-template>
    </xsl:if>     
      </ul>
  </body>

</html> 

</xsl:template> 

<xsl:template name='BuildNavList'>
 <xsl:param name='siteMapNode'/>
 <li> 
  <a>
   <xsl:attribute name="href">
    <xsl:value-of select="$siteMapNode/@url"/>
   </xsl:attribute>
   <xsl:attribute name="title">
    <xsl:value-of select="$siteMapNode/@description"/>       
   </xsl:attribute>
   <xsl:value-of select="$siteMapNode/@title"/>
  </a> 
    <!-- test for node-children, if true then recursion -->
  <xsl:if test='$siteMapNode/node()'>
   <ul>
    <xsl:for-each select="$siteMapNode/node()">
       <xsl:call-template name='BuildNavList'>
      <xsl:with-param name='siteMapNode' select='$siteMapNode/node()'/>
     </xsl:call-template>
    </xsl:for-each>  
   </ul>
  </xsl:if> 
 </li> 
</xsl:template>

</xsl:stylesheet>

但是我的递归调用似乎有一个错误(可能是我的for-each语句中的轴错误)!这里出了什么问题?

3 个答案:

答案 0 :(得分:2)

除了Gaby的回答之外,你可能想知道使用call-template并传递一个参数,一个节点,只是一种迂回的方式来说明应用模板到该节点(没有模板匹配)。 Apply-templates是正常做事的XSLT方式,而且不那么详细。

所以你的初始调用模板

<xsl:if test='siteMapNode'>
 <xsl:call-template name='BuildNavList'>
  <xsl:with-param name='siteMapNode' select='siteMapNode'/>
 </xsl:call-template>
</xsl:if>   

可以成为

 <xsl:apply-templates select='siteMapNode'/>

将应用于名为siteMapNode的上下文节点的子节点。

然后您的递归模板变为

<xsl:template match="siteMapNode">
 <li> 
  <a href="{@url}" title="{@description}">
   <xsl:value-of select="@title"/>
  </a> 
    <!-- test for siteMapNode element children, if true then recur -->
  <xsl:if test='siteMapNode'>
   <ul>
     <xsl:apply-templates select="siteMapNode" />
   </ul>
  </xsl:if> 
 </li> 
</xsl:template>

请注意,我们删除了对$ siteMapNode参数的大量引用,因为它现在是上下文节点。另请注意用于<a href=""title="">的属性值模板。更加简洁和可读!

当您按照设计的方式理解和使用XSLT时,XSLT会更方便!

答案 1 :(得分:1)

BuildNavList模板中,将内部模板调用更改为

<xsl:for-each select="$siteMapNode/siteMapNode">
   <xsl:call-template name='BuildNavList'>
  <xsl:with-param name='siteMapNode' select='.'/>
 </xsl:call-template>
</xsl:for-each>

重要的是使用.中的xsl:with-param,因为您已经在节点的循环内...

秒问题是for-each select。在这种情况下,我使用/siteMapNode来忽略元素之间的空格,因为node()替代方案将空白作为文本节点考虑在内并且搞砸了。

如果您必须使用nodes()版本({{1>} 上的),那么您可以在xslt的顶部添加for-each select,这样它就会删除它们..

答案 2 :(得分:1)

按照@LarsH和@Gaby的好答案,让我展示一下解决这个问题的首选方法。

在XSLT中,任何条件(<xsl:if><xsl:when>)都表示尚未使用XSLT模式匹配的全部功能。

尝试在match的{​​{1}}属性中使用尽可能多的模式匹配,而不是此类条件。

我的解决方案是

<xsl:template>

将此转换应用于提供的XML文档

<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:template match="/*">
    <html>
      <head>
         <link rel="stylesheet" href="xSiteMap.css" type="text/css" />
      </head>

      <body>
        <h2>SiteMap:</h2>
          <xsl:apply-templates select="siteMapNode"/>
      </body>
  </html>
 </xsl:template>

 <xsl:template match="siteMapNode[1]">
  <ul>
   <xsl:call-template name="buildNav"/>
   <xsl:apply-templates select="following-sibling::siteMapNode"
        mode="inList"/>
  </ul>
 </xsl:template>

 <xsl:template match="siteMapNode" name="buildNav">
  <li>
    <a href="{@url}" title="{@description}">
      <xsl:value-of select="@title"/>
    </a>
    <xsl:apply-templates select="siteMapNode"/>
  </li>
 </xsl:template>

 <xsl:template match="siteMapNode" mode="inList">
  <xsl:call-template name="buildNav"/>
 </xsl:template>
 <xsl:template match="siteMapNode[position() > 1]"/>
</xsl:stylesheet>

产生了想要的正确答案

<siteMap>
    <siteMapNode
    url="~/UsingMasterTemplate.aspx?id=1"
    title="Home"
    description="AAAAAAAAAAAAAAAAAAA">

        <siteMapNode
         url="~/UsingMasterTemplate.aspx?id=2"
         title="Profile"
         description="BBBBBBBBBBBBBBBBBB" />

        <siteMapNode
      url="~/UsingMasterTemplate.aspx?id=3"
      title="People"
      description="CCCCCCCCCCCCCCCCCCCCCCCC" />

        <siteMapNode
      url="~/UsingMasterTemplate.aspx?id=5"
      title="New Page"
      description="DDDDDDDDDDDDDDDDDDDD" /></siteMapNode>
</siteMap>

请注意<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="xSiteMap.css" type="text/css"> </head> <body> <h2>SiteMap:</h2> <ul> <li><a href="~/UsingMasterTemplate.aspx?id=1" title="AAAAAAAAAAAAAAAAAAA">Home</a><ul> <li><a href="~/UsingMasterTemplate.aspx?id=2" title="BBBBBBBBBBBBBBBBBB">Profile</a></li> <li><a href="~/UsingMasterTemplate.aspx?id=3" title="CCCCCCCCCCCCCCCCCCCCCCCC">People</a></li> <li><a href="~/UsingMasterTemplate.aspx?id=5" title="DDDDDDDDDDDDDDDDDDDD">New Page</a></li> </ul> </li> </ul> </body> </html> s如何“神奇地”消失。