Author:
vladG
Version:
1.0
Release Date:
6 Sep 2013
Category:
String Operations

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="'&#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>

Discuss this XSLT Utility

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details