我很难编写一个模板,用于从节点结构中生成面包屑试验。到目前为止,它无法正常工作,我的思考中有一些缺陷应该如何走项路径。
考虑以下页面结构:
<!-- ===== SITE PAGE STRUCTURE ===================================== -->
<index>
<item section="home" id="index"></item>
<item section="service" id="index">
<item id="content-management-systems">
<item id="p1-1"/>
<item id="p1-2"/>
<item id="p1-3"/>
</item>
<item id="online-stores"></item>
<item id="search-engines-and-ir"></item>
<item id="web-applications"></item>
</item>
<item section="solutions" id="index">
<item id="document-clustering"></item>
</item>
<item section="company" id="index">
<item section="company" id="about"></item>
<item section="company" id="philosophy" ></item>
...
</item>
...
</item>
此站点索引表示其层次结构中xml内容页面的站点结构(将其视为菜单)。它包含部分,它们代表网站部分,就像家庭,公司,服务,解决方案等。这些部分可以包含子部分页面,或只是常规内容页面。内容页面(其xml内容,如标题,文本内容等)由项目树中的@id属性标识。 @id属性主要用于获取将呈现为html的整个页面的内容。 面包屑模板使用 item 节点@id属性来获取页面的标题(将在痕迹路径中显示)。
我尝试通过检查目标节属性@section和树中的目标页面属性@id来实现以下遍历树的模板。我希望它通过比较祖先的@section属性和@id与该轴中每个节点的$ item_target来向下移动轴直到找到目标item_target。
例如:属性* $ item_section = service *和页面标识*目标item_target = p1-1 *现在应该递归“走”到部分分支“服务“(深度1),检查是否在此级别找到目标页面@id。在这种情况下找不到它,因此它会使下一个重复调用(通过apply-templates)到下一个项节点级别(在这种情况下,它将是 content-management-systems < / strong>,找到目标项目页面p1-1,因此完成了跟踪过程:
结果应该是这样的:
主页&gt;&gt;服务&gt;&gt; <内容管理系统>&gt; P1-1
但不幸的是,它不正确,至少在每种情况下都不正确。也许它可以更容易地解决。我尝试将它实现为一个递归模板,从顶部(级别0)到目标页面(项目节点)作为叶子。
<!-- walk item path to generate a breadcrumb trail -->
<xsl:template name="breadcrumb">
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<xsl:value-of select="$req-lg"/>
<xsl:text>/home/index</xsl:text>
</xsl:attribute>
<xsl:value-of select="'Home'"/>
</a>
<xsl:apply-templates select="$content/site/index" mode="Item-Path">
<xsl:with-param name="item_section" select="'service'"/>
<xsl:with-param name="item_target" select="'search-engines-and-ir'"/>
<xsl:with-param name="depth" select="0"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="item" mode="Item-Path">
<xsl:param name="item_section" />
<xsl:param name="item_target" />
<xsl:param name="depth" />
<!--
depth=<xsl:value-of select="$depth"/>
count=<xsl:value-of select="count(./node())"/><br/>
-->
<xsl:variable name="cur-id" select="@id"/>
<xsl:variable name="cur-section" select="@section"/>
<xsl:choose>
<xsl:when test="@id=$item_target">
>>
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<!-- req-lg: global langauge variable -->
<xsl:value-of select="$req-lg"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="$item_section"/>
<xsl:text>/</xsl:text>
<xsl:if test="$depth = 2">
<xsl:value-of select="../@id"/>
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:value-of
select="$content/page[@id=$cur-id]/title"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:if test="ancestor-or-self::item/@section = $item_section and count(./node()) > 0">
>>:
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<!-- req-lg: global langauge variable -->
<xsl:value-of select="$req-lg"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="$item_section"/>
<xsl:text>/</xsl:text>
<xsl:if test="$depth = 2">
<xsl:value-of select="../@id"/>
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:value-of
select="$content/page[@id=$cur-id and @section=$item_section]/title"/>
</a>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="item" mode="Item-Path">
<xsl:with-param name="item_section" select="$item_section"/>
<xsl:with-param name="item_target" select="$item_target"/>
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:apply-templates>
</xsl:template>
因此,模板中的硬编码参数 breadcrumb ,target section ='service'和target page ='search-engines-and-ir',我希望输出像
主页&gt;&gt;服务&gt;&gt;搜索引擎和-IR
但输出是
主页&gt;&gt;服务&gt;&gt;内容管理系统&gt;&gt;搜索引擎和-IR
显然不正确。
有人能给我一个提示如何纠正这个问题吗?避免深度检查会更优雅,但到目前为止我无法想到其他方式,我相信有一个更优雅的解决方案。
我使用XSLT 1.0(通过PHP5的libxml)。
希望我的问题很清楚,如果没有,请问:-)感谢您的帮助!
答案 0 :(得分:2)
就这么简单:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeById" match="item" use="@id"/>
<xsl:template match="/">
<xsl:text>home</xsl:text>
<xsl:call-template name="findPath">
<xsl:with-param name="pStart" select="'service'"/>
<xsl:with-param name="pEnd" select="'search-engines-and-ir'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="findPath">
<xsl:param name="pStart"/>
<xsl:param name="pEnd"/>
<xsl:for-each select=
"key('kNodeById', $pEnd)
[ancestor::item[@section=$pStart]]
[1]
/ancestor-or-self::item
[not(descendant::item[@section=$pStart])]
">
<xsl:value-of select=
"concat('>>', @id[not(../@section)], @section)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
产生了想要的正确结果:
home>>service>>search-engines-and-ir
请注意:
此解决方案将层次结构从任何节点(层次结构中的任何位置)打印到层次结构中任何位置的任何后代节点。更准确地说,对于item
属性等于id
的第一个$pEnd
(按文档顺序),面包屑是从其section
属性相等的最内部祖先生成的到$pStart
- 到item
元素。
此解决方案应该比使用//
的任何解决方案更有效,因为我们使用密钥有效地定位“结束”item
元素。
<强> II。 XSLT 2.0解决方案:
更短更容易 - 一个XPathe 2.0单表达式:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeById" match="item" use="@id"/>
<xsl:template match="/">
<xsl:value-of select=
"string-join(
(
'home',
key('kNodeById', $pEnd)
[ancestor::item[@section=$pStart]]
[1]
/ancestor-or-self::item
[not(descendant::item[@section=$pStart])]
/(@id[not(../@section)], @section)[1]
),
'>>'
)
"/>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
你可以迭代祖先或自我::轴。没有递归就很容易做到这一点。例如......
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html><body>
<xsl:call-template name="bread-crumbs">
<xsl:with-param name="items" select="*/item" />
<xsl:with-param name="section" select="'service'" />
<xsl:with-param name="leaf" select="'p1-2'" />
</xsl:call-template>
</body></html>
</xsl:template>
<xsl:template name="bread-crumbs">
<xsl:param name="items" />
<xsl:param name="section" />
<xsl:param name="leaf" />
<xsl:value-of select="concat($section,'>>')" />
<xsl:for-each select="$items/self::item[@section=$section]//item[@id=$leaf]/
ancestor-or-self::item[not(@section)]">
<xsl:value-of select="@id" />
<xsl:if test="position() != last()">
<xsl:value-of select="'>>'" />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...对您的样本输入产生...
<html>
<body>service>>content-management-systems>>p1-2</body>
</html>
......呈现为......
service>>content-management-systems>>p1-2