-1

input data: below is the input data getting from the source. how we can achieve through XSLT mapping SCPI, Thanks in advance, and looking forward to your response. I have the following problem (which is quite often discussed in this domain but still I can't get the exact solution): I have an XML like the following:

         <orderHeader>
            <distributionChannelCode>10</distributionChannelCode>
            <orderItem>
                <productCode>AQ7481-002-001</productCode>
            </orderItem>
              <orderItem>
                <productCode>AQ7481-002-004</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-001</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-002</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-004</productCode>
            </orderItem>
             <orderItem>
                <productCode>AQ7481-002-002</productCode>
            </orderItem>
        </orderHeader>

Required Output:

<orderHeader>
            <distributionChannelCode>10</distributionChannelCode>
            <orderItem>
                <productCode>AQ7481-002-001</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-002</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
            <orderItem>
                <productCode>AQ7481-002-004</productCode>
            </orderItem>
        </orderHeader>  
        <orderHeader>
            <distributionChannelCode>10</distributionChannelCode>
            <orderItem>
                <productCode>AQ7481-002-001</productCode>
            </orderItem>
             <orderItem>
                <productCode>AQ7481-002-002</productCode>
            </orderItem>
             <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
        </orderHeader>
        <orderHeader>
            <distributionChannelCode>10</distributionChannelCode>
             <orderItem>
                <productCode>AQ7481-002-003</productCode>
            </orderItem>
        </orderHeader>

1 Answers1

0

I am not sure I have understood the logic but perhaps the following which groups orderItems by productCode to establish which group has the most items and then outputs as many orderHeaders with the corresponding item from each group does the job:

<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:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="orderHeader">
      <xsl:variable name="groups" as="map(xs:string, element(orderItem)*)*">
          <xsl:for-each-group select="orderItem" group-by="string(productCode)">
              <xsl:map-entry key="current-grouping-key()" select="current-group()"/>
          </xsl:for-each-group>
      </xsl:variable>
      <xsl:variable name="this" select="."/>
      <xsl:variable name="max-items" select="max($groups!count(?*))"/>
      <xsl:iterate select="1 to $max-items">
          <orderHeader>
              <xsl:copy-of 
                select="$this/distributionChannelCode, 
                        $groups ! ?*[current()]"/>
          </orderHeader>
      </xsl:iterate>
  </xsl:template>
  
</xsl:stylesheet>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thank you so much :), Martin. The code is working fine but could you please provide same code in the XSLT 2.0 -- because I am familiar with version 2.0 and I am very new to version 3.0. It would be very grateful to me – srikanth boda Mar 25 '21 at 13:04
  • Well, there is documentation and training material like https://www.altova.com/training/xpath3/xpath-31#maps, https://www.w3.org/TR/xslt-30/#iterate, https://www.w3.org/TR/xpath-31/#id-maps. I didn't use XSLT 3 features to complicate things, the issue is just easier if you can store the groups in a sequence of maps and process that further. – Martin Honnen Mar 25 '21 at 13:15
  • I tried this logic from last week at last you did. Thank you so much for your quick response.. – srikanth boda Mar 26 '21 at 05:34
  • Hello martin, the above code is not working if the values are coming like A123-100-200 . Can you please reply . How we can achive this – srikanth boda Apr 02 '21 at 12:09
  • @srikanthboda,ask a new question with a minimal but complete input sample, the wanted result, the code you have tried and the wrong result you get. – Martin Honnen Apr 02 '21 at 12:20
  • Sorry, Thank you.. Give me 5min, please .. I will edit this – srikanth boda Apr 02 '21 at 12:24
  • Hai Martin -- I have edited the input and output structure.. Can you please check once and I need sorted output also .. product value is a combination of strings, numerics and - so product sample values lik A123B-100-001 and CD345-200-300. – srikanth boda Apr 02 '21 at 12:33
  • @srikanthboda, please don't change your question after having accepted an answer. Perhaps using adding `` as the first child inside the `xsl:for-each-group` suffices but you haven't really explained the logic. – Martin Honnen Apr 02 '21 at 14:27