xsl 祖先或自我不返回结果
Posted
技术标签:
【中文标题】xsl 祖先或自我不返回结果【英文标题】:xsl ancestor-or-self not return result 【发布时间】:2013-05-14 15:05:30 【问题描述】:我在尝试为每个节点的每个父节点时遇到问题。我有这样的 XML:
<item name="news" id="77"> <items> <item id="102" /> <item id="103" /> </items> </item> <item id="86"> <items> <item id="122"> <items> <item id="6" /> <item id="9" /> </items> </item> <item id="12"> <items> <item id="13" /> <item id="18" /> <item id="19" /> </items> </item> </items> </item> <item name="sitemap" id="88" />
在模板中我尝试这样:
<xsl:template name="render">
<xsl:param name="length" />
<xsl:param name="item" />
<xsl:for-each select="ancestor-or-self::item[@id='9']">
some code
</xsl:for-each>
<xsl:apply-templates select="*"/>
如果可以的话,请帮帮我。
统一更新: 我想要一些像菜单一样的东西(如果选择了 id=9 的选项):
<ul>
<li>77</li>
<li>
86
<ul>
<li>
122
<ul>
<li>6</li>
<li>9</li>
</ul>
</li>
<li>12</li>
</ul>
</li>
<li>88</li>
</ul>
我的 XSLT(我想想)不好:
<xsl:template match="/">
<ul>
<xsl:call-template name="render">
<xsl:with-param name="item" select="item[@id='9']" />
<xsl:with-param name="length" select="0" />
</xsl:call-template>
</ul>
</xsl:template>
<xsl:template name="render">
<xsl:param name="length" />
<xsl:param name="item" />
<xsl:for-each select="$item/ancestor-or-self::item[@id='9']">
<xsl:if test="position()=length">
<xsl:variable name="current" select="." />
<xsl:for-each select="../item">
<xsl:choose>
<xsl:when test=".=current">
<li class="selectedItem">
<p>
<xsl:value-of select="@id"/>
</p>
<xsl:call-template name="render">
<xsl:with-param name="length" select="$lenght + 1" />
<xsl:with-param name="item" select="$item" />
</xsl:call-template>
</li>
</xsl:when>
<xsl:otherwise>
<li>
<p>
<xsl:value-of select="@id"/>
</p>
</li>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="*"/>
</xsl:template>
【问题讨论】:
你的问题不是特别清楚,更像是一个陈述而不是一个问题。您能否更具体一点...特别是,您正在寻找什么作为输出。 调用render
模板时的当前节点是什么?您能否向我们展示更多您的 XSLT?
【参考方案1】:
您还没有明确您的问题,但我想知道您是否正在寻找参数节点 $item 的祖先,而不是上下文节点的祖先?如果是这样,那将是
select="$item/ancestor-or-self::item[@id='9']
但是,在您的示例 XML 中,唯一具有 @id='9' 的节点不是任何东西的祖先,所以我怀疑我在黑暗中摸索。
【讨论】:
【参考方案2】:所以本质上你想要生成一个树结构,其中所有节点都“折叠”,除了具有指定 id 的节点。我会以不同的方式处理这个问题:
<xsl:template match="items | menu" mode="menu">
<xsl:param name="targetId" />
<ul>
<xsl:apply-templates select="item" mode="menu">
<xsl:with-param name="targetId" select="$targetId"/>
</xsl:apply-templates>
</ul>
</xsl:template>
<xsl:template match="item" mode="menu">
<xsl:param name="targetId" />
<li>
<xsl:if test="@id = $targetId">
<xsl:attribute name="class">selectedItem</xsl:attribute>
</xsl:if>
<xsl:value-of select="@id"/>
<!-- expand the branch only if it contains the target id -->
<xsl:apply-templates select="items[.//@id = $targetId]" mode="menu">
<xsl:with-param name="targetId" select="$targetId"/>
</xsl:apply-templates>
</li>
</xsl:template>
当你想为一个特定的 id 渲染一个菜单时,你只需说
<xsl:apply-templates select="/menu" mode="menu">
<xsl:with-param name="targetId" select="'9'"/>
</xsl:apply-templates>
(这里我假设您的原始 XML 有一个 <menu>
根元素包裹在*** item
元素集周围,如果不是这种情况,您将不得不适当地调整匹配并选择表达式)。
如果您还想显示目标 id 下方的级别(例如,当目标 id 为 122 时包括 6、9 层),那么只需更改
<xsl:apply-templates select="items[.//@id = $targetId]" mode="menu">
到
<xsl:apply-templates select="items[current()//@id = $targetId]" mode="menu">
【讨论】:
【参考方案3】:看看下面的解决方案
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="home" select="//item[@name='home']" />
<xsl:variable name="current_item" select="//item[@id = '55']" />
<xsl:variable name="parents_line" select="$current_item/ancestor-or-self::item" />
<xsl:variable name="path">
<xsl:for-each select="$parents_line">
<xsl:text>/</xsl:text>
<xsl:value-of select="@id"/>
<xsl:if test="position()=last()">/</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="*">
<xsl:call-template name="menu" />
</xsl:template>
<xsl:template name="menu">
<xsl:param name="level" select="1" />
<xsl:param name="start" select="$home" />
<ul>
<xsl:for-each select="$start/items/item">
<xsl:variable name="current_id" select="@id" />
<li>
<xsl:value-of select="@name" />
<xsl:if test="contains($path, concat('/', $current_id, '/') )">
<xsl:call-template name="menu">
<xsl:with-param name="level" select="$level+1" />
<xsl:with-param name="start" select="." />
</xsl:call-template>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
【讨论】:
以上是关于xsl 祖先或自我不返回结果的主要内容,如果未能解决你的问题,请参考以下文章
XSLT 函数返回不同的结果 [Saxon-EE vs Saxon-HE/PE]