2010-11-01 68 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>如何「神奇地」消失。