统一处理分组的兄弟元素
Uniformly process grouped sibling elements
给定以下 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 样式表。
即文档中具有0
的@pos
属性的每个<a>
元素
隐式启动一个由它和 <a>
元素之后的 @total
-1 组成的组。换句话说,@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() <= current()/@total - 1]" />
</group>
</xsl:template>
<xsl:template match="a">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
我的解决方案存在的问题是它使那些 a[@pos=0]
元素成为 "special":要进一步处理预期组中的每个 <a>
元素,我必须单独应用适当的模板首先添加到 "group leader" 元素,然后添加到组中的其余元素。
换句话说,我非常想拥有类似(不正确)的东西
<xsl:template match="a" mode="leader">
<group>
<xsl:apply-templates select=". and following-sibling::a[position() <= current()/@total - 1]" />
</group>
</xsl:template>
这将一次性将我的 <xsl:template match="a">
模板应用于组中的所有元素。 (改写我试图在 select
表达式中拼写的内容:"select the context element and its following sibling elements matching …"。)
有没有一种方法可以在 XSLT 1.0 中获得我想要的东西,而无需诉诸变量和 exslt:node-set()
之类的技巧?可能有比我想出的更好的方法来根据元素计数进行这种分组(这本质上使每个组中的第一个元素变得特殊)?
我承认这个问题的标题很薄弱,但我没能想出一个简洁的标题来正确反映我的问题的本质。
你可以这样做:
<xsl:apply-templates select=". | following-sibling::a[position() <= current()/@total - 1]" />
P.S。使用变量或 node-set()
函数不符合 "hack".
给定以下 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 样式表。
即文档中具有0
的@pos
属性的每个<a>
元素
隐式启动一个由它和 <a>
元素之后的 @total
-1 组成的组。换句话说,@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() <= current()/@total - 1]" />
</group>
</xsl:template>
<xsl:template match="a">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
我的解决方案存在的问题是它使那些 a[@pos=0]
元素成为 "special":要进一步处理预期组中的每个 <a>
元素,我必须单独应用适当的模板首先添加到 "group leader" 元素,然后添加到组中的其余元素。
换句话说,我非常想拥有类似(不正确)的东西
<xsl:template match="a" mode="leader">
<group>
<xsl:apply-templates select=". and following-sibling::a[position() <= current()/@total - 1]" />
</group>
</xsl:template>
这将一次性将我的 <xsl:template match="a">
模板应用于组中的所有元素。 (改写我试图在 select
表达式中拼写的内容:"select the context element and its following sibling elements matching …"。)
有没有一种方法可以在 XSLT 1.0 中获得我想要的东西,而无需诉诸变量和 exslt:node-set()
之类的技巧?可能有比我想出的更好的方法来根据元素计数进行这种分组(这本质上使每个组中的第一个元素变得特殊)?
我承认这个问题的标题很薄弱,但我没能想出一个简洁的标题来正确反映我的问题的本质。
你可以这样做:
<xsl:apply-templates select=". | following-sibling::a[position() <= current()/@total - 1]" />
P.S。使用变量或 node-set()
函数不符合 "hack".