I have 3 xsl transformations which, when run seperatedly, work fine but I'd like all 3 in one xsl for simplicity.
Input xml:
<?xml version="1.0" encoding="UTF-8"?>
<SHPMNT05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20 SEGMENT="1">
<TKNUM>0000287203</TKNUM>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>1</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018666</VBELN>
</E1EDT01>
<E1EDT01 SEGMENT="1">
<VBELN>0081018667</VBELN>
</E1EDT01>
<E1EDT01 SEGMENT="1">
<VBELN>0081018668</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>2</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018666</VBELN>
</E1EDT01>
<E1EDT01 SEGMENT="1">
<VBELN>0081018668</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>3</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018666</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDL20 SEGMENT="1">
<VBELN>0081018666</VBELN>
</E1EDL20>
<E1EDL20 SEGMENT="1">
<VBELN>0081018667</VBELN>
</E1EDL20>
<E1EDL20 SEGMENT="1">
<VBELN>0081018668</VBELN>
</E1EDL20>
</E1EDT20>
</IDOC>
</SHPMNT05>
Required result:
<?xml version="1.0" encoding="UTF-8"?>
<SHPMNT05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
</EDI_DC40>
<E1EDT20 SEGMENT="1">
<TKNUM>0000287203</TKNUM>
<E1EDK33 SEGMENT="1">
<TSNUM>0001</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>1</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018667</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>2</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018668</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDK33 SEGMENT="1">
<TSNUM>0002</TSNUM>
<E1EDT44 SEGMENT="1">
<QUALI>001</QUALI>
</E1EDT44>
<E1EDT44 SEGMENT="1">
<QUALI>002</QUALI>
<ABLAD>3</ABLAD>
</E1EDT44>
<E1EDT01 SEGMENT="1">
<VBELN>0081018666</VBELN>
</E1EDT01>
</E1EDK33>
<E1EDL20 SEGMENT="1">
<VBELN>0081018667</VBELN>
<ABLAD>1</ABLAD>
</E1EDL20>
<E1EDL20 SEGMENT="1">
<VBELN>0081018668</VBELN>
<ABLAD>2</ABLAD>
</E1EDL20>
<E1EDL20 SEGMENT="1">
<VBELN>0081018666</VBELN>
<ABLAD>3</ABLAD>
</E1EDL20>
</E1EDT20>
</IDOC>
</SHPMNT05>
Steps
Step 1: Filter out the VBELN elements if they exist in the next sibling
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHPMNT05/IDOC/E1EDT20/E1EDK33/E1EDT01[(VBELN= following-sibling::E1EDT01/VBELN) or (VBELN= ../following-sibling::E1EDK33/E1EDT01/VBELN)]"/>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
Step 2: Use the ABLAD values of the E1EDK33/E1EDT01 elements and add an extra ABLAD element to E1EDL20
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHPMNT05/IDOC/E1EDT20/E1EDL20/VBELN">
<xsl:copy-of select="."/>
<xsl:variable name="stopno" select="/SHPMNT05/IDOC/E1EDT20/E1EDK33[E1EDT01/VBELN=current()]/E1EDT44/ABLAD"/>
<ABLAD><xsl:value-of select="$stopno" /></ABLAD>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
Step 3: Sort the E1EDL20 elements on the in step 2 newly created E1EDL20\ABLAD elements
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="E1EDT20">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each select="*[not(self::E1EDL20)]">
<xsl:copy-of select="."/>
</xsl:for-each>
<xsl:for-each select="E1EDL20">
<xsl:sort select="ABLAD" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- Default Template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Hope I made myself clear / this is possible :)
Best regards, Mike
Chaining using fold-left
and transform
(XPath 3.1, XQuery 3.1):
let $xslt1 := document {
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHPMNT05/IDOC/E1EDT20/E1EDK33/E1EDT01[(VBELN= following-sibling::E1EDT01/VBELN) or (VBELN= ../following-sibling::E1EDK33/E1EDT01/VBELN)]"/>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
},
$xslt2 := document {
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHPMNT05/IDOC/E1EDT20/E1EDL20/VBELN">
<xsl:copy-of select="."/>
<xsl:variable name="stopno" select="/SHPMNT05/IDOC/E1EDT20/E1EDK33[E1EDT01/VBELN=current()]/E1EDT44/ABLAD"/>
<ABLAD><xsl:value-of select="$stopno" /></ABLAD>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
},
$xslt3 := document {
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="E1EDT20">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each select="*[not(self::E1EDL20)]">
<xsl:copy-of select="."/>
</xsl:for-each>
<xsl:for-each select="E1EDL20">
<xsl:sort select="ABLAD" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- Default Template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
},
$xslts := ($xslt1, $xslt2, $xslt3)
return
fold-left(
$xslts,
.,
function($xml, $xslt) {
transform(
map {
'source-node' : $xml,
'stylesheet-node' : $xslt
}
)?output
}
)
Using three transformation steps with three modes in one XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*" mode="#all">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="step1">
<xsl:apply-templates mode="step1"/>
</xsl:variable>
<xsl:template mode="step1" match="/SHPMNT05/IDOC/E1EDT20/E1EDK33/E1EDT01[(VBELN= following-sibling::E1EDT01/VBELN) or (VBELN= ../following-sibling::E1EDK33/E1EDT01/VBELN)]"/>
<xsl:template mode="step1" match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
<xsl:variable name="step2">
<xsl:apply-templates select="$step1/node()" mode="step2"/>
</xsl:variable>
<xsl:template mode="step2" match="/SHPMNT05/IDOC/E1EDT20/E1EDL20/VBELN">
<xsl:copy-of select="."/>
<xsl:variable name="stopno" select="/SHPMNT05/IDOC/E1EDT20/E1EDK33[E1EDT01/VBELN=current()]/E1EDT44/ABLAD"/>
<ABLAD><xsl:value-of select="$stopno" /></ABLAD>
</xsl:template>
<xsl:template mode="step2" match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$step2/node()" mode="step3"/>
</xsl:template>
<xsl:template mode="step3" match="E1EDT20">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each select="*[not(self::E1EDL20)]">
<xsl:copy-of select="."/>
</xsl:for-each>
<xsl:for-each select="E1EDL20">
<xsl:sort select="ABLAD" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>