Home > Net >  transform an XML file by XSL1.0
transform an XML file by XSL1.0

Time:04-19

I want to modify an XML file according to the element 'identifier' and 'items' of menu.

  1. if the 'identifier' of a menu is exist in another menu's items in input XML file, the menu context should be copied below the parent menu in output XML file, and the order should be same with the parent's items.

  2. menu's element of 'label' should be changed to 'level_xx'.'xx' is the level number, for detail please refer to the excel capture.

Can any one please help me how do I achieve this using XSL1.0.

Input XML file:

<input>
    <menu>
        <identifier>1</identifier>
        <label>"1"</label>
        <items>
            <item>2</item>
            <item>3</item>
        </items>
    </menu>
    <menu>
        <identifier>2</identifier>
        <label>"2"</label>
        <items>
            <item>21</item>
            <item>22</item>
            <item>3</item>
        </items>
    </menu>
    <menu>
        <identifier>3</identifier>
        <label>"3"</label>
        <items>
            <item>31</item>
            <item>32</item>
        </items>
    </menu>
    <menu>
        <identifier>21</identifier>
        <label>"21"</label>
        <items>
            <item>211</item>
            <item>212</item>
        </items>
    </menu>
    <menu>
        <identifier>22</identifier>
        <label>"22"</label>
        <items>
            <item>221</item>
            <item>222</item>
        </items>
    </menu>
    <menu>
        <identifier>31</identifier>
        <label>"31"</label>
        <items>
            <item>311</item>
            <item>312</item>
        </items>
    </menu>
    <menu>
        <identifier>32</identifier>
        <label>"32"</label>
        <items>
            <item>321</item>
            <item>322</item>
        </items>
    </menu>
</input>

Output XML file:

<input>
    <menu>
        <identifier>1</identifier>
        <level_01>"1"</level_01>
        <items>
            <item>2</item>
            <item>3</item>
        </items>
    </menu>
    <menu>
        <identifier>2</identifier>
        <level_02>"2"</level_02>
        <items>
            <item>21</item>
            <item>22</item>
            <item>3</item>
        </items>
    </menu>
    <menu>
        <identifier>21</identifier>
        <level_03>"21"</level_03>
        <items>
            <item>211</item>
            <item>212</item>
        </items>
    </menu>
    <menu>
        <identifier>22</identifier>
        <level_03>"22"</level_03>
        <items>
            <item>221</item>
            <item>222</item>
        </items>
    </menu>
    <menu>
        <identifier>3</identifier>
        <level_03>"3"</level_03>
        <items>
            <item>31</item>
            <item>32</item>
        </items>
    </menu>
    <menu>
        <identifier>31</identifier>
        <level_04>"31"</level_04>
        <items>
            <item>311</item>
            <item>312</item>
        </items>
    </menu>
    <menu>
        <identifier>32</identifier>
        <level_04>"32"</level_04>
        <items>
            <item>321</item>
            <item>322</item>
        </items>
    </menu>
    <menu>
        <identifier>3</identifier>
        <level_02>"3"</level_02>
        <items>
            <item>31</item>
            <item>32</item>
        </items>
    </menu>
    <menu>
        <identifier>31</identifier>
        <level_03>"31"</level_03>
        <items>
            <item>311</item>
            <item>312</item>
        </items>
    </menu>
    <menu>
        <identifier>32</identifier>
        <level_03>"32"</level_03>
        <items>
            <item>321</item>
            <item>322</item>
        </items>
    </menu>
</input>

the level info of the output

CodePudding user response:

Assuming that your input XML actually looks like this:

XML

<input>
    <menu>
        <identifier>1</identifier>
        <label>"1"</label>
        <items>
            <item>2</item>
            <item>3</item>
        </items>
    </menu>
    <menu>
        <identifier>2</identifier>
        <label>"2"</label>
        <items>
            <item>21</item>
            <item>22</item>
        </items>
    </menu>
    <menu>
        <identifier>3</identifier>
        <label>"3"</label>
        <items>
            <item>31</item>
            <item>32</item>
        </items>
    </menu>
    <menu>
        <identifier>21</identifier>
        <label>"21"</label>
        <items>
            <item>211</item>
            <item>212</item>
        </items>
    </menu>
    <menu>
        <identifier>22</identifier>
        <label>"22"</label>
        <items>
            <item>221</item>
            <item>222</item>
        </items>
    </menu>
    <menu>
        <identifier>31</identifier>
        <label>"31"</label>
        <items>
            <item>311</item>
            <item>312</item>
        </items>
    </menu>
    <menu>
        <identifier>32</identifier>
        <label>"32"</label>
        <items>
            <item>321</item>
            <item>322</item>
        </items>
    </menu>
</input>

you could adapt the answer to your previous question and do:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="children" match="menu" use="identifier" />
<xsl:key name="parent" match="menu" use="items/item" />

<xsl:template match="/input">
    <xsl:copy>
        <xsl:apply-templates select="menu[not(key('parent', identifier))]">
            <xsl:with-param name="level" select="1"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<xsl:template match="menu">
    <xsl:param name="level"/>
    <xsl:copy>
        <xsl:copy-of select="identifier"/>
        <xsl:element name="level_{format-number($level, '00')}">
            <xsl:value-of select="label" />
        </xsl:element>
        <xsl:copy-of select="items"/>
    </xsl:copy>
    <xsl:apply-templates select="key('children', items/item)">
        <xsl:with-param name="level" select="$level   1"/>
    </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

Added:

If you need the child menu elements to be listed in the same order as the item elements are within items, then change this part:

    <xsl:apply-templates select="key('children', items/item)">
        <xsl:with-param name="level" select="$level   1"/>
    </xsl:apply-templates>

to:

    <xsl:for-each select="items/item">
        <xsl:apply-templates select="key('children', .)">
            <xsl:with-param name="level" select="$level   1"/>
        </xsl:apply-templates>
    </xsl:for-each>
  • Related