使用XSLT 1.0选择元素组的第一个元素

时间:2016-04-18 15:22:46

标签: xslt xpath

给出以下XML文档:

<foo>
  <bar>
    <type>1</type>
    <id>1</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>1</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>2</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>2</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
</foo>

XML元素bar是列表元素,按类型和ID进行逻辑分组。因此,示例文档包含两个有序列表(type = 1和id = 1,type = 1和id = 2),每个列表包含两个元素。在真实文档中,还有更多不同长度的列表(使用不同的类型和ID)。

现在我需要使用不同的值更新每个列表的第一个元素a1,例如在以下文件中:

<foo>
  <bar>
    <type>1</type>
    <id>1</id>
    <a1>-100</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>1</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>2</id>
    <a1>-100</a1>
    <other_stuff/>
  </bar>
  <bar>
    <type>1</type>
    <id>2</id>
    <a1>0</a1>
    <other_stuff/>
  </bar>
</foo>

在伪SQL中,这可能如下所示:

update bar set a1 = -100 where position() = 1 group by type, id

XSLT 1.0可以实现吗?我认为可以归结为能够编写一个XPath表达式,其结果与我的伪SQL语句相同。

1 个答案:

答案 0 :(得分:2)

使用Muenchian grouping标识每个组中的第一个项目并更改子项,使用标识转换复制其余项目:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:param name="new-value" select="-100"/>

    <xsl:key name="group" match="bar" use="concat(type, '|', id)"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"></xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])]/a1">
        <xsl:copy>
            <xsl:value-of select="$new-value"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

至于进一步的解释,密钥定义<xsl:key name="group" match="bar" use="concat(type, '|', id)"/>允许XSLT处理器索引bar上的concat(type, '|', id)元素,以便我们可以使用密钥函数,例如key('group', '1|1')bar concat(type, '|', id)找到具有bar值的所有bar[...]元素。

您只想更改每个组中的第一个bar[. is the first item in its group] 元素,因此我们需要有一种方法来识别谓词内的第一个项目key('group', concat(type, '|', id)),我们需要找到表达的模式条件

bar[. is the first item in key('group', concat(type, '|', id))]

我们使用is进入模式的组,因此我们想写一个条件

bar[. is key('group', concat(type, '|', id))[1]]

我们可以在XSLT 2.0中用bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])] 运算符和模式

表达几乎字面意思
bar

使用XSLT 1.0,我们可以使用generate-id表达它,如

中所述
[1]

选择/匹配生成的id等于key('group', concat(type, '|', id))计算的组中第一个(import file anyVariable = 42 # ... def aFunc(): file.anyVarible = file.anyVarible + 1 )项的生成ID的{{1}}元素。