如何按类似源节点生成所需的 XML 输出分组和排序?

How do I produce the required XML output grouping and sorting by like source nodes?

鉴于此来源 XML:

<output>
   <report>
      <C01>
         <InvID>001</InvID>
         <Daily>
            <row id="0000">1</row>
            <row id="0001">2</row>
            <row id="0002">5</row>
            <row id="0003">4</row>
         </Daily>
      </C01>
      <C02>
         <InvID>002</InvID>
         <Daily>
            <row id="0000">4</row>
            <row id="0001">3</row>
            <row id="0002">2</row>
            <row id="0003">5</row>
         </Daily>
      </C02>
      <C03>
         <InvID>001</InvID>
         <Daily>
            <row id="0000">3</row>
            <row id="0001">7</row>
            <row id="0002">2</row>
            <row id="0003">4</row>
         </Daily>
      </C03>
   <report>
<output>

我怎样才能产生这个输出:

<Data invID=001>
   <Value>1</Value>
   <Value>2</Value>
   <Value>5</Value>
   <Value>4</Value>
   <Value>3</Value>
   <Value>7</Value>
   <Value>2</Value>
   <Value>4</Value>
</Data>
<Data invID=002>
   <Value>4</Value>
   <Value>3</Value>
   <Value>2</Value>
   <Value>5</Value>
</Data>

我一直在尝试用这样的东西作为基础,但是感觉都不对:

<xsl:template match="output/report">
   <xsl:for-each select="*[starts-with(name(), 'C') and InvID != '']">
      <xsl:sort select="InvID" />
      <xsl:element name="Data">
         <xsl:attribute name="invID">
            <xsl:value-of select="InvID" />
         </xsl:attribute>
      </xsl:element>
   </xsl:for-each>
</xsl:template>

我需要聚合共享一个公共 InvID 的所有项目,为该组源元素输出单个 Data 元素,然后输出它们的所有 row 元素值进入 Data 元素 (Value) 的子元素。

这可以在 XPath 1.0 中完成吗?

正如我在评论中所建议的那样,您正在寻找的技术称为 Muenchian 分组。这通过定义一个 key 将相关节点组合在一起,然后使用 generate-idcount 的技巧来构造一个由一个 "representative" 每个组的节点。在您的情况下,由于您要组合在一起的节点具有不同的名称,因此您必须对匹配模式更具创意,但原理是相同的:

<xsl:key name="groupByInv" match="*[InvID]" use="InvID" />

在这里,我对具有 InvID 子元素的任何元素(无论名称如何)感兴趣,我想根据 InvID 值将它们组合在一起。现在实际的分组很简单:

<xsl:template match="output/report">
  <xsl:for-each select="*[InvID][generate-id() =
         generate-id(key('groupByInv', InvID)[1])]">
    <Data invID="{InvID}">
      <!-- process all the rows under all the elements in the current group -->
      <xsl:apply-templates select="key('groupByInv', InvID)/Daily/row" />
    </Data>
  </xsl:for-each>
</xsl:template>

<xsl:template match="row">
  <Value><xsl:value-of select="."/></Value>
</xsl:template>