0
votes

My requirement is as follows

If any complex element contains only text then corresponding element attributes translate into element to parent level.

If any complex element contains children then corresponding element attributes translate into element to same element level.

This translation want to achieve using xslt logic.

Input XML


<root>
    <food name="desert">butter scotch</food>
    <special type="nonveg">
        <name>chicken</name>
    </special>
</root>

Output XML


<root>
<food>butter scotch</food>
<name>desert</name>
<special>
    <type>nonveg</type>
    <name>chicken</name>
</special>
</root>
1

1 Answers

1
votes

Start off with the Identity Transform....

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

For the rule "If any complex element contains only text then corresponding element attributes translate into element to parent level", you could use the following template (I am ignoring comments and processing-instuctions here, and just checking the element has no child element)

<xsl:template match="*[not(*)][@*]">
    <xsl:copy>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
    <xsl:apply-templates select="@*" mode="toelement"/>
</xsl:template>

The template with mode "toelement" will turn the attribute to an element. (It will be re-used by the other rule).

    <xsl:template match="@*" mode="toelement">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>

For the rule "If any complex element contains children then corresponding element attributes translate into element to same element level." then you could actually match on the attribute directly:

<xsl:template match="*[*]/@*">
    <xsl:apply-templates select="." mode="toelement"/>
</xsl:template>

Try this XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="*[*]/@*">
        <xsl:apply-templates select="." mode="toelement"/>
    </xsl:template>

    <xsl:template match="*[not(*)][@*]">
        <xsl:copy>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
        <xsl:apply-templates select="@*" mode="toelement"/>
    </xsl:template>

    <xsl:template match="@*" mode="toelement">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>