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

时间:2015-02-10 18:31:49

标签: xml xslt xpath-1.0

鉴于此源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中完成吗?

1 个答案:

答案 0 :(得分:1)

正如我在评论中建议的那样,您正在寻找的技术称为 Muenchian分组。这可以通过定义将相关节点组合在一起的,然后使用generate-idcount的技巧构建一个由一个&#34;代表&#34组成的节点集。 ;每个组的节点。在您的情况下,由于您要组合在一起的节点具有不同的名称,因此您必须对匹配模式更具创造性,但原则是相同的:

<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>