2015-10-06 54 views
6

我有一個HTML文檔,在某些屬性中可能有&lt;&gt;。我試圖解壓縮並通過XSLT運行它,但XSLT引擎錯誤告訴我<在屬性內無效。innerHTML解開屬性<屬性

我做了一些挖掘,並發現它在源文件中正確地逃過一劫,但如果這是通過innerHTML加載到DOM中,DOM是unencoding的屬性。奇怪的是,它對&lt;&gt;這樣做,但沒有其他一些像&amp;

下面是一個簡單的例子:

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

我假設DOM實現決定,HTML屬性可以比XML屬性那麼嚴格,而這是「工作作爲意」。我的問題是,我可以在不寫一些可怕的正則表達式替換的情況下解決這個問題嗎?

+0

@Abel我使用jQuery的'的.html()',我只是試圖轉降低到我認爲的「問題​​」發生。源文檔是XML,在用'.html()'插入之前,我通過瀏覽器XSLT運行。稍後,我通過逆向過程來取回XML。我只是覺得很奇怪,DOM是* unescaping *這個角色(而不是其他人)。 – murrayju

+0

我無法修改源XML,並且需要在最後的輸出中保留相同的內容。我可以在中間運行任何需要的轉換,但是我正在尋找一種比一些正則表達式更好的方法。特別是考慮到文件充滿的'<'。 – murrayju

+0

@Abel我唯一的目標是以與它相同的方式將其從DOM中取出(如'<')。我用'.text(string)'把它放入''.text()'出來。我這次往返的問題是輸入不等於輸出(僅在這種情況下)。 – murrayju

回答

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> 

下一步是做我需要的特定更換模板:

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

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

我不確定這是你在找什麼,但看看。

var div1 = document.createElement('DIV'); 
var div2 = document.createElement('DIV'); 
div1.setAttribute('asdf','&lt;50'); 
div1.setAttribute('fdsa','&amp;50'); 
div2.appendChild(div1); 
console.log(div2.innerHTML.replace(/&amp;/g, '&')); 
+0

我沒有看到這是如何回答這個問題與屬性內逃脫少 - 然後字符...並且你可能不希望*每個*符號替換... – Abel

+0

其實它將<和&轉換爲& LT;和& amp;分別。替換功能將其更改回原始格式。 – Sumesh

+0

準確地說,我的觀點。 '&'不應該被替換,'<'只應該被替換,如果它是一個屬性值的一部分,就好像該字符串被解釋爲XML一樣。它不應該替換其他事件(文本節點,註釋節點,處理指令,cdata節,儘管其中一些在HTML中很少見)。 – Abel

2

嘗試的XMLSerializer:

var div = document.getElementById('d1'); 
 

 
var pre = document.createElement('pre'); 
 
pre.textContent = div.outerHTML; 
 
document.body.appendChild(pre); 
 

 
pre = document.createElement('pre'); 
 
pre.textContent = new XMLSerializer().serializeToString(div); 
 
document.body.appendChild(pre);
<div id="d1" data-foo="a &lt; b &amp;&amp; b &gt; c">This is a test</div>

您可能需要調整XSLT考慮到XHTML命名空間的XMLSerializer插件(至少在這裏與Firefox的測試)。

+0

這更接近我想要的,但它不適用於所有瀏覽器(IE8沒有'XMLSerializer') – murrayju

+0

@murrayju,[請參閱XML序列化器上的這個問題](http://stackoverflow.com/questions/4916327/javascript-replacement-for-xmlserializer-serializetostring),如果您必須支持(舊)瀏覽器且用戶分享率小於3%,則可以在此情況下使用'.xml'。我認爲Martin Honnen的這個解決方案非常出色:)。 – Abel

+0

@Abel,我不認爲在IE或其他地方爲HTML DOM節點實現了'xml'屬性,它只存在於MSXML DOM節點中。 –