给定以下 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() <= 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() <= current()/@total - 1]" />
</group>
</xsl:template>
这将一次性将我的<xsl:template match="a">
模板应用于组中的所有元素。(改写我试图在select
表达式中拼写的内容:"选择上下文元素及其以下同级元素匹配......"。
有没有办法在不使用变量和exslt:node-set()
等黑客的情况下使用 XSLT 1.0 获得我想要的东西? 也许有比我想出的更好的方法来根据元素计数进行这种分组(这本质上使每个组中的第一个元素变得特别)?
承认这个问题的标题相当薄弱,但我未能提出一个简洁的标题来正确反映我的问题的意义。
你可以做:
<xsl:apply-templates select=". | following-sibling::a[position() <= current()/@total - 1]" />
附言:使用变量或node-set()
函数不符合"黑客"的条件。