2

The HandlingUnitItem (/HandlingUnit/HandlingUnitItem/HandlingUnit/HandlingUnitItem) in the XML path getting repeated in the XML output. I'm not able to figure out why it was getting repeated in the Output.

I'm attaching the Input XML, XSLT code and the Output XML for your reference. exslt:node-set($Contents) what's this Content variable is holding?

Input xml :

<?xml version="1.0" encoding="UTF-8"?>
<SHPMNT05>
    <IDOC BEGIN="1">
        <E1EDT20 SEGMENT="1">
            <TKNUM>0001960714</TKNUM>
            <SHTYP>DEFC</SHTYP>
            <ABFER>1</ABFER>
            <ABWST>1</ABWST>
            <BFART>2</BFART>
            <E1EDL20 SEGMENT="1">
                <VBELN>0076668882</VBELN>
                <BTGEW>1.601</BTGEW>
                <NTGEW>1.584</NTGEW>
                <GEWEI>KGM</GEWEI>
                <E1EDL37 SEGMENT="1">
                    <EXIDV>00000000000109126078</EXIDV>
                    <TARAG>0.001</TARAG>
                    <GWEIT>KGM</GWEIT>
                    <BRGEW>0.001</BRGEW>
                    <NTGEW>0.000</NTGEW>
                    <GWEIM>KGM</GWEIM>
                    <VHILM>PM-3215</VHILM>
                    <LAENG>0.000</LAENG>
                    <BREIT>0.000</BREIT>
                    <HOEHE>0.000</HOEHE>
                    <VHILM_KU>KC2</VHILM_KU>
                    <VEBEZ>VDA-KLT R 3215</VEBEZ>
                    <SMGKN>S</SMGKN>
                    <E1EDL38 SEGMENT="1">
                        <MAGRV_BEZ>Ben</MAGRV_BEZ>
                        <VEBEZ>VDA</VEBEZ>
                    </E1EDL38>
                    <E1EDL44 SEGMENT="1">
                        <VELIN>1</VELIN>
                        <VBELN>0076668882</VBELN>
                        <POSNR>000010</POSNR>
                        <VEMNG>1600.000</VEMNG>
                        <VEMEH>PCE</VEMEH>
                        <MATNR>8993601404</MATNR>
                        <WERKS>DCXX</WERKS>
                        <LGORT>S002</LGORT>
                    </E1EDL44>
                </E1EDL37>
                <E1EDL37 SEGMENT="1">
                    <EXIDV>00000000000109126079</EXIDV>
                    <TARAG>0.000</TARAG>
                    <GWEIT>KGM</GWEIT>
                    <BRGEW>1.614</BRGEW>
                    <NTGEW>1.614</NTGEW>
                    <GWEIM>KGM</GWEIM>
                    <VHILM>PM-9999</VHILM>
                    <LAENG>0.000</LAENG>
                    <BREIT>0.000</BREIT>
                    <HOEHE>0.000</HOEHE>
                    <EXIDV2>040578630025545457</EXIDV2>
                    <VEBEZ>**********************</VEBEZ>
                    <SMGKN>M</SMGKN>
                    <E1EDL38 SEGMENT="1">
                        <VHART_BEZ>Palette</VHART_BEZ>
                        <MAGRV_BEZ>Ben</MAGRV_BEZ>
                        <VEBEZ>**********************</VEBEZ>
                    </E1EDL38>
                    <E1EDL44 SEGMENT="1">
                        <VELIN>3</VELIN>
                        <EXIDV>00000000000109126078</EXIDV>
                    </E1EDL44>
                </E1EDL37>
            </E1EDL20>
        </E1EDT20>
    </IDOC>
</SHPMNT05>

