Я попытался реализовать ответ, предоставленный Павлом Минаевым, и хочу отметить, что это очень опасно для больших строк, поскольку каждый символ во входной строке повторяется по отдельности, в результате чего глубина рекурсии быстро истекает. Я попытался запустить его через несколько строк текста, и это вызвало переполнение стека (смеется).
Вместо этого я использую шаблон, который не должен проверять каждый отдельный символ, скорее он будет помещать текст, пока не найдет строку, которую необходимо заменить. Это может быть использовано для экранирования символов:
<xsl:template name="Search-And-Replace">
<xsl:param name="Input-String"/>
<xsl:param name="Search-String"/>
<xsl:param name="Replace-String"/>
<xsl:choose>
<xsl:when test="$Search-String and contains($Input-String, $Search-String)">
<xsl:value-of select="substring-before($Input-String, $Search-String)"/>
<xsl:value-of select="$Replace-String"/>
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="substring-after($Input-String, $Search-String)"/>
<xsl:with-param name="Search-String" select="$Search-String"/>
<xsl:with-param name="Replace-String" select="$Replace-String"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Input-String"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Тогда нужно просто вызвать этот шаблон для символа, который вы хотите экранировать ..
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="Hi I am a string & I am awesome"/>
<xsl:with-param name="Search-String" select="'&'"/>
<xsl:with-param name="Replace-String" select="'&amp;'"/>
</xsl:call-template>
Чтобы экранировать несколько символов в одной строке, я использовал шаблон-оболочку, который использует переменные ...
<xsl:template name="EscapeText">
<xsl:param name="text" />
<xsl:variable name="a">
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="$text"/>
<xsl:with-param name="Search-String" select="'&'"/>
<xsl:with-param name="Replace-String" select="'&amp;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="b">
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="$a"/>
<xsl:with-param name="Search-String" select="'"'"/>
<xsl:with-param name="Replace-String" select="'&quot;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="c">
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="$b"/>
<xsl:with-param name="Search-String">'</xsl:with-param>
<xsl:with-param name="Replace-String" select="'&apos;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="d">
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="$c"/>
<xsl:with-param name="Search-String" select="'>'"/>
<xsl:with-param name="Replace-String" select="'&gt;'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="e">
<xsl:call-template name="Search-And-Replace">
<xsl:with-param name="Input-String" select="$d"/>
<xsl:with-param name="Search-String" select="'<'"/>
<xsl:with-param name="Replace-String" select="'&lt;'"/>
</xsl:call-template>
</xsl:variable>
<!--this is the final output-->
<xsl:value-of select="$e"/>
</xsl:template>
Это оказалось намного безопаснее для больших строк, так как больше не нужно повторять для каждого отдельного символа во входной строке.