2015-10-06 14 views
6

Bazı özelliklerde &lt; ve &gt; olabilecek bir HTML belgesine sahibim. Bunu ayıklamak ve bir XSLT aracılığıyla çalıştırmak için çalışıyorum, ancak < bir öznitelik içinde geçerli olmadığını söyleyen XSLT motor hataları. innerHTML unencodes < öznitelikleri

biraz araştırma yaptık ve düzgün kaynak belgede kaçan olduğunu bulundu, ancak bu innerHTML aracılığıyla DOM yüklenir, DOM unencoding nitelikleri olduğunu. Garip bir şekilde, bu &lt; ve &gt; için yapar, ancak &amp; gibi diğerleri değil. İşte

basit bir örnek:

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

DOM uygulaması HTML, XML öznitelikleri daha az sıkı olabilir niteliklerini olduğuna karar olduğunu farz ediyorum ve bu o "gibi çalıştığını "niyetindeydi. Sorum şu ki, korkunç bir regex değişimi yazmadan bu konuda çalışabilir miyim?

+0

@Abel ben jQuery'nin '.html()' kullanıyorum, ben sadece "sorun" oluştuğu düşünüyorum nereye kadar azaltmaya çalışmıştır. Kaynak belge, .html() 'ile eklemeden önce bir tarayıcı XSLT üzerinden çalıştırdığım XML'dir. Daha sonra, XML'i geri almak için onu ters işlemden geçiriyorum. Ben sadece DOM'ın * unescaping * karakterini (ve başkalarını değil) tuhaf buluyorum. – murrayju

+0

Kaynak XML'i değiştiremiyorum ve sonunda çıktıdaki aynı içeriği korumalıyım.Ortada hangi dönüşümleri gerekliyse koşabilirim, ama bunu bir regex yerine daha iyi yapmanın bir yolunu arıyorum. Özellikle karakter göz önüne alındığında, belgenin dolu olduğu <'. – murrayju

+0

@Abel'in tek amacım, DOM'dan aynı şekilde ("<" olarak) geri dönmesini sağlamaktır. Ben onu .text (string) ile içine alıyorum ve '.text()' ile dışarı çıkartıyorum. Bu gidiş gelişte karşılaştığım problem, girişin çıkışa eşit olmamasıdır (sadece bu durumda). – murrayju

cevap

0

Benim için en iyi şekilde sonuçlanan şey, gelen belgede bir XSLT kullanarak bunları iki kez atmaktı (ve bunu giden belgede tersine çevirmek). Bir öznede &lt;&amp;lt;

. Öneri için @Abel teşekkürler.

İlk XSLT'de 1.0 dize yedek yapmak için bir şablon: Burada

durumda diğerleri yararlı buluyorum, ben ekledi XSLT olduğunu. XSLT 2.0'ı kullanabiliyorsanız, bunun yerine yerleşik replace'u kullanabilirsiniz.

<!-- 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 çoğunlukla bir geçiş olup:

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

Sonraki I gereken özel değiştirmeler yapar şablon bulunmaktadır. kopyalama özelliklerini zaman sadece uygun şablonu çağrı:

<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

Bu sizin aradığınız şey olup olmadığından emin değiliz.

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

Bunun, öznitelikleri içindeki karakterlerden kaçışı olan soruları nasıl yanıtladığını göremiyorum ... Muhtemelen istemiyorsunuz * her * ve işareti değiştirilir ... – Abel

+0

Aslında < ve &, & lt; ve & amp; sırasıyla. Değiştirme işlevi, orijinal biçimine geri döner. – Sumesh

+0

Kesinlikle benim amacım. '&' değiştirilmemelidir, '<' yalnızca dizgenin XML olarak yorumlandığı gibi bir özellik değerinin bir parçasıysa değiştirilmelidir. Diğer oluşumları (metin düğümleri, yorum düğümleri, işlem yönergeleri, cdata bölümleri, bunların bazıları HTML'de nadir olsa da) değiştirmemelidir. – Abel

2

XMLSerializer deneyin:

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>

Sen (en azından burada Firefox ile bir testte) XHTML ad XMLSerializer ekler göz önünde XSLT'yi adapte gerekebilir.

+0

Bu istediğim şeye daha yakın, ancak tüm tarayıcılarda çalışmıyor (IE8 'XMLSerializer' içermiyor) – murrayju

+0

@murrayju, [XML Serializer'da bu soruya bakın] (http://stackoverflow.com/questions/4916327/javascript-replacement-for-xmlserializer-serializetostring), eğer (eski) tarayıcıları <% 3 kullanıcı payıyla desteklemeniz gerekiyorsa, bunu yapabilir ve bu durumda sadece 'xml' kullanabilirsiniz. Martin Honnen tarafından bu çözümün mükemmel olduğunu düşünüyorum :). – Abel

+0

@Abel, IE'de veya başka bir yerde HTML DOM düğümleri için bir 'xml' özelliği uygulandığını sanmıyorum, yalnızca MSXML DOM düğümleri için var. –