如何在XSL/XML中构建递归导航
我正在尝试构建一个导航,理论上可以使用XSL无限递归。不幸的是,我在这个竞技场上的技能仍在培养中。谁能告诉我这个代码哪里出了问题 更重要的是,nav的前两个级别有些独特(类名等),但在第三个级别之后,nav几乎是重复嵌套的相同元素 更新:如何在XSL/XML中构建递归导航,xml,xslt,recursion,xslt-1.0,Xml,Xslt,Recursion,Xslt 1.0,我正在尝试构建一个导航,理论上可以使用XSL无限递归。不幸的是,我在这个竞技场上的技能仍在培养中。谁能告诉我这个代码哪里出了问题 更重要的是,nav的前两个级别有些独特(类名等),但在第三个级别之后,nav几乎是重复嵌套的相同元素 更新: 导航级别2后没有递归,级别2后输出不存在,我不知道如何应用递归。我觉得这应该更容易,但我在XSL方面的技能并不是很好 HTML(我们需要它生成什么): <ul class="nav-l1"> <li class="nav-acti
导航级别2后没有递归,级别2后输出不存在,我不知道如何应用递归。我觉得这应该更容易,但我在XSL方面的技能并不是很好 HTML(我们需要它生成什么):
<ul class="nav-l1">
<li class="nav-active"><a href="nav2.html" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<ul class="nav-l2 nav-hidden">
<li class="nav-active"><a href="nav2.html" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<!-- 2nd level of navigation. -->
<ul class="nav-l2 nav-hidden">
<li><a href="#" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<!-- 3rd level of navigation. -->
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
</ul>
<data>
<folders level="1">
<folder clickable="Y" url="/lorem/ipsum.html" name="Lorem Ipsum"/>
<folder clickable="Y" url="/level/one.html" name="Level One"/>
<folder clickable="Y" url="/foo/bar.html" name="Foo Bar">
<folders level="2">
<folder clickable="Y" url="/level/two.html" name="Level two"/>
<folder clickable="Y" url="/child/item.html" name="Child Item">
<folders level="3">
<folder clickable="Y" url="/child/child/item.html" name="Child's Child Item">
<folders level="4">
<folder clickable="Y" url="/destiny/child/item.html" name="Destiny's Child"/>
</folders>
</folder>
</folders>
</folder>
</folders>
</folder>
</folders>
</data>
<?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="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="/data/folders">
<!-- NAVIGATION BEGINS HERE -->
<ul class="nav-l1">
<!-- LEVEL 1 -->
<xsl:for-each select="/data/folders[@level=1]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 2 -->
<xsl:choose>
<xsl:when test="child::*">
<ul class="nav-l2 nav-hidden">
<xsl:for-each select="folders[@level=2]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 3 and beyond ... -->
<xsl:apply-templates />
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- Infinity and beyond (=> Level 3) -->
<xsl:template name="folder">
<ul class="nav-ls nav-hidden">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:apply-templates select="folders[@level>3]/folder" />
</li>
</ul>
</xsl:template>
</xsl:stylesheet>
-
-
-
-
示例XML(初始数据提要的格式):
<ul class="nav-l1">
<li class="nav-active"><a href="nav2.html" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<ul class="nav-l2 nav-hidden">
<li class="nav-active"><a href="nav2.html" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<!-- 2nd level of navigation. -->
<ul class="nav-l2 nav-hidden">
<li><a href="#" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<!-- 3rd level of navigation. -->
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
</ul>
<data>
<folders level="1">
<folder clickable="Y" url="/lorem/ipsum.html" name="Lorem Ipsum"/>
<folder clickable="Y" url="/level/one.html" name="Level One"/>
<folder clickable="Y" url="/foo/bar.html" name="Foo Bar">
<folders level="2">
<folder clickable="Y" url="/level/two.html" name="Level two"/>
<folder clickable="Y" url="/child/item.html" name="Child Item">
<folders level="3">
<folder clickable="Y" url="/child/child/item.html" name="Child's Child Item">
<folders level="4">
<folder clickable="Y" url="/destiny/child/item.html" name="Destiny's Child"/>
</folders>
</folder>
</folders>
</folder>
</folders>
</folder>
</folders>
</data>
<?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="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="/data/folders">
<!-- NAVIGATION BEGINS HERE -->
<ul class="nav-l1">
<!-- LEVEL 1 -->
<xsl:for-each select="/data/folders[@level=1]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 2 -->
<xsl:choose>
<xsl:when test="child::*">
<ul class="nav-l2 nav-hidden">
<xsl:for-each select="folders[@level=2]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 3 and beyond ... -->
<xsl:apply-templates />
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- Infinity and beyond (=> Level 3) -->
<xsl:template name="folder">
<ul class="nav-ls nav-hidden">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:apply-templates select="folders[@level>3]/folder" />
</li>
</ul>
</xsl:template>
</xsl:stylesheet>
XSL(我们需要什么来转换XML):
<ul class="nav-l1">
<li class="nav-active"><a href="nav2.html" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<ul class="nav-l2 nav-hidden">
<li class="nav-active"><a href="nav2.html" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">First Level Parent</span></span></a>
<!-- 2nd level of navigation. -->
<ul class="nav-l2 nav-hidden">
<li><a href="#" class="nav-item"><span>Overview</span></a></li>
<li><a href="#" class="nav-item trigger-chan nav-next"><span><span class="trigger-cntr">Second Level Parent</span></span></a>
<!-- 3rd level of navigation. -->
<ul class="nav-ls nav-hidden">
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
<li><a href="#" class="nav-item"><span>Third Level</span></a></li>
</ul>
</li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
<li><a href="#" class="nav-item"><span>Second Level</span></a></li>
</ul>
</li>
</ul>
<data>
<folders level="1">
<folder clickable="Y" url="/lorem/ipsum.html" name="Lorem Ipsum"/>
<folder clickable="Y" url="/level/one.html" name="Level One"/>
<folder clickable="Y" url="/foo/bar.html" name="Foo Bar">
<folders level="2">
<folder clickable="Y" url="/level/two.html" name="Level two"/>
<folder clickable="Y" url="/child/item.html" name="Child Item">
<folders level="3">
<folder clickable="Y" url="/child/child/item.html" name="Child's Child Item">
<folders level="4">
<folder clickable="Y" url="/destiny/child/item.html" name="Destiny's Child"/>
</folders>
</folder>
</folders>
</folder>
</folders>
</folder>
</folders>
</data>
<?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="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="/data/folders">
<!-- NAVIGATION BEGINS HERE -->
<ul class="nav-l1">
<!-- LEVEL 1 -->
<xsl:for-each select="/data/folders[@level=1]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 2 -->
<xsl:choose>
<xsl:when test="child::*">
<ul class="nav-l2 nav-hidden">
<xsl:for-each select="folders[@level=2]/folder[not (@clickable ) or @clickable ='Y' ]">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- LEVEL 3 and beyond ... -->
<xsl:apply-templates />
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- Infinity and beyond (=> Level 3) -->
<xsl:template name="folder">
<ul class="nav-ls nav-hidden">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span><xsl:value-of select="@name" /></span>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:apply-templates select="folders[@level>3]/folder" />
</li>
</ul>
</xsl:template>
</xsl:stylesheet>
-
导航激活
-
导航激活
-
导航激活
非常感谢您的帮助
谢谢 您的XSLT非常专注,可以进行一些重新设计,使其更具功能性(从功能性编程的角度)
但主要错误在于:
<!-- Infinity and beyond (=> Level 3) -->
<xsl:template name="folder">
编辑:推式方法
这可能并不完美,但有几点:
*当列表中有
时,可以完全跳过,其中
是列表项。
*您似乎复制了级别1、2和3的项目代码。
*你只做过一件3级及以上的物品,其他的都会被忽略
请注意,我已经定义了如何基于级别渲染
,以及如何独立渲染
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="folders">
<ul>
<xsl:attribute name="class">
<xsl:text>nav-l</xsl:text>
<xsl:choose>
<xsl:when test="@level>2">
<xsl:text>s nav-hidden</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@level"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="folder">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span>
<xsl:value-of select="@name"/>
</span>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:apply-templates select="folders"/>
</li>
</xsl:template>
</xsl:stylesheet>
导航-l
导航隐藏
导航激活
请注意,由于删除了重复的元素,上述模板比初始模板短。所有的
都呈现相同的内容,因此只需要一个模板。事实上,
不需要知道它们的级别,只有父级才需要知道,这样就可以将逻辑移到正确的模板中
不熟悉XSLT的人通常会忽略如何有效地使用apply templates
来定义递归并允许元素之间非常清晰的分离。在创建模板时,请尝试并关注如何表示此特定元素,并了解如何需要其子元素。然后,重点关注子元素的新模板以及如何呈现这些子元素等等
除此之外,请始终注意。/
中的@选择s或
s,因为这意味着您的逻辑依赖于当前“范围”之外的元素。不总是坏的,但要注意
尽可能减少每个的,看看是否可以重写它们以使用应用模板
,除非出于某种奇怪的原因绝对需要,否则尝试不要使用调用模板
,因为它们的功能性较差。您的XSLT非常集中,可以使用一些重新设计来提高功能性(在函数编程的意义上)
但主要错误在于:
<!-- Infinity and beyond (=> Level 3) -->
<xsl:template name="folder">
编辑:推式方法
这可能并不完美,但有几点:
*当列表中有
时,可以完全跳过,其中
是列表项。
*您似乎复制了级别1、2和3的项目代码。
*你只做过一件3级及以上的物品,其他的都会被忽略
请注意,我已经定义了如何基于级别渲染
,以及如何独立渲染
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="folders">
<ul>
<xsl:attribute name="class">
<xsl:text>nav-l</xsl:text>
<xsl:choose>
<xsl:when test="@level>2">
<xsl:text>s nav-hidden</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@level"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="folder">
<li>
<xsl:if test="@selected='Y'">
<xsl:attribute name="class">nav-active</xsl:attribute>
</xsl:if>
<a href="{@url}" class="nav-item">
<xsl:choose>
<xsl:when test="child::*">
<xsl:attribute name="class">trigger-chan nav-next</xsl:attribute>
<span>
<span class="trigger-cntr">
<xsl:value-of select="@name"/>
</span>
</span>
</xsl:when>
<xsl:otherwise>
<span>
<xsl:value-of select="@name"/>
</span>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:apply-templates select="folders"/>
</li>
</xsl:template>
</xsl:stylesheet>
导航-l
导航隐藏
导航激活
注意abo