我有以下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语句中的轴错误)!这里出了什么问题?
答案 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如何“神奇地”消失。