统一处理分组的兄弟元素

时间:2016-11-23 09:34:58

标签: xslt xslt-1.0 xslt-grouping

给出以下XML文档

<root>
  <a pos="0" total="2"/>
  <a pos="1" total="2"/>

  <a pos="0" total="3"/>
  <a pos="1" total="3"/>
  <a pos="2" total="3"/>

  <a pos="0" total="4"/>
  <a pos="1" total="4"/>
  <a pos="2" total="4"/>
  <a pos="3" total="4"/>
</root>

我需要将其翻译为

<root>
  <group>
    <a pos="0" total="2"/>
    <a pos="1" total="2"/>
  </group>
  <group>
    <a pos="0" total="3"/>
    <a pos="1" total="3"/>
    <a pos="2" total="3"/>
  </group>
  <group>
    <a pos="0" total="4"/>
    <a pos="1" total="4"/>
    <a pos="2" total="4"/>
    <a pos="3" total="4"/>
  </group>
</root>

使用XSLT 1.0样式表。

也就是说,文档中<a>属性为@pos的每个0元素 隐式启动一个由它组成的组和@total - 1个<a>元素之后的组。换句话说,@pos表示@total个相邻元素组中元素的从0开始的索引(位置)。

我提出了以下样式表,它有效:

<?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:template match="/">
        <xsl:apply-templates select="root" />
    </xsl:template>

    <xsl:template match="root">
        <xsl:apply-templates select="a[@pos=0]" mode="leader"/>
    </xsl:template>

    <xsl:template match="a" mode="leader">
        <group>
            <xsl:apply-templates select="." />
            <xsl:apply-templates select="following-sibling::a[position() &lt;= current()/@total - 1]" />
        </group>
    </xsl:template>

    <xsl:template match="a">
         <xsl:copy-of select="." />
    </xsl:template>

</xsl:stylesheet>

我的解决方案存在的问题是,它使这些a[@pos=0]元素“特殊”:要进一步处理预期组中的每个<a>元素,我必须先分别应用相应的模板“组长”元素,然后是组中其他元素。

换句话说,我非常希望得到类似(不正确)的内容

    <xsl:template match="a" mode="leader">
        <group>
            <xsl:apply-templates select=". and following-sibling::a[position() &lt;= current()/@total - 1]" />
        </group>
    </xsl:template>

将我的<xsl:template match="a">模板一次性应用于组中的所有元素。 (重新说明我试图在select表达式拼写的内容:“选择上下文元素及其后续的兄弟元素匹配...”。)

有没有办法在不诉诸变量和exslt:node-set()等黑客的情况下使用XSLT 1.0获得我想要的东西?可能有一个更好的方法来进行基于元素计数的分组而不是我想出的那个(这本身就使每个组中的第一个元素特殊)?

我承认这个问题的标题相当薄弱,但我没有想出一个正确反映我问题本质的succint。

1 个答案:

答案 0 :(得分:1)

你可以这样做:

<xsl:apply-templates select=". | following-sibling::a[position() &lt;= current()/@total - 1]" />

P.S。使用变量或node-set()函数不符合&#34; hack&#34;。