xsl:value-of used as xsl:element name

Thomson Comer picture Thomson Comer · Jan 16, 2011 · Viewed 18.1k times · Source

I have an incoming XML file with a list structure:

<list>
  <listItem>
    <name>elementOne</name>
    <value>elementOneValue</name>
  </listItem>
  <listItem>
    <name>elementTwo</name>
    <value>elementTwoValue</name>
  </listItem>
</list>

Which I am trying to convert to this structure:

<elementOne>elementOneValue</elementOne>
<elementTwo>elementTwoValue</elementTwo>

This is easy logic to implement with XSL, but I'm running into complications.

<xsl:for-each select="/list/listItem">
  <xsl:element name="<xsl:value-of select="name"/>">
    <xsl:value-of select="value"/>
  </xsl:element>
</xsl:for-each>

Doesn't work because I assume the sequential double quotes are breaking the <xsl:element> tag

<xsl:for-each select="/list/listItem">
  <<xsl:value-of select="name"/>>
    <xsl:value-of select="value"/>
  </<xsl:value-of select="name"/>>
</xsl:for-each>

Doesn't work because I can't use << or >> and

<xsl:for-each select="/list/listItem">
  &lt;<xsl:value-of select="name"/>&gt;
    <xsl:value-of select="value"/>
  &lt;/<xsl:value-of select="name"/>&gt;
</xsl:for-each>

Doesn't work because I end up with > and < in my code instead of XML parseable < or >. I expected this to be a very easy solution but I can't find any records for it on the internet. What is the simple fix I'm overlooking?

Answer

Dimitre Novatchev picture Dimitre Novatchev · Jan 16, 2011

Here is a complete and short solution, using the <xsl:element> XSLT instruction:

<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:template match="listItem">
   <xsl:element name="{name}">
     <xsl:value-of select="value"/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document (corrected to be well-formed):

<list>
    <listItem>
        <name>elementOne</name>
        <value>elementOneValue</value>
    </listItem>
    <listItem>
        <name>elementTwo</name>
        <value>elementTwoValue</value>
    </listItem>
</list>

the wanted result is produced:

<elementOne>elementOneValue</elementOne>
<elementTwo>elementTwoValue</elementTwo>

Do note:

  1. The use of the <xsl:element> instruction to create an element with statically unknown name.

  2. The use of AVT (Attribute-Value-Template) to specify the name attribute in a compact and more readable way.

  3. It is possible for an error to be raised if the string values of elementOne and elementTwo do not obey the lexical/syntactic rules for an element name (QName).