Skip to content

Instantly share code, notes, and snippets.

@ijy
Last active December 23, 2015 03:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ijy/6574468 to your computer and use it in GitHub Desktop.
Save ijy/6574468 to your computer and use it in GitHub Desktop.
Converts a node-set into a string (allows you to insert code blocks as text rather than being interpreted). Useful for things such as JSON conversions and displaying code snippets. @href: http://www.getsymphony.com/download/xslt-utilities/view/103039/ @href: http://www.getsymphony.com/discuss/thread/103015/
<xsl:variable name="html-ready">
<!-- prepare the HTML as you want it -->
</xsl:variable>
<!-- stringify it -->
<xsl:call-template name="nodetostring">
<xsl:with-param name="node" select="$html-ready"/>
<xsl:with-param name="esc-dblq" select="true()"/>
</xsl:template>
<?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="'&#09;'"/>
<!-- 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="'&#09;'"/>
<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>&#10;</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>&#10;</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>&#10;</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="'&#09;'"/>
<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="'&#34;'"/>
<xsl:with-param name="replace" select="'&#92;&#34;'"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$format">
<xsl:text>&#10;</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>&lt;</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>/&gt;</xsl:text>
</xsl:template>
<!-- Render open tag -->
<xsl:template match="*" mode="nodetostring-opentag">
<xsl:param name="esc-dblq" select="false()"/>
<xsl:text>&lt;</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>&gt;</xsl:text>
</xsl:template>
<!-- Render close tag -->
<xsl:template match="*" mode="nodetostring-closetag">
<xsl:text>&lt;/</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>&gt;</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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment