【问题标题】:XSLT 2.0 Splitting current-group() by first occurence of an elementXSLT 2.0 通过第一次出现的元素拆分 current-group()
【发布时间】:2020-08-31 18:28:56
【问题描述】:

使用 XSLT 2.0,假设您有 current-group() = { A, X, B, B, X } 其中 A, B,X 是元素。在第一次出现 B 时拆分它以获得两个序列 S1S2高效且清晰的方法是什么> 这样 S1 = { A, X }S2 = { B, B, X }?是否可以使用 xsl:for-each-group 构造来完成此操作?

编辑:current-group() 的元素不保证是兄弟姐妹,但保证按文档顺序排列。


第一次尝试:使用 xsl:for-each-groupgroup-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-beforeitems-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 元素;它与Bselect 序列中的位置无关。

标签: xslt xslt-2.0 xslt-grouping


【解决方案1】:

functx 库定义了一个函数functx:index-of-node (http://www.xsltfunctions.com/xsl/functx_index-of-node.html):

<xsl:function name="functx:index-of-node" as="xs:integer*"
              xmlns:functx="http://www.functx.com">
  <xsl:param name="nodes" as="node()*"/>
  <xsl:param name="nodeToFind" as="node()"/>

  <xsl:sequence select="
  for $seq in (1 to count($nodes))
  return $seq[$nodes[$seq] is $nodeToFind]
 "/>

</xsl:function>

这会减少你的第二种方法

<xsl:template match="root">
  <xsl:copy>
    <xsl:for-each-group select="*" group-starting-with="A">
        <xsl:variable name="pos" select="functx:index-of-node(current-group(), (current-group()[self::B])[1])"/>
        <S1>
            <xsl:copy-of select="current-group()[position() lt $pos]"/>
        </S1>
        <S2>
            <xsl:copy-of select="current-group()[position() ge $pos]"/>
        </S2>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

在具有扩展功能 saxon:items-beforesaxon:items-fromsyntax extension for anonymous functions 的 Saxon 10 PE 或 EE 的“新”“XSLT 4”世界中,您可以将其写为

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
    exclude-result-prefixes="#all" version="3.0">

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:output indent="yes"/>

    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each-group select="*" group-starting-with="A">
                <S1>
                    <xsl:apply-templates
                        select="saxon:items-before(current-group(), .{ . instance of element(B) })"/>
                </S1>
                <S2>
                    <xsl:apply-templates
                        select="saxon:items-from(current-group(), .{ . instance of element(B) })"/>
                </S2>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多