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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="serialize" />
<xsl:choose>
<xsl:when test="node()">
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize" />
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> /></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('<',$name)"/>
<xsl:for-each select="$node/@*">
<xsl:value-of select="concat(' ',name(),'="',.,'" ')"/>
</xsl:for-each>
<xsl:value-of select="concat('>',./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('</',$name,'>')"/>
</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>
Related videos on Youtube
Author by
Kalyan
Updated on July 09, 2022Comments
-
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 almost 13 yearsYou want the output to be: <A><B>TESTING</B></A> ?
-
Kalyan almost 13 yearsmikey - exactly the same output i need.
-
mikey almost 13 yearsGot it working on my end and posted below.
-
Emiliano Poggi almost 13 yearsIn that case the output you want would be
<A><B<TESTING>/B></A>
I think. Otherwise you can simply usexsl:copy-of
.
-
-
Kalyan almost 13 yearsThanks 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 almost 13 yearsWell 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 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 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 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 about 10 yearsThis feature needs the paid version of Saxon.
-
Telic over 7 yearsThe feature is also available in Saxon-B
-
Alejandro about 5 yearsIn 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 over 4 yearsSample 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>