如何在XSLT1.0中聚合节点



我经常需要使用XSLT1.0聚合一系列节点,但我总是很难找到一个干净的解决方案。

这是一个典型的例子;

输入

<x>Foo/Red</x>
<x>Foo/Green</x>
<x>Foo/Blue</x>
<x>Bar/Hello</x>
<x>Bar/World</x>

所需输出

<y s="Foo">Red, Green, Blue</y>
<y s="Bar">Hello, World</y>

我总是在这类问题上一塌糊涂。是否有一个优雅的XSLT1.0解决方案来解决上述问题?

我使用的是PHPlibxslt,所以如果需要,我可以使用exslt:node-set()函数。

这里是muenchian分组对您的示例的改编。欲了解更多信息,请点击此处。如果您已经了解了它的工作原理,并尝试将其适应不断变化的分组问题,那么它将变得非常方便。

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:key name="kXprev" match="x" use="substring-before(text(),'/')"/>
    <xsl:template name="y">
        <xsl:param name="s" />
        <y s="{$s}">
            <xsl:for-each select="key('kXprev', $s)">
                <xsl:if test="position()>1" >
                    <xsl:text> </xsl:text>
                </xsl:if>
                <xsl:value-of select="substring-after(text(),'/')"/>
            </xsl:for-each>
        </y>
    </xsl:template>
    <xsl:template match="/*">
        <out>
            <xsl:for-each select="x[count( . | key('kXprev',substring-before(text(),'/') )[1] ) =1]" >
                <xsl:call-template name="y">
                    <xsl:with-param name="s" select="substring-before(text(),'/') "/>
                </xsl:call-template>
            </xsl:for-each>
        </out>
    </xsl:template>
</xsl:stylesheet>

一般来说:阅读Muenchian分组。

对于这个特定的问题(但也有一些有用的建议(:把它分解成更小的部分。

分解它的一种方法是:在输入中的x元素的(.,'/'(之前,您希望为表达式子字符串的每个不同值生成一个y元素。或者可能对于x的每次出现,其中该子字符串与其紧挨在前的同级的对应子字符串不同。首先编写一个样式表,它只生成正确数量的y元素,并为s属性提供适当的值。所以输出是

<y s="Foo"/>
<y s="Bar"/>

你怎么能那样做?

完成后,您需要为y元素提供内容:对于输入中共享相同前缀的每个x,打印出字符串值。在最终版本中,您需要逗号和空格,但正确使用它们需要一些繁琐的细节,因此编写下一版本的样式表以生成z元素序列作为y:的子元素

<y s="Foo"><z>Red</z><z>Green</z><z>Blue</z></y>
<y s="Bar"><z>Hello</z><z>World</z></y>

z元素需要出现在y元素内部。因此,生成y元素的模板更改为:

<xsl:template match="...">
  <!--* old code here ... *-->
  <xsl:element name="y">
    <xsl:attribute name="s">
      <xsl:value-of select="..."/>
    </xsl:attribute>
    <!--* code to produce 'z' elements goes here *-->
  </xsl:element>
</xsl:template>

生成z元素的代码应该是什么样子的?在给定前缀值$prefixy元素中,我们希望输入中共享该前缀的每个x都有一个z元素。因此,完成这项工作的一种简单方法是仅在y元素集上调用apply模板。为了避免干扰与x元素匹配并产生y元素的模板,给它一个模式。调用应用模板可能如下所示:

<xsl:apply-templates mode="z-production"
  select="//x[substring-before(.,'/') = $prefix]"/>

现在为z生产模式中的x元素编写模板。

最后,更改样式表以生成逗号和空格,而不是z元素。

还有其他方法可以将问题分解为更小的部分;有时,在树上从兄弟姐妹走到兄弟姐妹,而不是从父母走到兄弟姊妹,这很有帮助。

相关内容

  • 没有找到相关文章

最新更新