Merge XML nodes based on Certain Key Value using XSLT

浪尽此生 提交于 2020-01-06 05:52:06

问题


Merge XML nodes based on ReferenceNumber Value

How to merge the xml request to the output given below using XSLT based on the Key value. Basically the xml response has to be merged for ReferenceNumber, along with the respective ProductCode and SecondaryDivision. Below is the Request and the Expected response.

I tried Using following XSLT but it did not gave desired result.

Below is the XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="refNo" match="Envelope/Body/DocumentMetadataResponse" use="ReferenceNumber" />
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Envelope/Body/DocumentMetadataResponse/DocumentMetadata" />
    <xsl:template match="Envelope/Body/DocumentMetadataResponse/DocumentMetadata[generate-id()=generate-id(key('refNo', DocumentMetadata/ReferenceNumber))]">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="DocumentMetadata">
        <xsl:copy>
            <xsl:apply-templates select="@*|ReferenceNumber" />
            <divisionses>
                <xsl:apply-templates select="key('refNo', ReferenceNumber)/DocumentMetadata" mode="divisions" />
            </divisionses>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="DocumentMetadata" mode="divisions">
        <Divisions>
            <xsl:apply-templates select="*[not(self::ReferenceNumber)]" />
        </Divisions>
    </xsl:template>
</xsl:stylesheet>

Input XML

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:DocumentMetadataResponse xmlns:ns2="http://www.example.com/mService">
         <PageNumber>1</PageNumber>
         <PageSize>1000</PageSize>
         <TotalDocumentsAvailable>4919</TotalDocumentsAvailable>
         <DocumentMetadata>
            <ReferenceNumber>Ref-01</ReferenceNumber>
            <SecondaryDivision>AT</SecondaryDivision>
            <ProductCode>Product-AT-01</ProductCode>
         </DocumentMetadata>
         <DocumentMetadata>
            <ReferenceNumber>Ref-01</ReferenceNumber>
            <SecondaryDivision>AT</SecondaryDivision>
            <ProductCode>Product-AT-02</ProductCode>
         </DocumentMetadata>
         <DocumentMetadata>
            <ReferenceNumber>Ref-01</ReferenceNumber>
            <SecondaryDivision>BE</SecondaryDivision>
            <ProductCode>Product-BE-01</ProductCode>
         </DocumentMetadata>
         <DocumentMetadata>
            <ReferenceNumber>Ref-02</ReferenceNumber>
            <SecondaryDivision>BS</SecondaryDivision>
            <ProductCode>Product-BS-01</ProductCode>
         </DocumentMetadata>
      </ns2:DocumentMetadataResponse>
   </soap:Body>
</soap:Envelope>

Expected Output XML

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:DocumentMetadataResponse xmlns:ns2="http://www.example.com/mService">
         <PageNumber>1</PageNumber>
         <PageSize>1000</PageSize>
         <TotalDocumentsAvailable>4919</TotalDocumentsAvailable>
         <DocumentMetadata>
            <ReferenceNumber>Ref-01</ReferenceNumber>
            <Divisions>
               <Division>
                  <SecondaryDivision>AT</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-AT-01</ProductCode>
                     </Product>
                     <Product>
                        <ProductCode>Product-AT-02</ProductCode>
                     </Product>
                  </Products>
               </Division>
               <Division>
                  <SecondaryDivision>BE</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-BE-01</ProductCode>
                     </Product>
                  </Products>
               </Division>
            </Divisions>
         </DocumentMetadata>
         <DocumentMetadata>
            <ReferenceNumber>Ref-02</ReferenceNumber>
            <Divisions>
               <Division>
                  <SecondaryDivision>BS</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-BS-01</ProductCode>
                     </Product>
                  </Products>
               </Division>
            </Divisions>
         </DocumentMetadata>
      </ns2:DocumentMetadataResponse>
   </soap:Body>
</soap:Envelope>

回答1:


You can use this XSLT-2.0 template to do the job. xsl:for-each-group performs the two levels of grouping:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns2="http://www.example.com/mService">
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ns2:DocumentMetadataResponse ">
        <xsl:copy>
            <xsl:apply-templates select="@*|* except DocumentMetadata" />
            <xsl:for-each-group select="DocumentMetadata" group-by="ReferenceNumber">
                <DocumentMetadata>
                    <ReferenceNumber><xsl:value-of select="current-grouping-key()" /></ReferenceNumber>
                    <Divisions>
                        <xsl:for-each-group select="current-group()" group-by="SecondaryDivision">
                            <Division>
                                <SecondaryDivision><xsl:value-of select="current-grouping-key()" /></SecondaryDivision>
                                <Products>
                                    <xsl:for-each select="current-group()">
                                        <Product>
                                            <ProductCode><xsl:value-of select="ProductCode" /></ProductCode>
                                        </Product>
                                    </xsl:for-each>
                                </Products>
                            </Division>
                        </xsl:for-each-group>
                    </Divisions>
                </DocumentMetadata>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Output is:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:DocumentMetadataResponse xmlns:ns2="http://www.example.com/mService">
         <PageNumber>1</PageNumber>
         <PageSize>1000</PageSize>
         <TotalDocumentsAvailable>4919</TotalDocumentsAvailable>
         <DocumentMetadata>
            <ReferenceNumber>Ref-01</ReferenceNumber>
            <Divisions>
               <Division>
                  <SecondaryDivision>AT</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-AT-01</ProductCode>
                     </Product>
                     <Product>
                        <ProductCode>Product-AT-02</ProductCode>
                     </Product>
                  </Products>
               </Division>
               <Division>
                  <SecondaryDivision>BE</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-BE-01</ProductCode>
                     </Product>
                  </Products>
               </Division>
            </Divisions>
         </DocumentMetadata>
         <DocumentMetadata>
            <ReferenceNumber>Ref-02</ReferenceNumber>
            <Divisions>
               <Division>
                  <SecondaryDivision>BS</SecondaryDivision>
                  <Products>
                     <Product>
                        <ProductCode>Product-BS-01</ProductCode>
                     </Product>
                  </Products>
               </Division>
            </Divisions>
         </DocumentMetadata>
      </ns2:DocumentMetadataResponse>
   </soap:Body>
</soap:Envelope>


来源:https://stackoverflow.com/questions/58140104/merge-xml-nodes-based-on-certain-key-value-using-xslt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!