XSLT-2.0:将来自 current-group() 的结果合并为一个

XSLT-2.0: Combining results from current-group() into one

使用 SaxonHE 9.7/XPath-2.0

我的XML:

<osm>
  <node>
    <tag k="fhrs:id" v="204258"/>
    <tag k="name" v="King of Wessex"/>
  </node>
  <node>
    <tag k="fhrs:id" v="139245"/>
    <tag k="name" v="The Royal Oak"/>
  </node>
  <node>
    <tag k="fhrs:id" v="204258"/>
    <tag k="name" v="The Rising Sun"/>
  </node>
  etc...
</osm>

我正在返回 fhrs:id 的所有重复值 (v=) 使用:

 <xsl:template match="/">       
     <xsl:for-each-group select="/*/*/tag[@k='fhrs:id']" group-by="@v">
        <xsl:apply-templates select="current-group() [current-group()[2]]"/>
     </xsl:for-each-group>
 </xsl:template>

我正在将输出转换为 geojson 格式。这要求除最后一个元素之外的每个元素都以逗号结尾。在其他例程中,我用它来测试它是否是最后一个:

<xsl:template match="/*/*/tag">
    {

     ...<snip>... 

    }<xsl:if test="position() &lt; last()">,</xsl:if>
</xsl:template> 

但是,因为在这种情况下 xsl:apply-templates 一次只传递两个,所以 geojson 输出中的每个其他元素都缺少一个逗号。

有没有一种方法可以将 xsl:for-each-group 的所有输出合并为一个,然后再传递给 xsl:apply-templates 或找到最终元素的替代方法? xsl:for-each-group 是最好的方法吗?

我研究了各种使用方法 variables/arrays 但似乎不符合要求。

你可以改变

<xsl:template match="/">       
     <xsl:for-each-group select="/*/*/tag[@k='fhrs:id']" group-by="@v">
        <xsl:apply-templates select="current-group() [current-group()[2]]"/>
     </xsl:for-each-group>
 </xsl:template>

<xsl:template match="/"> 
  <xsl:variable name="duplicates" as="element()*">      
     <xsl:for-each-group select="/*/*/tag[@k='fhrs:id']" group-by="@v">
        <xsl:sequence select="current-group() [current-group()[2]]"/>
     </xsl:for-each-group>
  </xsl:variable>
   <xsl:apply-templates select="$duplicates"/>
 </xsl:template>

至于 last() 的问题,Saxonica 重现了 https://saxonica.plan.io/issues/3122 中报告的问题,我认为在你的情况下你可以通过使用稍微不同的检查来避免使用 last() position() gt 1,但在输出内容之前:

<xsl:template match="/*/*/tag">
    <xsl:if test="position() gt 1">,</xsl:if>
    {

    "value" : "<xsl:value-of select="@v"/>"

    }
</xsl:template> 

<xsl:template match="/"> 
    <xsl:variable name="duplicates" as="element()*">      
        <xsl:for-each-group select="/*/*/tag[@k='fhrs:id']" group-by="@v">
            <xsl:sequence select="current-group() [current-group()[2]]"/>
        </xsl:for-each-group>
    </xsl:variable>
    <xsl:apply-templates select="$duplicates"/>
</xsl:template>

这样你应该能够避免与 last() 相关的错误,但是你应该在序列的项目之间得到一个逗号输出。