sajushko
sajushko

Reputation: 420

Transform XML with tree data structure to flat structure using XSLT

I am trying to transform XML with tree structure into a flat list. This is a small part of input XML that I am trying to transform:

<category_list>
    <category>
        <id>12</id>
        <name>Forks</name>
        <sub_categories>
            <category>
                <id>15</id>
                <name>26"</name>
                <sub_categories />
            </category>
            <category>
                <id>16</id>
                <name>27,5"</name>
                <sub_categories />
            </category>
            <category>
                <id>19</id>
                <name>27,5+"</name>
                <sub_categories />
            </category>
            <category>
                <id>17</id>
                <name>29"</name>
                <sub_categories />
            </category>
        </sub_categories>
    </category>
    <category>
        <id>13</id>
        <name>Shocks</name>
        <sub_categories />
    </category>
    <category>
        <id>14</id>
        <name>Springs</name>
        <sub_categories />
    </category>
</category_list>

I need output like this:

<categories>
    <category>
        <id>12</id>
        <name>Forks</name>
        <parent_category>0</parent_category>
        <order_by>1</order_by>
    </category>
    <category>
        <id>15</id>
        <name>26"</name>
        <parent_category>12</parent_category>
        <order_by>1</order_by>
    </category>
    <category>
        <id>16</id>
        <name>27,5"</name>
        <parent_category>12</parent_category>
        <order_by>2</order_by>
    </category>
    <category>
        <id>19</id>
        <name>27,5+"</name>
        <parent_category>12</parent_category>
        <order_by>3</order_by>
    </category>
    <category>
        <id>17</id>
        <name>29"</name>
        <parent_category>12</parent_category>
        <order_by>4</order_by>
    </category>
    <category>
        <id>13</id>
        <name>Shocks</name>
        <parent_category>0</parent_category>
        <order_by>2</order_by>
    </category>
    <category>
        <id>14</id>
        <name>Springs</name>
        <parent_category>0</parent_category>
        <order_by>3</order_by>
    </category>
</categories>

I have no idea how to do it. First problem is to change tree structure to flat list and second problem is add an order_by tag that increments with category count.

Can you please advice?

Upvotes: 0

Views: 276

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

You can process all //category and then use position():

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes"/>

    <xsl:template match="category_list">
        <categories>
            <xsl:apply-templates select="//category"/>
        </categories>
    </xsl:template>

    <xsl:template match="category">
        <xsl:copy>
            <xsl:copy-of select="*[not(self::sub_categories)]"/>
            <parent_category>
                <xsl:choose>
                    <xsl:when test="../parent::category">
                        <xsl:value-of select="../parent::category/id"/>
                    </xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
            </parent_category>
            <order_by>
                <xsl:value-of select="position()"/>
            </order_by>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions