1

尝试为每个节点的每个父节点时遇到问题。我有这样的 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="*"/>

如果可以的话,请帮助我。

UPD:
我想要一些像菜单一样的东西(如果选择了 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>
4

3 回答 3

1

所以本质上你想要生成一个树结构,其中所有节点都“折叠”,除了具有指定 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">
于 2013-05-15T08:06:36.010 回答
1

您还没有明确您的问题,但我想知道您是否正在寻找参数节点 $item 的祖先,而不是上下文节点的祖先?如果是这样,那将是

select="$item/ancestor-or-self::item[@id='9']

但是,在您的示例 XML 中,唯一具有 @id='9' 的节点不是任何东西的祖先,所以我怀疑我在黑暗中摸索。

于 2013-05-14T18:23:58.770 回答
0

看下面的解决方案

<?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>
于 2013-06-05T13:29:02.243 回答