innerHTML unncodes< 在属性中

mur*_*yju 6 html javascript xml xslt innerhtml

我有可能有一个HTML文档&lt;,并&gt;在某些属性.我试图提取它并通过XSLT运行它,但XSLT引擎错误告诉我<在属性内部无效.

我做了一些挖掘,发现它在源文档中被正确转义,但是当它通过innerHTMLDOM 加载到DOM中时,DOM 就不会对属性进行编码.奇怪的是,它这样做的&lt;&gt;,而不是一些人喜欢&amp;.

这是一个简单的例子:

var div = document.createElement('DIV');
div.innerHTML = '<div asdf="&lt;50" fdsa="&amp;50"></div>';
console.log(div.innerHTML)
Run Code Online (Sandbox Code Playgroud)

我假设DOM实现决定HTML属性可以不如XML属性严格,并且这是"按预期工作".我的问题是,如果不写一些可怕的正则表达式替换,我可以解决这个问题吗?

mur*_*yju 0

最终对我来说最有效的是在传入文档上使用 XSLT 进行双重转义(并在传出文档上反转)。

所以&lt;在属性中就变成了&amp;lt;. 感谢@Abel 的建议。

这是我添加的 XSLT,以防其他人发现它有帮助:

第一个是用于在 XSLT 1.0 中进行字符串替换的模板。如果您可以使用 XSLT 2.0,则可以使用内置的replace

<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>
Run Code Online (Sandbox Code Playgroud)

接下来是执行我需要的特定替换的模板:

<!-- xml -> html -->
<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="'&lt;'"/>
            <xsl:with-param name="by" select="'&amp;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="'&gt;'"/>
            <xsl:with-param name="by" select="'&amp;gt;'"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$gt"/>
</xsl:template>

<!-- html -> xml -->
<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="'&amp;lt;'"/>
            <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="'&amp;gt;'"/>
            <xsl:with-param name="by" select="'&gt;'"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$gt"/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

XSLT 主要是传递。我只是在复制属性时调用适当的模板:

<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>

<!-- copy all nodes -->
<xsl:template match="node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)