XSLT2.0:如何使用嵌套的 for-each-group 压缩 xml 记录

XSLT2.0: How to use nested for-each-group to compress xml records

我正在尝试将嵌套的 for-each-group 和 for-each 与 current-group() 结合使用,以基于两个键将类似数据压缩到一个 xml 记录中。第一个键是 ID,第二个键是 Inv_Link

我得到了外循环的预期结果,但是当我使用 //Record 时,我得到了内循环的预期结果,我得到了每个结果中的所有键,带有 .我只得到第一个数据元素。在父键中获取所有嵌套键的正确选择器是什么?

感谢您的帮助!

XML数据集

<Data>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE2</Link>
        <Component_ID>DEBT</Component_ID>
        <Amt>1500</Amt>
    </Record>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE1</Link>
        <Component_ID>EQT</Component_ID>
        <Amt>200</Amt>
    </Record>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE1</Link>
        <Component_ID>CASH</Component_ID>
        <Amt>100</Amt>
    </Record>
    <Record>
        <ID>01_2020</ID>
        <Link>ICE3</Link>
        <Component_ID>CASH</Component_ID>
        <Amt>100</Amt>
    </Record>
</Data>

我现在使用的 XSLT:

   <xsl:template match="Data">
        <xsl:for-each-group select="Record" group-by="ID">
        <xsl:for-each select="current-group()">
          <Record>
            <groupkey><xsl:value-of select="current-grouping-key()"/></groupkey>
            <AssetEvent>
                <ID> <xsl:copy> <xsl:value-of select="ID/text()" /> </xsl:copy> </ID>
                <DecompositionSequence>
                    <xsl:for-each-group select="Record" group-by="Link">
                    <groupkey><xsl:value-of select="current-grouping-key()"/></groupkey>
                    <xsl:for-each select="current-group()">
                        <Decompositions>
                            <Link> 
                              <ID><xsl:copy><xsl:value-of select="Link/text()" /> </xsl:copy> <ID> 
                            </Link>
                            <DecompositionDataSequence>
                                <DecompositionData>
                                    <Component>
                                        <ID> <xsl:copy> <xsl:value-of select="Component_ID/text()" /> </xsl:copy> </ID> 
                                    </Component>
                                    <Amt> <xsl:copy> <xsl:value-of select="Amt/text()" /> </xsl:copy> </Amt>
                                </DecompositionData>
                            </DecompositionDataSequence>
                        </Decompositions>   
                    </xsl:for-each>
                    </xsl:for-each-group>
              </DecompositionSequence>
            </AssetEvent>
          </Record>
        </xsl:for-each>
        </xsl:for-each-group>
  </xsl:template>

