XSLT: How to convert XML Node to String

49,322

Solution 1

You need to serialize the nodes. The most simple for your example would be something like

<xsl:template match="ROOT">
  <xsl:variable name="nodestring">
    <xsl:apply-templates select="//A" mode="serialize"/>
  </xsl:variable>
  <xsl:value-of select="$nodestring"/>  
</xsl:template>

<xsl:template match="*" mode="serialize">
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="serialize"/>
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
</xsl:template>

<xsl:template match="text()" mode="serialize">
  <xsl:value-of select="."/>
</xsl:template>

The above serializer templates do not handle e.g. attributes, namespaces, or reserved characters in text nodes, but the concept should be clear. XSLT process works on a node tree and if you need to have access to "tags", you need to serialize the nodes.

Solution 2

Based on @jelovirt solution, here is a more complete piece of code:

<xsl:template match="*" mode="serialize">
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:apply-templates select="@*" mode="serialize" />
    <xsl:choose>
        <xsl:when test="node()">
            <xsl:text>&gt;</xsl:text>
            <xsl:apply-templates mode="serialize" />
            <xsl:text>&lt;/</xsl:text>
            <xsl:value-of select="name()"/>
            <xsl:text>&gt;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text> /&gt;</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="@*" mode="serialize">
    <xsl:text> </xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>="</xsl:text>
    <xsl:value-of select="."/>
    <xsl:text>"</xsl:text>
</xsl:template>

<xsl:template match="text()" mode="serialize">
    <xsl:value-of select="."/>
</xsl:template>

Solution 3

In XSLT Version 3.0. See this W3 link for fn:serialize. This worked for me using SaxonPE.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
<xsl:variable name="output">
    <output:serialization-parameters>
        <output:method value="html"/>
    </output:serialization-parameters>
</xsl:variable>
    <xsl:template match="div">
        <xsl:value-of select="serialize(., $output/output:serialization-parameters)" />
    </xsl:template>
</xsl:stylesheet>

Solution 4

<xsl:template name="serializeNodeToString">
    <xsl:param name="node"/>
    <xsl:variable name="name" select="name($node)"/>
    <xsl:if test="$name">
        <xsl:value-of select="concat('&lt;',$name)"/>
        <xsl:for-each select="$node/@*">
            <xsl:value-of select="concat(' ',name(),'=&quot;',.,'&quot; ')"/>
        </xsl:for-each>
        <xsl:value-of select="concat('&gt;',./text())"/>
    </xsl:if>
    <xsl:for-each select="$node/*">
        <xsl:call-template name="serializeNodeToString">
            <xsl:with-param name="node" select="."/>
        </xsl:call-template>
    </xsl:for-each>
    <xsl:if test="$name">
        <xsl:value-of select="concat('&lt;/',$name,'&gt;')"/>
    </xsl:if>
</xsl:template>

Solution 5

Saxon required for following solution. I find it here

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:saxon="http://saxon.sf.net/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- To serialize with saxon:serialize() -->
<xsl:output name="default" indent="yes"
    omit-xml-declaration="yes" />

<xsl:template match="*">
    <xsl:variable name="node-set">
        <xsl:element name="level1">
            <xsl:element name="level2" />
            <xsl:element name="level2" />
        </xsl:element>
    </xsl:variable>

    <xsl:element name="input">
        <xsl:copy-of select="$node-set" />
    </xsl:element>

    <xsl:element name="output">
        <xsl:value-of select="saxon:serialize($node-set, 'default')" />
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
Share:
49,322

Related videos on Youtube

Kalyan
Author by

Kalyan

Updated on July 09, 2022

Comments

  • Kalyan
    Kalyan almost 2 years
    <ROOT>
       <A>
          <B>TESTING</B>
       </A>
    </ROOT>
    

    XSL:

    <xsl:variable name="nodestring" select="//A"/>
    <xsl:value-of select="$nodestring"/>
    

    I am trying to convert XML nodeset to string using XSL. Any thoughts?

    • mikey
      mikey almost 13 years
      You want the output to be: <A><B>TESTING</B></A> ?
    • Kalyan
      Kalyan almost 13 years
      mikey - exactly the same output i need.
    • mikey
      mikey almost 13 years
      Got it working on my end and posted below.
    • Emiliano Poggi
      Emiliano Poggi almost 13 years
      In that case the output you want would be &lt;A&gt;&lt;B&lt;TESTING&gt;/B&gt;&lt;/A&gt; I think. Otherwise you can simply use xsl:copy-of.
  • Kalyan
    Kalyan almost 13 years
    Thanks mikey. I want to store the output of <xsl:copy-of> to a variable. As soon as I store it, it loses the tag information.
  • mikey
    mikey almost 13 years
    Well we are putting the nodes into the variable. To output the tag info, you can do it with copy-of. It is not lost it just depends how you display it. value-of will only display the tag values not the tags themselves.
  • Kalyan
    Kalyan almost 13 years
    <input type="hidden" name="hiddenxml"> <xsl:attribute name="value"><xsl:copy-of select="$nodes"/></xsl:attribute></input>. If I do this, only the value comes out, instead of entire xml string
  • Emiliano Poggi
    Emiliano Poggi almost 13 years
    @Kalyan, that's correct. You can't copy nodes into an attribute as value. You need to correctly escape the tags.
  • Emiliano Poggi
    Emiliano Poggi almost 13 years
    @Kaylan, you then will populate the attribute as follows: <input type="hidden" name="hiddenxml"> <xsl:attribute name="value"><xsl:value-of select="$nodestring"/></xsl:attribute></input>
  • david.perez
    david.perez about 10 years
    This feature needs the paid version of Saxon.
  • Telic
    Telic over 7 years
    The feature is also available in Saxon-B
  • Alejandro
    Alejandro about 5 years
    In order to show you how complex this task might become, check how this well formed XML <test a='1"2'/> is wrongly handled by your solution.
  • dlauzon
    dlauzon over 4 years
    Sample call of this template in a message, for debugging purposes: <xsl:message><xsl:call-template name="serializeNodeToString"> <xsl:with-param name="node" select = "."/> </xsl:call-template></xsl:message>