nodetostring plus
Nodetostring evolved
Description
Stringify nodes.
Can output pretty formatted text (useful for code snippets).
Can escape double quotes (useful for json conversions, data inside attributes etc)
XSLT
View Raw
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <!-- Converts a nodeset to string, especially useful for json conversions. =================================================================================== Adapted from @Thomas Appel's nodetostring utility at http://www.getsymphony.com/download/xslt-utilities/view/79266/ This version adds formatting capabilities. Very useful for displaying code snippets. =================================================================================== Example usage: (convert a nodeset to string: ) ___ <xsl:call-template name="nodetostring"> <xsl:with-param name="node" select="YOUR_XML"/> </xsl:template> ___ Format result ___ <xsl:call-template name="nodetostring"> <xsl:with-param name="node" select="YOUR_XML"/> <xsl:with-param name="format" select="true()"/> </xsl:template> ___ Escape double quotes ___ <xsl:call-template name="nodetostring"> <xsl:with-param name="node" select="YOUR_XML"/> <xsl:with-param name="esc-dblq" select="true()"/> </xsl:template> --> <xsl:template name="nodetostring"> <!-- Incoming XML --> <xsl:param name="node"/> <!-- Turn format on and off --> <xsl:param name="format" select="false()"/> <!-- Format indent --> <xsl:param name="format-tab" select="'	'"/> <!-- Escape double quotes in strings --> <xsl:param name="esc-dblq" select="false()"/> <xsl:apply-templates select="exsl:node-set($node)/* | exsl:node-set($node)/text()" mode="nodetostring"> <xsl:with-param name="format" select="$format"/> <xsl:with-param name="format-tab" select="$format-tab"/> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> </xsl:template> <!-- Render nodes --> <xsl:template match="*" mode="nodetostring"> <xsl:param name="format" select="false()"/> <xsl:param name="format-tab" select="'	'"/> <xsl:param name="esc-dblq" select="false()"/> <xsl:variable name="empty"/> <xsl:choose> <!-- if element has text only --> <xsl:when test="normalize-space(.) != $empty and not(*)"> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-opentag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:apply-templates select="text()" mode="nodetostring"> <xsl:with-param name="format" select="false()"/> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:apply-templates select="." mode="nodetostring-closetag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> </xsl:when> <!-- if element has text and children --> <xsl:when test="normalize-space(.) != $empty and *"> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-opentag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:if test="$format"> <xsl:text> </xsl:text> </xsl:if> <xsl:apply-templates select="* | text()" mode="nodetostring"> <xsl:with-param name="format" select="$format"/> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-closetag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> </xsl:when> <!-- if element has children only --> <xsl:when test="*"> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-opentag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:if test="$format"> <xsl:text> </xsl:text> </xsl:if> <xsl:apply-templates select="*" mode="nodetostring"> <xsl:with-param name="format" select="$format"/> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-closetag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> </xsl:when> <!-- assuming empty tags are self closing, e.g. <img/>, <source/>, <input/> --> <xsl:otherwise> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:apply-templates select="." mode="nodetostring-selfclosetag"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> </xsl:otherwise> </xsl:choose> <xsl:if test="$format"> <xsl:text> </xsl:text> </xsl:if> </xsl:template> <!-- Render text --> <xsl:template match="text()" mode="nodetostring"> <xsl:param name="format" select="false()"/> <xsl:param name="format-tab" select="'	'"/> <xsl:param name="esc-dblq" select="false()"/> <xsl:if test="$format"> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:if> <xsl:choose> <xsl:when test="$esc-dblq"> <xsl:call-template name="nodetostring.replace"> <xsl:with-param name="in" select="."/> <xsl:with-param name="needle" select="'"'"/> <xsl:with-param name="replace" select="'\"'"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> <xsl:if test="$format"> <xsl:text> </xsl:text> </xsl:if> </xsl:template> <!-- Render self closing tags --> <xsl:template match="*" mode="nodetostring-selfclosetag"> <xsl:param name="esc-dblq" select="false()"/> <xsl:text><</xsl:text> <xsl:value-of select="name()"/> <xsl:apply-templates select="@*" mode="nodetostring-attribs"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:text>/></xsl:text> </xsl:template> <!-- Render open tag --> <xsl:template match="*" mode="nodetostring-opentag"> <xsl:param name="esc-dblq" select="false()"/> <xsl:text><</xsl:text> <xsl:value-of select="name()"/> <xsl:apply-templates select="@*" mode="nodetostring-attribs"> <xsl:with-param name="esc-dblq" select="$esc-dblq"/> </xsl:apply-templates> <xsl:text>></xsl:text> </xsl:template> <!-- Render close tag --> <xsl:template match="*" mode="nodetostring-closetag"> <xsl:text></</xsl:text> <xsl:value-of select="name()"/> <xsl:text>></xsl:text> </xsl:template> <!-- Render attributes --> <xsl:template match="@*" mode="nodetostring-attribs"> <xsl:param name="esc-dblq" select="false()"/> <xsl:variable name="dbl-quotes"> <xsl:if test="$esc-dblq">\</xsl:if> <xsl:text>"</xsl:text> </xsl:variable> <xsl:value-of select="concat(' ', name(), '=', $dbl-quotes, ., $dbl-quotes)"/> </xsl:template> <!-- Formatter utility. Inserts $format-tab as long as parents exist --> <xsl:template match="*" mode="nodetostring-format"> <xsl:param name="format-tab"/> <xsl:value-of select="$format-tab"/> <xsl:apply-templates select="ancestor::*[1]" mode="nodetostring-format"> <xsl:with-param name="format-tab" select="$format-tab"/> </xsl:apply-templates> </xsl:template> <!-- Utility to replace a string in another string --> <xsl:template name="nodetostring.replace"> <xsl:param name="in" select="''"/> <xsl:param name="needle" select="''"/> <xsl:param name="replace" select="''"/> <xsl:choose> <xsl:when test="contains($in, $needle)"> <xsl:value-of select="substring-before($in, $needle)"/> <xsl:value-of select="$replace"/> <xsl:call-template name="nodetostring.replace"> <xsl:with-param name="in" select="substring-after($in, $needle)"/> <xsl:with-param name="needle" select="$needle"/> <xsl:with-param name="replace" select="$replace"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$in"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>