当前结果,我总共得到 2 条记录,但有 none 个内部分组(如果我使用 //Record,那么我得到两个结果记录的全部):

    <Record>
      <groupkey>ICE 01_2019</groupkey>
      <AssetEvent>
        <ID>ICE 01_2019</ID>
        <DecompositionSequence />
      </AssetEvent>
    </Record>
    <Record>
      <groupkey>01_2020</groupkey>
      <AssetEvent>
        <ID>01_2020</ID>
        <DecompositionSequence />
      </AssetEvent>
    </Record>


我期待的是:

    <Record>
      <groupkey>01_2019</groupkey>
      <AssetEvent>
        <ID>01_2019</ID>
        <DecompositionSequence>
          <groupkey>ICE2</groupkey>
          <Decompositions>
            <InvestmentLink>ICE2</InvestmentLink>
            <DecompositionDataSequence>
              <DecompositionData>
                <Component>
                  <ID>DEBT</ID>
                </Component>
                <Amt>150</Amt>
              </DecompositionData>
            </DecompositionDataSequence>
          </Decompositions>
          <groupkey>ICE1</groupkey>
          <Decompositions>
            <InvestmentLink>ICE1</InvestmentLink>
            <DecompositionDataSequence>
              <DecompositionData>
                <Component>
                  <ID>EQT</ID>
                </Component>
                <Amt>150</Amt>
              </DecompositionData>
              <DecompositionData>
                <Component>
                  <ID>CASH</ID>
                </Component>
                <Amt>150</Amt>
              </DecompositionData>
            </DecompositionDataSequence>
          </Decompositions>
        </DecompositionSequence>
      </AssetEvent>
    </Record>
    <Record>
      <groupkey>01_2020</groupkey>
      <AssetEvent>
        <ID>01_2020</ID>
        <DecompositionSequence>
          <groupkey>ICE3</groupkey>
          <Decompositions>
            <InvestmentLink>ICE3</InvestmentLink>
            <DecompositionDataSequence>
              <DecompositionData>
                <Component>
                  <ID>CASH</ID>
                </Component>
                <Amt>100</Amt>
              </DecompositionData>
            </DecompositionDataSequence>
          </Decompositions>
        </DecompositionSequence>
      </AssetEvent>
    </Record>

假设你的输入样本是

<Data>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE2</Link>
        <Component_ID>DEBT</Component_ID>
        <Amt>1500</Amt>
    </Record>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE1</Link>
        <Component_ID>EQT</Component_ID>
        <Amt>200</Amt>
    </Record>
    <Record>
        <ID>01_2019</ID>
        <Link>ICE1</Link>
        <Component_ID>CASH</Component_ID>
        <Amt>100</Amt>
    </Record>
    <Record>
        <ID>01_2020</ID>
        <Link>ICE3</Link>
        <Component_ID>CASH</Component_ID>
        <Amt>100</Amt>
    </Record>
</Data>

然后是代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>

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

  <xsl:template match="Data">
    <xsl:for-each-group select="Record" group-by="ID">
        <xsl:copy>
            <groupkey>
                <xsl:value-of select="current-grouping-key()"/>
            </groupkey>
            <AssetEvent>
                <xsl:copy-of select="ID"/>
                <DecompositionSequence>
                  <xsl:for-each-group select="current-group()" group-by="Link">
                      <groupkey>
                          <xsl:value-of select="current-grouping-key()"/>
                      </groupkey>
                      <Decompositions>
                          <InvestmentLink>
                              <xsl:value-of select="current-grouping-key()"/>
                          </InvestmentLink>
                          <DecompositionDataSequence>
                              <xsl:apply-templates select="current-group()"/>
                          </DecompositionDataSequence>
                      </Decompositions>
                  </xsl:for-each-group>
                </DecompositionSequence>
            </AssetEvent>

        </xsl:copy>
      </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="Record">
        <DecompositionData>
            <xsl:apply-templates select="* except (ID, Link)"/>
        </DecompositionData>
    </xsl:template>

    <xsl:template match="Component_ID">
        <Component>
            <ID>
                <xsl:value-of select="."/>
            </ID>
        </Component>
    </xsl:template>

</xsl:stylesheet>

给出输出

<?xml version="1.0" encoding="UTF-8"?>
<Record>
   <groupkey>01_2019</groupkey>
   <AssetEvent>
      <ID>01_2019</ID>
      <DecompositionSequence>
         <groupkey>ICE2</groupkey>
         <Decompositions>
            <InvestmentLink>ICE2</InvestmentLink>
            <DecompositionDataSequence>
               <DecompositionData>
                  <Component>
                     <ID>DEBT</ID>
                  </Component>
                  <Amt>1500</Amt>
               </DecompositionData>
            </DecompositionDataSequence>
         </Decompositions>
         <groupkey>ICE1</groupkey>
         <Decompositions>
            <InvestmentLink>ICE1</InvestmentLink>
            <DecompositionDataSequence>
               <DecompositionData>
                  <Component>
                     <ID>EQT</ID>
                  </Component>
                  <Amt>200</Amt>
               </DecompositionData>
               <DecompositionData>
                  <Component>
                     <ID>CASH</ID>
                  </Component>
                  <Amt>100</Amt>
               </DecompositionData>
            </DecompositionDataSequence>
         </Decompositions>
      </DecompositionSequence>
   </AssetEvent>
</Record>
<Record>
   <groupkey>01_2020</groupkey>
   <AssetEvent>
      <ID>01_2020</ID>
      <DecompositionSequence>
         <groupkey>ICE3</groupkey>
         <Decompositions>
            <InvestmentLink>ICE3</InvestmentLink>
            <DecompositionDataSequence>
               <DecompositionData>
                  <Component>
                     <ID>CASH</ID>
                  </Component>
                  <Amt>100</Amt>
               </DecompositionData>
            </DecompositionDataSequence>
         </Decompositions>
      </DecompositionSequence>
   </AssetEvent>
</Record>

它使用 XSLT 3 声明 <xsl:mode on-no-match="shallow-copy"/> 但如果您使用 XSLT 2 处理器,您可以将其替换为身份转换模板。