Search code examples
xmltemplatesxsltvalue-of

xsl:value-of used as xsl:element name


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?


Solution

  • 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).