What worked best for me was to double them using XSLT for the incoming document (and uncheck this on the outgoing document).
So < &lt; becomes in the attribute . Thanks @Abel for the suggestion.
Here is the XSLT I added in case others find it useful:
First, this is a template for performing line replacements in XSLT 1.0. If you can use XSLT 2.0, you can use the built-in replace instead.
<xsl:template name="string-replace-all"> <xsl:param name="text"/> <xsl:param name="replace"/> <xsl:param name="by"/> <xsl:choose> <xsl:when test="contains($text, $replace)"> <xsl:value-of select="substring-before($text,$replace)"/> <xsl:value-of select="$by"/> <xsl:call-template name="string-replace-all"> <xsl:with-param name="text" select="substring-after($text,$replace)"/> <xsl:with-param name="replace" select="$replace"/> <xsl:with-param name="by" select="$by"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Next is a template that needs specific replacements:
<xsl:template name="replace-html-codes"> <xsl:param name="text"/> <xsl:variable name="lt"> <xsl:call-template name="string-replace-all"> <xsl:with-param name="text" select="$text"/> <xsl:with-param name="replace" select="'<'"/> <xsl:with-param name="by" select="'&lt;'"/> </xsl:call-template> </xsl:variable> <xsl:variable name="gt"> <xsl:call-template name="string-replace-all"> <xsl:with-param name="text" select="$lt"/> <xsl:with-param name="replace" select="'>'"/> <xsl:with-param name="by" select="'&gt;'"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="$gt"/> </xsl:template> <xsl:template name="restore-html-codes"> <xsl:param name="text"/> <xsl:variable name="lt"> <xsl:call-template name="string-replace-all"> <xsl:with-param name="text" select="$text"/> <xsl:with-param name="replace" select="'&lt;'"/> <xsl:with-param name="by" select="'<'"/> </xsl:call-template> </xsl:variable> <xsl:variable name="gt"> <xsl:call-template name="string-replace-all"> <xsl:with-param name="text" select="$lt"/> <xsl:with-param name="replace" select="'&gt;'"/> <xsl:with-param name="by" select="'>'"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="$gt"/> </xsl:template>
XSLT is mostly cross-cutting. I just call the appropriate template when copying the attributes:
<xsl:template match="@*"> <xsl:attribute name="data-{local-name()}"> <xsl:call-template name="replace-html-codes"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:attribute> </xsl:template> <xsl:template match="node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template>
source share