2010-07-20 223 views
2

逃脫XML對於下面的XML我想從XSLT如呈現在瀏覽器中的轉義文本部分:渲染的瀏覽器

<one> 
&lt;text&gt; 
</one> 

我想呈現瀏覽器的標記是:

&lt;text&gt; 

但是當我使用下面的應用模板時,如下所示

<xsl:template match="text()" mode="literalHTML"> 
    <xsl:copy-of select="."> 
    </xsl:copy-of> 
</xsl:template> 

以上XML呈現爲:

<text> 

我怎麼能修改此模板,以便它打印& LT;文本& GT;在瀏覽器上?

此致 凱沙夫

回答

2

這可以在XSLT 1.0使用相當棘手遞歸處理來實現。

幸運的是,人們可以使用FXSL(XSLT模板庫)來解決相同的任務,在短短几分鐘內:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:testmap="testmap" 
exclude-result-prefixes="xsl f testmap"> 
    <xsl:import href="str-dvc-map.xsl"/> 

    <testmap:testmap/> 

    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:template match="/"> 
    <xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/> 
    <xsl:call-template name="str-map"> 
     <xsl:with-param name="pFun" select="$vTestMap"/> 
     <xsl:with-param name="pStr" select="/*/text()"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="escape" mode="f:FXSL" 
    match="*[namespace-uri() = 'testmap']"> 
     <xsl:param name="arg1"/> 

     <xsl:choose> 
     <xsl:when test="$arg1 = '&lt;'">&amp;lt;</xsl:when> 
     <xsl:when test="$arg1 = '&gt;'">&amp;gt;</xsl:when> 
     <xsl:otherwise><xsl:value-of select="$arg1"/></xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

當施加在下面的XML文檔這一轉變:

<one> 
&lt;text&gt; 
</one> 

有用結果產生

&amp;lt;text&amp;gt; 

並顯示在瀏覽器中&lt;text&gt;

+0

是不是不可能在不使用fsxl的情況下實現這一點? – keshav84 2010-07-20 13:49:16

+0

@ keshav.veerapaneni:這是可能的,但這是FXSL的目的:永遠不必手工編寫任何繁瑣的遞歸處理(並可能犯錯誤) - 只需使用存在於您的模板。另外,即使文本長度爲數百萬字符,我的解決方案也不會因堆棧溢出而崩潰。所選擇的模板(請參見''指令中的名稱)使用DVC(分而治之)式遞歸,這保證N = 1000000(1M)時最大遞歸深度僅爲log2(N) - 19。 – 2010-07-20 14:36:41

+0

嗨dimitre,我也寫了一個解決方案,我上面粘貼的反覆,請你建議,如果有任何優化可能溢出它 – keshav84 2010-07-20 17:23:28

2

的 「棘手遞歸處理」

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" omit-xml-declaration="yes"/> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="text()" name="text"> 
     <xsl:param name="text" select="."/> 
     <xsl:if test="$text != ''"> 
      <xsl:variable name="first" select="substring($text,1,1)"/> 
      <xsl:choose> 
       <xsl:when test="$first = '&lt;'">&amp;lt;</xsl:when> 
       <xsl:when test="$first = '&gt;'">&amp;gt;</xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$first"/> 
       </xsl:otherwise> 
      </xsl:choose> 
      <xsl:call-template name="text"> 
       <xsl:with-param name="text" select="substring($text,2,(string-length($text)-1) div 2 + 1)"/> 
      </xsl:call-template> 
      <xsl:call-template name="text"> 
       <xsl:with-param name="text" select="substring($text,(string-length($text)-1) div 2 + 3)"/> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

結果:

<one> 
&amp;lt;text&amp;gt; 
</one> 

EDIT:甲DVC圖案避免溢出。

+0

嗨alejandro,如果字符串很長,這不會導致stackoverflow? – keshav84 2010-07-20 14:13:24

+0

好的解決方案,但請參閱我的回答OP的意見,以我的答案。 FXSL是一種節省時間的工具,可以保護您免受錯誤的影響(在已經爲您編寫的代碼中,您必須一次又一次地寫入代碼)。 – 2010-07-20 14:38:42

+0

@Dimitre:我認爲FXSL不僅是一個概念的證明,也是一個優秀的設計模式。它顯示Temporaly Result(比如XSLT 2.0)比Result Tree Fragment更好的規範選擇,因爲它允許數據建模。我發佈了這個答案,因爲很多人(不是你)都害怕遞歸。 – 2010-07-20 15:27:54

0

我也寫過一個使用遞歸的解決方案,但我唯一擔心的是性能,以及是否會有一些內存或一些計算器因爲這一點。我想知道是否有任何解決方案使用< xsl:value-of>或< copy-of>?如果遞歸可以轉換爲循環等,請讓我知道下面的解決方案是否有任何改進。

<xsl:template match="text()" mode="literalHTML"> 
    <xsl:variable name="txt" select="."/> 
    <xsl:value-of select="smc:escapeChar(smc:escapeChar(smc:escapeChar($txt,'&amp;','&amp;amp;'),'&lt;','&amp;lt;'),'&gt;','&amp;gt;')"/> 
</xsl:template> 
<xsl:function name="smc:escapeChar"> 
    <xsl:param name="txt"/> 
    <xsl:param name="char"/> 
    <xsl:param name="subs"/> 
    <xsl:result> 
     <xsl:variable name="result"> 
      <xsl:choose> 
       <xsl:when test="contains($txt, $char)"> 
        <xsl:variable name="after" select="substring-after($txt,$char)"/> 
        <xsl:value-of select="substring-before($txt,$char)"/> 
        <xsl:value-of select="$subs"/> 
        <xsl:value-of select="smc:escapeChar($after,$char,$subs)"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$txt"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 
     <xsl:value-of select="$result"></xsl:value-of> 
     </xsl:result> 
</xsl:function> 
+0

當然,'contains()'更好,因爲處理器會做一些工作,但是這導致你調用函數爲每個字符反覆在同一個字符串。每個字符遞歸允許在XSLT 1.0中進行節點集合比較(當/ @ test中只有一個使用'$ first = $ characters',在樣式表或其他文檔中甚至是內聯的$字符某些節點集合映射時,替換每個字符。但對於XSLT 2.0(作爲答案),最好使用字符映射http://www.w3.org/TR/xslt20/#character-maps – 2010-07-20 17:44:18