How to select a preceding sibling with an attribute value equal to current()/@value -1 in XSLT?

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 :

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><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>
</code>
<code><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> </code>
<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 :

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><?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>
</code>
<code><?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> </code>
<?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 :

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><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>
</code>
<code><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> </code>
<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 :

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><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>
</code>
<code><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> </code>
<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 !

New contributor

Ollysheep is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

4

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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><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>
</code>
<code><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> </code>
<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>

The context node at the point where you are using preceding-sibling is a results element, and all the siblings of a results element are also named results, so you want preceding-sibling::results or simply preceding-sibling::*.

And I’ve no idea what the /TYPE_UE in your expression is there for — there don’t appear to be any TYPE_UE elements in your input.

3

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật