2010-11-01 54 views
2

我有以下XML网站地图文件:XSL递归轴故障?

<?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> 

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

+0

好问题,+1。查看我的答案,以获得最大限度地使用XSLT模板匹配并且在任何模板内都没有条件的解决方案。 :) – 2010-11-01 13:30:12

回答

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()版本(for-each select),那么你可以在你的XSLT的顶部添加<xsl:strip-space elements="*"/>,这样它会删除..

+0

该死的,非常感谢加比。奇迹般有效!我需要查看这些轴语句!干杯... – 2010-11-01 10:18:23

2

除了盖比的答案,你可能想知道使用call-template并传递一个参数,一个节点,只是将apply-templates应用到该节点(没有模板匹配)的一种迂回方式。 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确实更方便!

+1

+1对于XSLT答案:应用模板和模式匹配。 – 2010-11-01 12:29:31

1

继@LarsH和@Gaby的好回答之后,让我展示一下解决这个问题的首选方法。

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

而不是这些条件,尽量尽量使用match属性<xsl:template>中的模式匹配。

我的解决办法是

<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> 

当这种转变被应用到所提供的XML文档

<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> 

请注意<xsl:if>如何“神奇地”消失。