XSLT Code :

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" extension-element-prefixes="exslt">
    <xsl:template match="/">
        <xsl:choose>
            <xsl:when test="/*/IDOC/E1EDT20">
                <xsl:for-each select="/*/IDOC/E1EDT20|/*/IDOC[E1EDL20]">
                    <xsl:for-each select="E1EDL20/E1EDL37[not(EXIDV=/*/IDOC/E1EDT20/E1EDL20/E1EDL37/E1EDL44/EXIDV)]">
                        <xsl:sort select="EXIDV"/>
                        <xsl:value-of select="EXIDV"/>
                        <xsl:call-template name="HUTree"/>
                    </xsl:for-each>
                </xsl:for-each>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="HUTree">
        <HandlingUnit>
            <xsl:attribute name="key">
                <xsl:value-of select="concat(VHILM,VHILM_KU,SMGKN,LAENG,BREIT,HOEHE,BRGEW,NTGEW,GWEIM)"/>
                <xsl:for-each select="E1EDL44|E1EDT43">
                    <xsl:sort select="VELIN" order="descending"/>
                    <xsl:sort select="MATNR"/>
                    <xsl:value-of select="concat(VELIN,EXIDV,MATNR,VBELN,POSNR,VEMNG,VEMEH,KDMAT)"/>
                </xsl:for-each>
            </xsl:attribute>
            <xsl:copy-of select="EXIDV|VHILM|VHILM_KU|SMGKN|LAENG|BREIT|HOEHE|BRGEW|NTGEW|GWEIM"/>
            <xsl:variable name="Contents">
                <xsl:for-each select="E1EDL44|E1EDT43">
                    <xsl:sort select="VELIN" order="descending"/>
                    <xsl:sort select="MATNR"/>
                    <xsl:variable name="VBELN" select="VBELN"/>
                    <xsl:variable name="POSNR" select="POSNR"/>
                    <HandlingUnitItem>
                        <xsl:copy-of select="VELIN|MATNR|VBELN|POSNR|VEMNG|VEMEH|KDMAT"/>
                        <xsl:copy-of select="/*/IDOC/E1EDT20/E1EDL20[VBELN=$VBELN]/E1EDL24[POSNR=$POSNR]/E1EDL41[QUALI='001']/BSTNR"/>
                        <xsl:for-each select="../../E1EDL20/E1EDL37[EXIDV=current()/EXIDV] | ../../../E1EDL20/E1EDL37[EXIDV=current()/EXIDV]">
                            <xsl:sort select="EXIDV"/>
                            <xsl:call-template name="HUTree"/>
                        </xsl:for-each>
                    </HandlingUnitItem>
                </xsl:for-each>
            </xsl:variable>
            <xsl:copy-of select="$Contents"/>
            <xsl:for-each select="exslt:node-set($Contents)/HandlingUnitItem[not(HandlingUnit/@key=preceding-sibling::HandlingUnitItem/HandlingUnit/@key)]">
                <HandlingUnitItem>
                    <xsl:copy-of select="VELIN|MATNR|VBELN|POSNR|VEMNG|VEMEH|KDMAT|BSTNR"/>
                    <xsl:if test="HandlingUnit">
                        <HandlingUnit>
                            <xsl:variable name="str">
                                <xsl:for-each select=".|following-sibling::HandlingUnitItem[HandlingUnit/@key=current()/HandlingUnit/@key]">
                                    <xsl:if test="position()!=1 and HandlingUnit/EXIDV!=preceding-sibling::HandlingUnitItem[HandlingUnit/@key=current()/HandlingUnit/@key][1]/HandlingUnit/EXIDV+1">
                                        <xsl:value-of select="'|'"/>
                                    </xsl:if>
                                    <xsl:value-of select="concat(HandlingUnit/EXIDV,',')"/>
                                </xsl:for-each>
                            </xsl:variable>
                            <OutputStr>
                                <xsl:value-of select="$str"/>
                            </OutputStr>
                        </HandlingUnit>
                    </xsl:if>
                </HandlingUnitItem>
            </xsl:for-each>
        </HandlingUnit>
    </xsl:template>
</xsl:stylesheet>

Output xml :

<?xml version='1.0' encoding='UTF-8' ?>
00000000000109126079<HandlingUnit key="PM-9999M0.0000.0000.0001.6141.614KGM300000000000109126078">
    <EXIDV>00000000000109126079</EXIDV>
    <BRGEW>1.614</BRGEW>
    <NTGEW>1.614</NTGEW>
    <GWEIM>KGM</GWEIM>
    <VHILM>PM-9999</VHILM>
    <LAENG>0.000</LAENG>
    <BREIT>0.000</BREIT>
    <HOEHE>0.000</HOEHE>
    <SMGKN>M</SMGKN>
    <HandlingUnitItem>
        <VELIN>3</VELIN>
        <HandlingUnit key="PM-3215KC2S0.0000.0000.0000.0010.000KGM1899360140400766688820000101600.000PCE">
            <EXIDV>00000000000109126078</EXIDV>
            <BRGEW>0.001</BRGEW>
            <NTGEW>0.000</NTGEW>
            <GWEIM>KGM</GWEIM>
            <VHILM>PM-3215</VHILM>
            <LAENG>0.000</LAENG>
            <BREIT>0.000</BREIT>
            <HOEHE>0.000</HOEHE>
            <VHILM_KU>KC2</VHILM_KU>
            <SMGKN>S</SMGKN>
            <HandlingUnitItem>
                <VELIN>1</VELIN>
                <VBELN>0076668882</VBELN>
                <POSNR>000010</POSNR>
                <VEMNG>1600.000</VEMNG>
                <VEMEH>PCE</VEMEH>
                <MATNR>8993601404</MATNR>
                <BSTNR>0057328890010</BSTNR>
            </HandlingUnitItem>
            <HandlingUnitItem>
                <VELIN>1</VELIN>
                <VBELN>0076668882</VBELN>
                <POSNR>000010</POSNR>
                <VEMNG>1600.000</VEMNG>
                <VEMEH>PCE</VEMEH>
                <MATNR>8993601404</MATNR>
                <BSTNR>0057328890010</BSTNR>
            </HandlingUnitItem>
        </HandlingUnit>
    </HandlingUnitItem>
    <HandlingUnitItem>
        <VELIN>3</VELIN>
        <HandlingUnit>
            <OutputStr>00000000000109126078,</OutputStr>
        </HandlingUnit>
    </HandlingUnitItem>
</HandlingUnit>
6
  • 1
    Please reduce the code examples to the minimum required to demonstrate the problem ( see: minimal reproducible example) and add the expected result. Commented Dec 19, 2024 at 13:48
  • 3
    When your code samples need scrolling to view them, you greatly reduce the chance that anyone is prepared to make the effort. Especially when the code is full of cryptic element names like GWEIM and VHILM. Simplifying the problem to its bare essentials not only means you're more likely to get an answer: very often it means you will find the answer yourself in the process. Commented Dec 19, 2024 at 14:43
  • Hi @MichaelKay This is not the complete XSLT code, I've only posted a part of it. It involves recursive template call, and an xml is created inside the HUTree template. The variable $Contents is defined to hold <HandlingUnitItem> elements and while displaying the output of that variable, duplicate <HandlingUnitItem> tags appear in the output xml. Commented Dec 24, 2024 at 7:02
  • 1
    Thanks for the extra information, but I'm not motivated to help you with this problem. I would happily do so if you made the effort to simplify it and make a complete but minimal reproducible example. Commented Dec 27, 2024 at 20:19
  • Why can't you add temporary code to display the value of the variable in your output? Commented Jan 1 at 6:50

1 Answer 1

0

Please confirm whether this simplified example captures what you want to achieve:

  • Flatten a recursive node structure into a node list. (Done by the <xsl:template match="a">, the output is collected into $flat.)
  • From that list, keep only the first node with a given key. (key('key', ...) returns the first node with a given key, generate-id is used to check whether this is the current node.)
<a key="1">
  <a key="2">
    <a key="1" />
  </a>
</a>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common">
  <xsl:key name="key" match="a" use="@key" />
  <xsl:template match="/">
    <xsl:variable name="flat">
      <xsl:apply-templates select="a" />
    </xsl:variable>
    <flat>
      <xsl:for-each
        select="exslt:node-set($flat)/a[generate-id()=generate-id(key('key',@key))]">
        <a key="{@key}" />
      </xsl:for-each>
    </flat>
  </xsl:template>
  <xsl:template match="a">
    <a key="{@key}" /> <!-- Your key attribute is more complex -->
    <xsl:apply-templates select="a" />
  </xsl:template>
</xsl:stylesheet>

The condition with key and generate-id is not only faster than preceding-sibling::*, it works even without storing the flattened list in a variable:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="key" match="a" use="@key" />
  <xsl:template match="/">
    <flat>
      <xsl:apply-templates select="a" />
    </flat>
  </xsl:template>
  <xsl:template match="a">
    <xsl:if test="generate-id()=generate-id(key('key',@key))">
      <a key="{@key}" />
    </xsl:if>
    <xsl:apply-templates select="a" />
  </xsl:template>
</xsl:stylesheet>

(This last trick may not be applicable to your case, because your key attribute is computed from many key properties. Or is it? Many properties that make up your key are in fact measures like weight or height, I cannot imagine that these are really key components.)

Sign up to request clarification or add additional context in comments.

2 Comments

Hi Heiko, Thanks for your reply! It’s not about the end result that I’m concerned about here, I’m more focused on understanding why the <HandlingUnitItem> tag is being duplicated in the output. When I run the code upto <xsl:copy-of select="$Contents"/>, I don’t get the duplicate tag. However, when I add the <xsl:for-each> with the preceding-sibling predicate, the duplicate appears in the output.
The duplicate is caused by the <xsl:copy-of select="$Contents"/> followed by the <xsl:for-each ...>. This is easier to see if you wrap the former as <copy><xsl:copy-of select="$Contents"/></copy>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.