【发布时间】:2020-08-31 18:28:56
【问题描述】:
使用 XSLT 2.0,假设您有 current-group() = { A, X, B, B, X } 其中 A, B, 和 X 是元素。在第一次出现 B 时拆分它以获得两个序列 S1 和 S2的高效且清晰的方法是什么> 这样 S1 = { A, X } 和 S2 = { B, B, X }?是否可以使用 xsl:for-each-group 构造来完成此操作?
编辑:current-group() 的元素不保证是兄弟姐妹,但保证按文档顺序排列。
第一次尝试:使用 xsl:for-each-group 和 group-starting-with
<xsl:for-each-group select="current-group()" group-starting-with="B[1]">
<xsl:choose>
<xsl:when test="position() = 1">
<!-- S1 := current-group() -->
</xsl:when>
<xsl:otherwise>
<!-- S2 := current-group() -->
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
如果当前组()的第一个 B 没有前面的兄弟 B,则此方法有效。
我原以为位置谓词[1] 将限定为select 子句,因为current-group()[self::B][1] 返回正确的B。我很想知道为什么它没有这样的范围。
XML
<root>
<A>A1</A>
<B>B1-1</B>
<B>B1-2</B>
<A>A2</A>
<B>B2-1</B>
<B>B2-2</B>
</root>
XSLT
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="A">
<xsl:for-each-group select="current-group()" group-starting-with="B[1]">
<xsl:choose>
<xsl:when test="position() = 1">
<S1><xsl:copy-of select="current-group()" /></S1>
</xsl:when>
<xsl:otherwise>
<S2><xsl:copy-of select="current-group()" /></S2>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
结果
<root>
<S1>
<A>A1</A>
</S1>
<S2>
<B>B1-1</B>
<B>B1-2</B>
</S2>
<S1>
<A>A2</A>
<B>B2-1</B>
<B>B2-2</B>
</S1>
</root>
如您所见,第一组已正确拆分,但第二组未正确拆分。但是,如果您将 current-group() 包装在父项中,然后将其传递给 select 子句,这将起作用,但这似乎效率低下。
【问题讨论】:
-
商业版中的Saxon 10具有
items-before和items-from等函数。 saxonica.com/documentation/index.html#!functions/saxon/…。如果需要,您可以自己滚动,但我对您的输入没有清楚的了解,是否只需要在第一个B上拆分序列?是否保证了B的存在?您是否需要进一步拆分Bs 序列?而且还不清楚您是要解决元素是兄弟元素的输入还是A, X, B, B, X的任何序列,与它们在XML 中的顺序/关系无关 -
@MartinHonnen 感谢您的快速回复!不保证
B的存在。我不确定您所说的“B的进一步序列”是什么意思。在这种特殊情况下,组的元素始终按文档顺序排列,但不一定是兄弟。 -
group-starting-with="B[1]"在与模式B[1]匹配的任何项目上开始一个新组,并且此模式匹配作为其父级的第一个B子级的任何B元素;它与B在select序列中的位置无关。
标签: xslt xslt-2.0 xslt-grouping