xmlxpathxslt-1.0transformconverters

Using XSLT to Iterate and Transform XML to Simple Text


I am a beginner and still learning in XSLT. I have a simple xml code below:

<?xml version="1.0" encoding="UTF-8"?>
<order id="1021">
    <items>
        <item code="11">
            <quantity>2</quantity
            <price>50</price>
        </item>
        <item code="21">
            <quantity>1</quantity>
            <price>250</price>
        </item>
        <item code="13">
            <quantity>4</quantity>
            <price>100</price>
        </item>
    </items>
    <status>3</status>
</order>

And I want to write an XSLT script which will convert it into a simple text array which contains all item codes. For example, the above xml should be converted as: [11,21,13]

I have written the following XSLT Code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <!-- Template to match the root 'order' element -->
    <xsl:template match="/order">
        <!-- Start bracket for the array -->
        <xsl:text>[</xsl:text>
        <!-- Iterate over each item -->
        <xsl:for-each select="items/item">
            <!-- Output the code attribute -->
            <xsl:value-of select="@code"/>
            <!-- If not the last item, add a comma and space -->
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
        </xsl:for-each>
        <!-- End bracket for the array -->
        <xsl:text>]</xsl:text>
    </xsl:template>

</xsl:stylesheet>

I am facing the problem in iterating over all items. I only get the code of the first item in output: [11]

Where as I am expecting the codes of all items like: [11,21,13]

Kindly let me know if anyone can spot a mistake in my XSLT code. I have tried asking chatgpt for it but it was not much of a help.


Solution

  • Your XSLT 1.0 is perfectly working.

    For comparison, please see below how it is much easier to implement in XSLT 2.0 and later versions.

    In XSLT 2.0, <xsl:value-of> was enhanced, and has a separator attribute.

    XSLT, 2nd Edition by Doug Tidwell

    For the reference: XSLT

    Input XML

    <?xml version="1.0" encoding="UTF-8"?>
    <order id="1021">
        <items>
            <item code="11">
                <quantity>2</quantity>
                <price>50</price>
            </item>
            <item code="21">
                <quantity>1</quantity>
                <price>250</price>
            </item>
            <item code="13">
                <quantity>4</quantity>
                <price>100</price>
            </item>
        </items>
        <status>3</status>
    </order>
    

    XSLT 1.0

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <!-- Template to match the root 'order' element -->
        <xsl:template match="/order">
            <!-- Start bracket for the array -->
            <xsl:text>[</xsl:text>
            <!-- Iterate over each item -->
            <xsl:for-each select="items/item">
                <!-- Output the code attribute -->
                <xsl:value-of select="@code"/>
                <!-- If not the last item, add a comma and space -->
                <xsl:if test="position() != last()">
                    <xsl:text>, </xsl:text>
                </xsl:if>
            </xsl:for-each>
            <!-- End bracket for the array -->
            <xsl:text>]</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    

    XSLT 2.0

    <?xml version="1.0"?>
    <xsl:stylesheet version="2.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
    
        <xsl:template match="/">
            <xsl:text>[</xsl:text>
            <xsl:value-of select="order/items/item/@code"
                          separator=", "/>
            <xsl:text>]</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    

    Output

    [11, 21, 13]