I have a xml where I want to:
filter out E1EDL20 (deliveries) where the E1EDL24\LGORT = 1033 or 1035
If there are no E1EDl24 elements left after the filtering I want to suppress remove the E1EDL20
If there are no E1EDL20 elements left I want to suppress / remove the CMR element
If there are no CMR elements left I want to suppress / remove the STOP element
…
up to If there is no STOP I don’t want anything at all (write 0 kb in SAP PO).
LINK: https://xsltfiddle.liberty-development.net/jyH7UCe/5
Input xml
<SHPMNT05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20>
<TKNUM>0000303246</TKNUM>
<STOP>
<ABLAD>1</ABLAD>
<CMR>
<E1EDL20 SEGMENT="1">
<VBELN>0082051477</VBELN>
<ABLAD>1</ABLAD>
<E1EDL24 SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000000032183</MATNR>
<MATWA>000000000000032183</MATWA>
<ARKTX>Plaat multiplex populieren 9mm 244X122cm</ARKTX>
<LGORT>1033</LGORT>
<LFIMG>1.000</LFIMG>
</E1EDL24>
<E1EDL24 SEGMENT="1">
<POSNR>000020</POSNR>
<MATNR>000000000000056163</MATNR>
<MATWA>000000000000056163</MATWA>
<ARKTX>Werkblad spaanplaat 29mm wit 60x302cm</ARKTX>
<LGORT>1066</LGORT>
<LFIMG>1.000</LFIMG>
</E1EDL24>
</E1EDL20>
<E1EDL20 SEGMENT="1">
<VBELN>0082051417</VBELN>
<ABLAD>1</ABLAD>
<E1EDL24 SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000000032183</MATNR>
<MATWA>000000000000032183</MATWA>
<ARKTX>Plaat multiplex populieren 9mm 244X122cm</ARKTX>
<LGORT>1038</LGORT>
<LFIMG>1.000</LFIMG>
</E1EDL24>
<E1EDL24 SEGMENT="1">
<POSNR>000020</POSNR>
<MATNR>000000000000056163</MATNR>
<MATWA>000000000000056163</MATWA>
<ARKTX>Werkblad spaanplaat 29mm wit 60x302cm</ARKTX>
<LGORT>1066</LGORT>
<LFIMG>1.000</LFIMG>
</E1EDL24>
</E1EDL20>
</CMR>
</STOP>
<STOP>
<ABLAD>2</ABLAD>
<CMR>
<E1EDL20 SEGMENT="1">
<VBELN>0082051282</VBELN>
<ABLAD>2</ABLAD>
<E1EDL24 SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000000036417</MATNR>
<MATWA>000000000000036417</MATWA>
<ARKTX>Plaat MDF 4mm 244X122cm</ARKTX>
<LGORT>1038</LGORT>
<LFIMG>5.000</LFIMG>
</E1EDL24>
<E1EDL24 SEGMENT="1">
<POSNR>000020</POSNR>
<MATNR>000000000000036426</MATNR>
<MATWA>000000000000036426</MATWA>
<ARKTX>Plaat MDF 16mm 244X122cm</ARKTX>
<LGORT>1031</LGORT>
<LFIMG>5.000</LFIMG>
</E1EDL24>
<E1EDL24 SEGMENT="1">
<POSNR>000030</POSNR>
<MATNR>000000000000036150</MATNR>
<MATWA>000000000000036150</MATWA>
<ARKTX>Multiplex hardhout 3,6mm 122X61cm</ARKTX>
<LGORT>1031</LGORT>
<LFIMG>4.000</LFIMG>
</E1EDL24>
</E1EDL20>
</CMR>
</STOP>
</E1EDT20>
</IDOC>
XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Remove whitespace -->
<xsl:strip-space elements="*"/>
<!-- Keep indentation -->
<xsl:output method="xml" indent="yes"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- suppress E1EDL24 where LGORT is not 1033 or 1035 -->
<xsl:template match="E1EDL24[not(LGORT='1033' or LGORT='1035')]"/>
<!-- suppress E1EDL20 if E1EDL24 count is 0 -->
<xsl:template match="E1EDL20[count(E1EDL24[LGORT='1033' or LGORT='1035'])=0]"/>
<!-- Remove CMR if there are no E1EDL20 elements -->
<xsl:template match="CMR[not(E1EDL20)]"/>
<!-- Remove STOP if there are no E1EDL20 elements -->
<xsl:template match="STOP[not(CMR/E1EDL20)]"/>
</xsl:stylesheet>
Current result
<?xml version="1.0" encoding="UTF-8"?>
<SHPMNT05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20>
<TKNUM>0000303246</TKNUM>
<STOP>
<ABLAD>1</ABLAD>
<CMR>
<E1EDL20 SEGMENT="1">
<VBELN>0082051477</VBELN>
<ABLAD>1</ABLAD>
<E1EDL24 SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000000032183</MATNR>
<MATWA>000000000000032183</MATWA>
<ARKTX>Plaat multiplex populieren 9mm 244X122cm</ARKTX>
<LGORT>1033</LGORT>
<LFIMG>1.000</LFIMG>
</E1EDL24>
</E1EDL20>
</CMR>
</STOP>
<STOP>
<ABLAD>2</ABLAD>
<CMR/>
</STOP>
</E1EDT20>
</IDOC>
</SHPMNT05>
I can’t get it to work because when I reach the CMR
<xsl:template match="CMR[not(E1EDL20)]"/>
I’m stuck with an empty </CMR> element?!
What is causing this because the 2nd CMR element doesn’t have any E1EDL20 elements left?
And knowing myself it could well be it’s much easier to reach my goal with less code?
Regards,
Mike
>Solution :
Use a pipeline e.g.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Remove whitespace -->
<xsl:strip-space elements="*"/>
<!-- Keep indentation -->
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="step1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="step2">
<xsl:apply-templates select="$step1/node()"/>
</xsl:variable>
<xsl:variable name="step3">
<xsl:apply-templates select="$step2/node()"/>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="$step3/node()"/>
</xsl:template>
<!-- identity transform -->
<xsl:template match="@*|node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<!-- suppress E1EDL24 where LGORT is not 1033 or 1035 -->
<xsl:template match="E1EDL24[not(LGORT='1033' or LGORT='1035')]"/>
<!-- suppress E1EDL20 if E1EDL24 count is 0 -->
<xsl:template match="E1EDL20[count(E1EDL24[LGORT='1033' or LGORT='1035'])=0]"/>
<!-- Remove CMR if there are no E1EDL20 elements -->
<xsl:template match="CMR[not(E1EDL20)]"/>
<!-- Remove STOP if there are no E1EDL20 elements -->
<xsl:template match="STOP[not(CMR/E1EDL20)]"/>
</xsl:stylesheet>
I am not sure I have enough steps for all requirements and in the end it is safer and cleaner to use different modes for the different steps but for the example I hope it suffices to use a single mode.
In theory (and with XSLT 3 supported) it might also be possible to throw in some xsl:where-populated but it mainly works with completely empty elements and given there seems to be stuff like ABLAD that is not removed I am currently not sure whether it is a feasible idea to use xsl:where-populated and that way avoid pipeline steps.