给出以下xml:
<container>
<val>2</val>
<id>1</id>
</container>
<container>
<val>2</val>
<id>2</id>
</container>
<container>
<val>2</val>
<id>3</id>
</container>
<container>
<val>4</val>
<id>1</id>
</container>
<container>
<val>4</val>
<id>2</id>
</container>
<container>
<val>4</val>
<id>3</id>
</container>
我想返回类似
的内容2 - 1
2 - 3
4 - 1
4 - 3
使用节点集我已经能够通过以下方式获得最后一次:
exsl:node-set($list)/container[not(val = following::val)]
但我无法弄清楚如何获得第一个。
答案 0 :(得分:3)
要获取每个“<val>
”组中的第一个和最后一个(文档顺序),您可以使用<xsl:key>
,如下所示:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="ContainerGroupByVal" match="container" use="val" />
<xsl:variable name="ContainerGroupFirstLast" select="//container[
generate-id() = generate-id(key('ContainerGroupByVal', val)[1])
or
generate-id() = generate-id(key('ContainerGroupByVal', val)[last()])
]" />
<xsl:template match="/">
<xsl:for-each select="$ContainerGroupFirstLast">
<xsl:value-of select="val" />
<xsl:text> - </xsl:text>
<xsl:value-of select="id" />
<xsl:value-of select="' '" /><!-- LF -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
编辑#1:有点解释,因为这可能不会立即显而易见:
<xsl:key>
返回具有给定<container>
的所有<val>
个节点。您可以使用key()
函数进行查询。<xsl:variable>
就是这一切发生的地方。它读作:
<container>
节点(“//container
”)检查... generate-id()
返回的第一个节点或key()
返回的最后一个节点具有相同的唯一ID(key()
)key('ContainerGroupByVal', val)
返回与当前<container>
<val>
个节点集
<xsl:for-each>
执行输出。它也可以是<xsl:apply-templates>
。//
”XPath简写。如果你可以避免它,一定要这样做 - 部分是因为它可能选择你不想要的节点,主要是因为它比一个更具体的XPath表达式更慢。例如,如果您的文档如下:
<containers>
<container><!-- ... --></container>
<container><!-- ... --></container>
<container><!-- ... --></container>
</containers>
然后你应该使用“/containers/container
”或“/*/container
”代替“//container
”。
编辑#3:上述的另一种语法是:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="ContainerGroupByVal" match="container" use="val" />
<xsl:variable name="ContainerGroupFirstLast" select="//container[
count(
.
| key('ContainerGroupByVal', val)[1]
| key('ContainerGroupByVal', val)[last()]
) = 2
]" />
<xsl:template match="/">
<xsl:for-each select="$ContainerGroupFirstLast">
<xsl:value-of select="val" />
<xsl:text> - </xsl:text>
<xsl:value-of select="id" />
<xsl:value-of select="' '" /><!-- LF -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
说明:XPath联合运算符“|
”将其参数组合到节点集中。根据定义,节点集不能包含重复节点 - 例如:“. | . | .
”将创建一个仅包含一个节点(当前节点)的节点集。
这意味着,如果我们从当前节点(“。”),“key(…)[1]
”节点和“key(…)[last()]
”节点创建联合节点集,它的节点数将为2如果(且仅当)当前节点等于其他两个节点之一,则在所有其他情况下,计数将为3.
答案 1 :(得分:1)
基本XPath:
//container[position() = 1] <- this is the first one
//container[position() = last()] <- this is the last one
这里有一组更详细的XPath functions。
答案 2 :(得分:1)
<强> 予。 XSLT 1.0
基本上与Tomalak的解决方案相同,但更容易理解 它也是完整的,因此您只需要复制并粘贴XML文档和转换,然后只需按您最喜欢的XSLT IDE的“转换”按钮:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kContByVal" match="container"
use="val"/>
<xsl:template match="/*">
<xsl:for-each select=
"container[generate-id()
=
generate-id(key('kContByVal',val)[1])
]
">
<xsl:variable name="vthisvalGroup"
select="key('kContByVal', val)"/>
<xsl:value-of select=
"concat($vthisvalGroup[1]/val,
'-',
$vthisvalGroup[1]/id,
'
'
)
"/>
<xsl:value-of select=
"concat($vthisvalGroup[last()]/val,
'-',
$vthisvalGroup[last()]/id,
'
'
)
"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
将此转换应用于最初提供的XML文档(编辑为格式良好)时:
<t>
<container>
<val>2</val>
<id>1</id>
</container>
<container>
<val>2</val>
<id>2</id>
</container>
<container>
<val>2</val>
<id>3</id>
</container>
<container>
<val>4</val>
<id>1</id>
</container>
<container>
<val>4</val>
<id>2</id>
</container>
<container>
<val>4</val>
<id>3</id>
</container>
</t>
生成了想要的结果:
2-1
2-3
4-1
4-3
请注意:
container
具有相同值的每组此类元素找到一个val
元素。container
值的val
元素的整个节点列表中,我们输出组中第一个container
元素的必需数据以及该组中的最后一个container
元素。<强> II。 XSLT 2.0
此转化:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:for-each-group select="container"
group-by="val">
<xsl:for-each select="current-group()[1], current-group()[last()]">
<xsl:value-of select=
"concat(val, '-', id, '
')"/>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
应用于上述相同的XML文档时,产生想要的结果:
2-1
2-3
4-1
4-3
请注意:
使用<xsl:for-each-group>
XSLT指令。
使用current-group()
功能。