I have the following XML :-
<inventory>
<item>
<name_element>
<!--some structure-->
</name_element>
<some_element1>val1</some_element1>
<some_element2>val2</some_element2>
<!-- some more elements -->
</item>
<!-- lots of items -->
</inventory>
Now I want to convert this to :-
<inventory>
<item some_element1="val1" some_element2="val2" ... >
<name_element>
<!-- as it is -->
</name_element>
</inventory>
Basically I don't know anything about the names/types of some_elements and any item could have any number of these elements. I do know that they are all simple types and convertible to attributes.
I've read Converting XML elements to XML attributes using XSLT which tells how I can convert all child elements to attributes but it's not clear from that how I could exclude a specific 'name_element' from being converted to an attribute.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<!--apply templates for any attributes and convert
elements(except for name_element) in order to create all
attributes before creating child nodes for item element -->
<xsl:apply-templates select="@*
| *[not(self::name_element)]"/>
<!--apply templates to name_element and any comments or processing instructions -->
<xsl:apply-templates select="name_element
| comment()
| processing-instruction()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item/*[not(self::name_element)]">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
First, use the identity template to copy every thing as is:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
Then, define a template for item. You can iterate over children, and excluding what you don't want be converted to an attribute. this is an example template:
<xsl:template match="item">
<xsl:copy>
<!-- this will set children as attributes, but name_element -->
<xsl:for-each select="*[not(local-name()='name_element')]">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
<!-- this preserves name_element as it is -->
<xsl:apply-templates select="name_element"/>
</xsl:copy>
</xsl:template>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With