XSLT 3.0如何获取分组内前一行的DataInicio元素值
解决XSLT 3.0分组后获取组内前一行
DataInicio值的问题 在按userId分组并对组内row排序后,不能直接用preceding-sibling,因为分组后的节点集合是独立的节点序列,并非原始文档中的兄弟节点。可以通过以下两种方式修正:
方法1:使用current-group()结合位置索引
在遍历分组内的节点时,通过position()获取当前位置,再从current-group()中取前一个位置的节点:
<xsl:for-each-group select="/root/row" group-by="@userId"> <!-- 先对组内节点按DataInicio排序 --> <xsl:for-each select="current-group()!sort(., function($r) { $r/DataInicio })"> <xsl:variable name="current-pos" select="position()" /> <!-- 获取前一行的DataInicio --> <xsl:variable name="prev-data-inicio" select="current-group()[sort(., function($r) { $r/DataInicio })][$current-pos - 1]/DataInicio" /> <!-- 你的业务逻辑代码 --> <row> <userId><xsl:value-of select="@userId" /></userId> <currentDataInicio><xsl:value-of select="DataInicio" /></currentDataInicio> <prevDataInicio><xsl:value-of select="$prev-data-inicio" /></prevDataInicio> </row> </xsl:for-each> </xsl:for-each-group>
方法2:使用XSLT 3.0的window函数(更简洁)
利用窗口函数直接将排序后的节点序列按相邻关系分组,直接获取前一个节点:
<xsl:for-each-group select="/root/row" group-by="@userId"> <xsl:variable name="sorted-group" select="current-group()!sort(., function($r) { $r/DataInicio })" /> <xsl:for-each select="$sorted-group!window(start at $s where true(), end at $e where true())"> <row> <userId><xsl:value-of select="$s/@userId" /></userId> <currentDataInicio><xsl:value-of select="$s/DataInicio" /></currentDataInicio> <prevDataInicio><xsl:value-of select="if ($s is not $sorted-group[1]) then $sorted-group[index-of($sorted-group, $s) - 1]/DataInicio else ''" /></prevDataInicio> </row> </xsl:for-each> </xsl:for-each-group>
关键说明
preceding-sibling仅适用于原始XML文档中节点的兄弟关系,分组后的节点序列是独立的节点集合,因此无法直接通过该语法获取组内前一个节点。- 第一种方法通过在
current-group()中重新引用排序后的节点序列,结合position()位置索引定位前一个节点,逻辑直观易理解。 - 第二种方法利用XSLT 3.0新增的
window函数,更高效地处理相邻节点的关联关系,适合复杂的序列遍历场景。
内容的提问来源于stack exchange,提问作者Carlos Moraes
相关产品推荐
相关产品推荐

