I'm new to XSLT and despite my research, I struggle to find explanations or at least to apply them to my case, so I try my luck here and thank you in advance for your attention
I have an XML structure where each element(units/results) has an attribute named packagingLevel
. I need to find a preceding sibling of the current node where the packagingLevel
attribute equals current()/@packagingLevel
-1 and select the value of a different attribute (packagingType
) within the transformation that I already have. So if the packagingLevel
= 5, I'm searching the packagingType
of a sibling that have packagingLevel
= 4.
Here is an exemple of my input :
<root>
<header>
<products>
<results>
<units>
<results>
<itemCode>001</itemCode>
<packagingType>BOX</packagingType>
<eanCode>0000000000001</eanCode>
<packagingLevel>1</packagingLevel>
<quantity>1</quantity>
</results>
<results>
<itemCode>002</itemCode>
<packagingType>PALETTE</packagingType>
<eanCode>0000000000002</eanCode>
<packagingLevel>2</packagingLevel>
<quantity>1</quantity>
</results>
</units>
</results>
</products>
</header>
</root>
This is an exemple of what I tried :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xsl:for-each select="//products/results">
<Element>
<xsl:for-each select="units/results">
<UE>
<UE_EAN>
<xsl:value-of select="eanCode" />
</UE_EAN>
<TYPE_UE>
<xsl:choose>
<xsl:when test="packagingLevel = 1">A01</xsl:when>
<xsl:when test="packagingType = 'BOX'">B01</xsl:when>
<xsl:when test="packagingType = 'PALETTE'">P01</xsl:when>
</xsl:choose>
</TYPE_UE>
<TYPE_UE_CONTENT>
<xsl:choose>
<xsl:when test="packagingLevel = 1">A01</xsl:when>
<xsl:otherwise>
<xsl:variable name="prevLevel" select="preceding-sibling::units[packagingLevel = current()/packagingLevel - 1]/TYPE_UE" />
<xsl:value-of select="$prevLevel"/>
</xsl:otherwise>
</xsl:choose>
</TYPE_UE_CONTENT>
<UE_QTE>
<xsl:value-of select="quantite" />
</UE_QTE>
</UE>
</xsl:for-each>
</Element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
here is the current output :
<Element>
<... />
<... />
<UE>
<UE_EAN>0000000000001</UE_EAN>
<TYPE_UE>A01</TYPE_UE>
<TYPE_UE_CONTENT>A01</TYPE_UE_CONTENT>
<UE_QTY>1</UE_QTY>
</UE>
<UE>
<UE_EAN>0000000000002</UE_EAN>
<TYPE_UE>P01</TYPE_UE>
<TYPE_UE_CONTENT />
<UE_QTE>2</UE_QTE>
</UE>
<... />
</Element>
and here is the expected output based on the exemple above :
<Element>
<... />
<... />
<UE>
<UE_EAN>0000000000001</UE_EAN>
<TYPE_UE>A01</TYPE_UE>
<TYPE_UE_CONTENT>A01</TYPE_UE_CONTENT>
<UE_QTY>1</UE_QTY>
</UE>
<UE>
<UE_EAN>0000000000002</UE_EAN>
<TYPE_UE>P01</TYPE_UE>
<TYPE_UE_CONTENT>A01</TYPE_UE_CONTENT>
<UE_QTE>2</UE_QTE>
</UE>
<... />
</Element>
Thanks a lot for reading me and any help or explanation you could provide me !
You cannot use the preceding-sibling
axis to retrieve a calculated value from the output. You must either re-calculate the value using the values from the input or (more efficiently) pre-calculate all values before writing to the output.
In XSLT 1.0 this would be done as:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root">
<xsl:for-each select="header/products/results">
<xsl:variable name="temps">
<xsl:for-each select="units/results">
<temp>
<xsl:copy-of select="*"/>
<TYPE_UE>
<xsl:choose>
<xsl:when test="packagingLevel = 1">A01</xsl:when>
<xsl:when test="packagingType = 'BOX'">B01</xsl:when>
<xsl:when test="packagingType = 'PALETTE'">P01</xsl:when>
</xsl:choose>
</TYPE_UE>
</temp>
</xsl:for-each>
</xsl:variable>
<Element>
<xsl:for-each select="exsl:node-set($temps)/temp">
<UE>
<UE_EAN>
<xsl:value-of select="eanCode"/>
</UE_EAN>
<xsl:copy-of select="TYPE_UE"/>
<TYPE_UE_CONTENT>
<xsl:choose>
<xsl:when test="packagingLevel = 1">A01</xsl:when>
<xsl:otherwise>
<xsl:value-of select="preceding-sibling::temp[packagingLevel = current()/packagingLevel - 1]/TYPE_UE"/>
</xsl:otherwise>
</xsl:choose>
</TYPE_UE_CONTENT>
<UE_QTY>
<xsl:value-of select="quantity"/>
</UE_QTY>
</UE>
</xsl:for-each>
</Element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>