<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="use-empty-syntax" select="true()"/>
<xsl:param name="exclude-unused-prefixes" select="true()"/>
<xsl:param name="start-tag-start" select="'<'"/>
<xsl:param name="start-tag-end" select="'>'"/>
<xsl:param name="empty-tag-end" select="'/>'"/>
<xsl:param name="end-tag-start" select="'</'"/>
<xsl:param name="end-tag-end" select="'>'"/>
<xsl:param name="space" select="' '"/>
<xsl:param name="ns-decl" select="'xmlns'"/>
<xsl:param name="colon" select="':'"/>
<xsl:param name="equals" select="'='"/>
<xsl:param name="attribute-delimiter" select="'"'"/>
<xsl:param name="comment-start" select="'<!--'"/>
<xsl:param name="comment-end" select="'-->'"/>
<xsl:param name="pi-start" select="'<?'"/>
<xsl:param name="pi-end" select="'?>'"/>
<xsl:template name="xml-to-string">
<xsl:param name="node-set" select="."/>
<xsl:apply-templates select="$node-set" mode="xml-to-string">
<xsl:with-param name="depth" select="1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/" name="xml-to-string-root-rule">
<xsl:call-template name="xml-to-string"/>
</xsl:template>
<xsl:template match="/" mode="xml-to-string">
<xsl:param name="depth"/>
<xsl:apply-templates mode="xml-to-string">
<xsl:with-param name="depth" select="$depth"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="xml-to-string">
<xsl:param name="depth"/>
<xsl:variable name="element" select="."/>
<xsl:value-of select="$start-tag-start"/>
<xsl:call-template name="element-name">
<xsl:with-param name="text" select="name()"/>
</xsl:call-template>
<xsl:apply-templates select="@*" mode="xml-to-string"/>
<xsl:for-each select="namespace::*">
<xsl:call-template name="process-namespace-node">
<xsl:with-param name="element" select="$element"/>
<xsl:with-param name="depth" select="$depth"/>
</xsl:call-template>
</xsl:for-each>
<xsl:choose>
<xsl:when test="node() or not($use-empty-syntax)">
<xsl:value-of select="$start-tag-end"/>
<xsl:apply-templates mode="xml-to-string">
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:apply-templates>
<xsl:value-of select="$end-tag-start"/>
<xsl:call-template name="element-name">
<xsl:with-param name="text" select="name()"/>
</xsl:call-template>
<xsl:value-of select="$end-tag-end"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$empty-tag-end"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="process-namespace-node">
<xsl:param name="element"/>
<xsl:param name="depth"/>
<xsl:variable name="declaredAbove">
<xsl:call-template name="isDeclaredAbove">
<xsl:with-param name="depth" select="$depth - 1"/>
<xsl:with-param name="element" select="$element/.."/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="(not($exclude-unused-prefixes) or ($element | $element//@* | $element//*)[namespace-uri()=current()]) and not(string($declaredAbove)) and name()!='xml'">
<xsl:value-of select="$space"/>
<xsl:value-of select="$ns-decl"/>
<xsl:if test="name()">
<xsl:value-of select="$colon"/>
<xsl:call-template name="ns-prefix">
<xsl:with-param name="text" select="name()"/>
</xsl:call-template>
</xsl:if>
<xsl:value-of select="$equals"/>
<xsl:value-of select="$attribute-delimiter"/>
<xsl:call-template name="ns-uri">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="$attribute-delimiter"/>
</xsl:if>
</xsl:template>
<xsl:template name="isDeclaredAbove">
<xsl:param name="element"/>
<xsl:param name="depth"/>
<xsl:if test="$depth > 0">
<xsl:choose>
<xsl:when test="$element/namespace::*[name(.)=name(current()) and .=current()]">1</xsl:when>
<xsl:when test="$element/namespace::*[name(.)=name(current())]"/>
<xsl:otherwise>
<xsl:call-template name="isDeclaredAbove">
<xsl:with-param name="depth" select="$depth - 1"/>
<xsl:with-param name="element" select="$element/.."/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="@*" mode="xml-to-string">
<xsl:value-of select="$space"/>
<xsl:call-template name="attribute-name">
<xsl:with-param name="text" select="name()"/>
</xsl:call-template>
<xsl:value-of select="$equals"/>
<xsl:value-of select="$attribute-delimiter"/>
<xsl:call-template name="attribute-value">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="$attribute-delimiter"/>
</xsl:template>
<xsl:template match="comment()" mode="xml-to-string">
<xsl:value-of select="$comment-start"/>
<xsl:call-template name="comment-text">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="$comment-end"/>
</xsl:template>
<xsl:template match="processing-instruction()" mode="xml-to-string">
<xsl:value-of select="$pi-start"/>
<xsl:call-template name="pi-target">
<xsl:with-param name="text" select="name()"/>
</xsl:call-template>
<xsl:value-of select="$space"/>
<xsl:call-template name="pi-text">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="$pi-end"/>
</xsl:template>
<xsl:template match="text()" mode="xml-to-string">
<xsl:call-template name="text-content">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="element-name">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="attribute-name">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="attribute-value">
<xsl:param name="text"/>
<xsl:variable name="escaped-markup">
<xsl:call-template name="escape-markup-characters">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$attribute-delimiter = "'"">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$escaped-markup"/>
<xsl:with-param name="replace" select=""'""/>
<xsl:with-param name="with" select="'&apos;'"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$attribute-delimiter = '"'">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$escaped-markup"/>
<xsl:with-param name="replace" select="'"'"/>
<xsl:with-param name="with" select="'&quot;'"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$escaped-markup"/>
<xsl:with-param name="replace" select="$attribute-delimiter"/>
<xsl:with-param name="with" select="''"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="ns-prefix">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="ns-uri">
<xsl:param name="text"/>
<xsl:call-template name="attribute-value">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="text-content">
<xsl:param name="text"/>
<xsl:call-template name="escape-markup-characters">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="pi-target">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="pi-text">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="comment-text">
<xsl:param name="text"/>
<xsl:value-of select="$text"/>
</xsl:template>
<xsl:template name="escape-markup-characters">
<xsl:param name="text"/>
<xsl:variable name="ampEscaped">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$text"/>
<xsl:with-param name="replace" select="'&'"/>
<xsl:with-param name="with" select="'&amp;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ltEscaped">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$ampEscaped"/>
<xsl:with-param name="replace" select="'<'"/>
<xsl:with-param name="with" select="'&lt;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$ltEscaped"/>
<xsl:with-param name="replace" select="']]>'"/>
<xsl:with-param name="with" select="']]&gt;'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:variable name="stringText" select="string($text)"/>
<xsl:choose>
<xsl:when test="contains($stringText,$replace)">
<xsl:value-of select="substring-before($stringText,$replace)"/>
<xsl:value-of select="$with"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="substring-after($stringText,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$stringText"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>