如何在XSLT中有条件地过滤掉子项

时间:2015-07-22 20:00:42

标签: xslt

我目前有类似于以下XML的内容:

<div class="newsFeed">
   <div class="newsItem"><news position="3"/></div>
   <categoryFilter dayFilter="4">
       <div class="newsItem"><news position="2"/></div>
   </categoryFilter>
</div>

我需要复制XML,并在节点上输出第n个新闻项。此外,我需要能够过滤该新闻。对于此示例,让我们按如下方式构建我的新闻:

<xsl:variable name="news">
    <xsl:for-each select="1 to 30">
        <item>
          <day><xsl:value-of select=". mod 4" /></day>
          <content>Content: <xsl:value-of select="." /></content>
        </item>
    </xsl:for-each>
</xsl:variable>

我实际上使用document()并使用for-each对其进行排序,但我试图保持简洁。这意味着我的输出XML将类似于以下内容:

<div class="newsFeed">
    <div class="newsItem">Content: 3</div>  
    <div class="newsItem">Content: 8</div>  
 </div>

第二个8的原因是因为categoryFilter会过滤掉每天<item>的日期不是4(恰好是第4天,第8天,第12天) ,依此类推),然后我们选择第二个。

产生上述内容的XSLT如下:

XSLT:

<xsl:template match="news">
   <xsl:param name="items" select="$news" />
   <xsl:variable name="position" select="@position" />
   <xsl:copy-of select="$items/item[position()=$position]/content" />
</xsl:template>

<xsl:template match="categoryFilter">
   <xsl:param name="items" select="$news" />
   <xsl:variable name="day" select="@dayFilter" />
   <xsl:variable name="filteredItems">
      <xsl:for-each select="$items/item[day=$day]">
         <xsl:copy-of select="." />
      </xsl:for-each>
   </xsl:variable>
   <xsl:apply-templates>
      <xsl:with-param name="items" select="$filteredItems">
   </xsl:apply-templates>
</xsl:template>

我的问题在于<for-each>。我必须使用for-each来过滤掉<item>节点,这似乎很愚蠢,但我无法找到更好的方法。只需执行<xsl:variable select="$items/item[day=$day]">即可更改结构,并使其<xsl:template match="news">无法正常工作。

有没有办法过滤掉子节点而不使用for-each?我正在使用<xsl:stylesheet version="3.0">

1 个答案:

答案 0 :(得分:1)

而不是这样做......

<xsl:variable name="filteredItems">
   <xsl:for-each select="$items/item[day=$day]">
      <xsl:copy-of select="." />
   </xsl:for-each>
</xsl:variable>

...你可以使用一个序列。这将选择实际项目,而不是创建它们的副本

<xsl:variable name="filteredItems">
   <xsl:sequence select="$items/item[day=$day]" />
</xsl:variable>

这样做,$filteredItems/item仍然有用。

或者,您可以采取相反的方法,并且不需要在所有表达式中指定/item

首先,定义您的news变量,如下所示:

<xsl:variable name="news" as="element()*">

这意味着您可以像这样编写使用它的表达式:

<xsl:copy-of select="$news[position()=$position]/content" />

同样适用于filteredItems ....

<xsl:variable name="filteredItems" select="$items[day=$day]" />