使用xsl从节点结构生成breadcrumb跟踪



我很难编写一个从节点结构中生成面包屑试用版的模板。到目前为止,它还不能正常工作,我认为它应该如何走项目的路径存在一些缺陷。

考虑以下页面结构:

<!-- ===== 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的整个页面的内容。breadcrumb模板使用node@id属性来获取页面的标题(将显示在breadcrump跟踪中)。

我试图通过检查树中的目标节属性@section和目标页属性@id来实现遍历树的以下模板。我希望它沿着轴向下移动,直到通过比较该轴中每个节点的祖先@section属性和@id与$item_target找到目标item_target。

例如:属性*$item_section=service*和页面id*target item_target=p1-1*现在应该递归地"行走"到部分分支">service"(深度1),检查是否在该级别上找到目标页面@id。在这种情况下,它找不到,因此它对下一个项目节点级别进行下一次递归调用(通过应用模板)(在这种情况中,它将是内容管理系统,在那里找到了目标项目页面p1-1,因此跟踪过程完成:

结果应该是这样的:

主页>>服务>>内容管理系统>>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">
&gt;&gt;
<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">
&gt;&gt;:
<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中的硬编码参数,目标部分="服务",目标页面="搜索引擎和ir",我预计会有类似的输出

主页>>服务>>搜索引擎和ir

但是输出是

主页>>服务>>内容管理系统>>搜索引擎和ir

这显然是不正确的。

有人能告诉我如何纠正这个问题吗?避免深度检查会更优雅,但到目前为止,我想不出其他方法,我相信有一个更优雅的解决方案。

我使用XSLT1.0(通过PHP5的libxml)。

希望我的问题足够清楚,如果不清楚,请问:-)谢谢你提前的帮助!

就这么简单

<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

注意

  1. 此解决方案将面包屑从层次结构中的任何节点打印到层次结构中任何子节点。更准确地说,对于id属性等于$pEnd的第一个item(按文档顺序),面包屑是从其section属性等于$pStart的最内部祖先到该item元素生成的。

  2. 这个解决方案应该比使用//的任何解决方案都要高效得多,因为我们正在使用一个键来有效地定位"结束"item元素。


II。XSLT2.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>

您可以在祖先或self::轴上迭代。这在没有递归的情况下很容易做到。例如

<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,'&gt;&gt;')" />
<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="'&gt;&gt;'" />
</xsl:if>  
</xsl:for-each>  
</xsl:template>  
</xsl:stylesheet>

根据您的样本输入产量。。。

<html>
<body>service&gt;&gt;content-management-systems&gt;&gt;p1-2</body>
</html> 

呈现为…

service>>content-management-systems>>p1-2

相关内容

  • 没有找到相关文章

最新更新