Converting XML elements to XML attributes using XSLT
Solution 1:
This should work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="INVENTORY">
<INVENTORY>
<xsl:apply-templates/>
</INVENTORY>
</xsl:template>
<xsl:template match="ITEM">
<ITEM>
<xsl:for-each select="*">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</ITEM>
</xsl:template>
</xsl:stylesheet>
Solution 2:
Here is probably the simplest solution that will convert any children-elements of ITEM
to its attributes and will reproduce everything else as is, while converting the element names to any desired attribute names:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<!-- -->
<xsl:strip-space elements="*"/>
<xsl:variable name="vrtfNameMapping">
<item name="SERIALNUMBER" newName="serialNumber"/>
<item name="LOCATION" newName="location"/>
<item name="BARCODE" newName="barcode"/>
</xsl:variable>
<!-- -->
<xsl:variable name="vNameMapping" select=
"document('')/*/xsl:variable[@name='vrtfNameMapping']"/>
<!-- -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- -->
<xsl:template match="ITEM/*">
<xsl:attribute name=
"{$vNameMapping/*[@name=name(current())]/@newName}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when the above transformation is applied on the provided XML document:
<INVENTORY>
<ITEM>
<SERIALNUMBER>something</SERIALNUMBER>
<LOCATION>something</LOCATION>
<BARCODE>something</BARCODE>
</ITEM>
</INVENTORY>
the wanted result is produced:
<INVENTORY>
<ITEM serialNumber="something" location="something" barcode="something"/>
</INVENTORY>
Do note the following:
The use of the identity rule
The use of
<xsl:strip-space elements="*"/>
The use of the variable
vrtfNameMapping
without anyxxx:node-set()
extension function.The fact that we handle any mapping between a name and a newName, not only simple lower-casing.
Solution 3:
These two templates should do it:-
<xsl:template match="ITEM">
<ITEM serialNumber="{SERIALNUMBER}" location="{LOCATION}" barcode="{BARCODE}" />
</xsl:template>
<xsl:template match="INVENTORY">
<INVENTORY>
<xsl:apply-templates />
</INVENTORY>
</xsl:template>
Solution 4:
This ought to do it:
<xsl:for-each select="//ITEM">
<xsl:element name="ITEM">
<xsl:attribute name="serialNumber">
<xsl:value-of select="SERIALNUMBER"/>
</xsl:attribute>
<xsl:attribute name="location">
<xsl:value-of select="LOCATION"/>
</xsl:attribute>
<xsl:attribute name="barcode">
<xsl:value-of select="BARCODE"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
Or using David's shortcut:
<xsl:for-each select="//ITEM">
<ITEM serialNumber="{SERIALNUMBER}" location="{LOCATION}" barcode="{BARCODE}"/>
</xsl:for-each>