2011-03-20 44 views
1

我的問題是如何un-escape已經轉義的xml。如何在XSLT的幫助下使用轉義XML內容?

我嘗試了Tomalak提供的代碼來回應How to unescape XML characters with help of XSLT?,但我無法做到我想做的。

我有SoapMsg Xml。正文包含一些元素,其中一個是String。該字符串 包含Escaped XML。這通常在RPC SoapMsg中完成,因爲它們不允許使用複雜的 類型。爲了解決這個問題,他們將Escaped-Xml嵌入到String元素中,請參閱下面的輸入中的sXmlParameters

例輸入:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:pan="http://wsdl.somebody.com/Stuff/"> 
    <soap:Header /> 
    <soap:Body> 
    <pan:SomeCommand> 
     <first>eefbb52a0fee443cbda838caffbc2654</first> 
     <second>f26eb2f5dabc457ca045e64585f7b185</second> 
     <sXmlParameters>&lt;PARAMETERS&gt;&lt;TIMEOUTDATETIME&gt;2011-03-15 
     2:09:48.997&lt;/TIMEOUTDATETIME&gt;&lt;/PARAMETERS&gt;</sXmlParameters> 
    </pan:SomeCommand> 
    </soap:Body> 
</soap:Envelope> 

我也看到<![CDATA[>]]>這個數據逃了出來,我需要取消逃避它也。

轉換的輸出:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:pan="http://wsdl.somebody.com/Stuff/"> 
    <soap:Header /> 
    <soap:Body> 
    <pan:SomeCommand> 
     <first>eefbb52a0fee443cbda838caffbc2654</first> 
     <second>f26eb2f5dabc457ca045e64585f7b185</second> 
     <sXmlParameters> 
     <PARAMETERS> 
      <TIMEOUTDATETIME>2011-03-15 2:09:48.997</TIMEOUTDATETIME> 
     </PARAMETERS> 
     </sXmlParameters> 
    </pan:SomeCommand> 
    </soap:Body> 
</soap:Envelope> 
+0

您可以編輯題。請不要發佈答案。這是一個Q/A網站,而不是論壇。 – dandan78 2011-03-21 18:20:08

+0

@ user668595:SOAP允許嵌入詞彙表。爲什麼這個可怕的設計選擇呢? – 2011-03-23 00:36:29

回答

1

這會已經把你的問題的一半的護理 - 而不是CDATA部分:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="//sXmlParameters"> 
     <xsl:copy> 
      <xsl:call-template name="unescape"> 
       <xsl:with-param name="escaped" select="string(.)"/> 
      </xsl:call-template> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template name="unescape"> 
     <xsl:param name="escaped"/> 
     <xsl:choose> 
      <xsl:when test="contains($escaped,'&lt;')"> 
       <xsl:variable name="beforeelem" select="substring-before($escaped,'&lt;')"/> 
       <xsl:variable name="elemname1" select="substring-before(substring-after($escaped,'&lt;'),' ')"/> 
       <xsl:variable name="elemname2" select="substring-before(substring-after($escaped,'&lt;'),'&gt;')"/> 
       <xsl:variable name="elemname3" select="substring-before(substring-after($escaped,'&lt;'),'/&gt;')"/> 
       <xsl:variable name="hasattributes" select="string-length($elemname1) &gt; 0 and ((string-length($elemname2)=0 or string-length($elemname1) &lt; string-length($elemname2)) and (string-length($elemname3)=0 or string-length($elemname1) &lt; string-length($elemname3)))"/> 
       <xsl:variable name="elemclosed" select="string-length($elemname3) &gt; 0 and (string-length($elemname2)=0 or string-length($elemname3) &lt; string-length($elemname2))"/> 
       <xsl:variable name="elemname"> 
        <xsl:choose> 
         <xsl:when test="$hasattributes"> 
          <xsl:value-of select="$elemname1"/> 
         </xsl:when> 
         <xsl:when test="not($elemclosed)"> 
          <xsl:value-of select="$elemname2"/> 
         </xsl:when> 
         <xsl:otherwise> 
          <xsl:value-of select="$elemname3"/> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:variable> 
       <xsl:variable name="elemclosetag" select="concat('&lt;/',$elemname,'&gt;')"/> 
       <xsl:variable name="innercontent"> 
        <xsl:if test="not($elemclosed)"> 
         <xsl:call-template name="skipper-before"> 
          <xsl:with-param name="source" select="substring-after(substring-after($escaped,'&lt;'),'&gt;')"/> 
          <xsl:with-param name="delimiter" select="$elemclosetag"/> 
         </xsl:call-template> 
        </xsl:if> 
       </xsl:variable> 
       <xsl:variable name="afterelem"> 
        <xsl:choose> 
         <xsl:when test="not($elemclosed)"> 
          <xsl:call-template name="skipper-after"> 
           <xsl:with-param name="source" select="substring-after(substring-after($escaped,'&lt;'),'&gt;')"/> 
           <xsl:with-param name="delimiter" select="$elemclosetag"/> 
          </xsl:call-template> 
         </xsl:when> 
         <xsl:otherwise> 
          <xsl:value-of select="substring-after(substring-after($escaped,'&lt;'),'/&gt;')"/> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:variable> 
       <xsl:element name="{$elemname}"> 
        <xsl:if test="$hasattributes"> 
         <xsl:call-template name="unescapeattributes"> 
          <xsl:with-param name="escapedattributes"> 
           <xsl:choose> 
            <xsl:when test="not($elemclosed)"> 
             <xsl:value-of select="normalize-space(substring-after($elemname2,' '))"/> 
            </xsl:when> 
            <xsl:otherwise> 
             <xsl:value-of select="normalize-space(substring-after($elemname3,' '))"/> 
            </xsl:otherwise> 
           </xsl:choose> 
          </xsl:with-param> 
         </xsl:call-template> 
        </xsl:if> 
        <xsl:call-template name="unescape"> 
         <xsl:with-param name="escaped" select="$innercontent"/> 
        </xsl:call-template> 
       </xsl:element> 
       <xsl:call-template name="unescape"> 
        <xsl:with-param name="escaped" select="$afterelem"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:call-template name="unescapetext"> 
        <xsl:with-param name="escapedtext" select="$escaped"/> 
       </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template name="unescapeattributes"> 
     <xsl:param name="escapedattributes"/> 
     <xsl:variable name="attrname" select="substring-before($escapedattributes,'=')"/> 
     <xsl:variable name="attrquote" select="substring($escapedattributes,string-length($attrname)+2,1)"/> 
     <xsl:variable name="attrvalue" select="substring-before(substring-after($escapedattributes,$attrquote),$attrquote)"/> 
     <xsl:variable name="afterattr" select="substring-after(substring-after($escapedattributes,$attrquote),$attrquote)"/> 
     <xsl:attribute name="{$attrname}"> 
      <xsl:call-template name="unescapetext"> 
       <xsl:with-param name="escapedtext" select="$attrvalue"/> 
      </xsl:call-template> 
     </xsl:attribute> 
     <xsl:if test="contains($afterattr,'=')"> 
      <xsl:call-template name="unescapeattributes"> 
       <xsl:with-param name="escapedattributes" select="normalize-space($afterattr)"/> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template name="unescapetext"> 
     <xsl:param name="escapedtext"/> 
     <xsl:call-template name="string-replace-all"> 
      <xsl:with-param name="text"> 
       <xsl:call-template name="string-replace-all"> 
        <xsl:with-param name="text"> 
         <xsl:call-template name="string-replace-all"> 
          <xsl:with-param name="text" select="$escapedtext"/> 
          <xsl:with-param name="replace">&amp;gt;</xsl:with-param> 
          <xsl:with-param name="by">&gt;</xsl:with-param> 
         </xsl:call-template> 
        </xsl:with-param> 
        <xsl:with-param name="replace">&amp;lt;</xsl:with-param> 
        <xsl:with-param name="by">&lt;</xsl:with-param> 
       </xsl:call-template> 
      </xsl:with-param> 
      <xsl:with-param name="replace">&amp;amp;</xsl:with-param> 
      <xsl:with-param name="by">&amp;</xsl:with-param> 
     </xsl:call-template> 
    </xsl:template> 

    <!-- replaces substrings in strings --> 
    <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> 

    <!-- returns the substring after the last delimiter --> 
    <xsl:template name="skipper-after"> 
     <xsl:param name="source"/> 
     <xsl:param name="delimiter"/> 
     <xsl:choose> 
      <xsl:when test="contains($source,$delimiter)"> 
       <xsl:call-template name="skipper-after"> 
        <xsl:with-param name="source" select="substring-after($source,$delimiter)"/> 
        <xsl:with-param name="delimiter" select="$delimiter"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$source"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <!-- returns the substring before the last delimiter --> 
    <xsl:template name="skipper-before"> 
     <xsl:param name="source"/> 
     <xsl:param name="delimiter"/> 
     <xsl:param name="result"/> 
     <xsl:choose> 
      <xsl:when test="contains($source,$delimiter)"> 
       <xsl:call-template name="skipper-before"> 
        <xsl:with-param name="source" select="substring-after($source,$delimiter)"/> 
        <xsl:with-param name="delimiter" select="$delimiter"/> 
        <xsl:with-param name="result"> 
         <xsl:if test="result!=''"> 
          <xsl:value-of select="concat($result,$delimiter)"/> 
         </xsl:if> 
         <xsl:value-of select="substring-before($source,$delimiter)"/> 
        </xsl:with-param> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$result"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 
+0

答案應該是解析未解析的數據。你認爲你在這裏有一個好的XML解析器嗎? – 2011-03-23 00:34:21

+0

@Ajjandro:xslt輸出請求的結果(針對給定的輸入進行測試)。 xslt基於一些轉換來註釋/取消部分xml文檔的註釋。想想看,還有更多的缺失,而不僅僅是對CDATA的支持:「/」/處理指令/ ...沒有專門處理。 – mousio 2011-03-23 09:33:30

+0

此版本不處理'
'。 '/'前面的空格導致'$ hasattributes = true'。另外,它不輸出'$ beforeelem'。我也將擴展我的處理實體...你有這個模板在github或其他地方我可以提供更改嗎? – Emyr 2014-06-06 15:05:24

0

我發現我可以使用撒克遜爲此在一個多更簡單的方法使用以下內容:

<xsl:template match="SomeCommand"> 
    <sXmlParameters> 
     <xsl:apply-templates select="saxon:parse(.)" /> 
    </sXmlParameters> 
    </xsl:template> 

還有撒克遜:seriralize()可用於逃脫t他xml的

感謝所有爲你輸入

0

寫了XML的轉義字符串SAX解析器在純XSL 1.0 + EXSLT

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:pxml="https://github.com/ilyakharlamov/pure-xsl/parseStringAsXML" 
    version="1.0"> 
    <xsl:import href="https://raw.githubusercontent.com/ilyakharlamov/pure-xsl/master/parseStringAsXML.xsl"/> 
    <xsl:template match="/"> 
     <xsl:call-template name="pxml:parseStringAsXML"> 
      <xsl:with-param name="string">&lt;PARAMETERS&gt;&lt;TIMEOUTDATETIME&gt;2011-03-152:09:48.997&lt;/TIMEOUTDATETIME&gt;&lt;/PARAMETERS&gt;</xsl:with-param> 
     </xsl:call-template> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<PARAMETERS> 
    <TIMEOUTDATETIME>2011-03-152:09:48.997</TIMEOUTDATETIME> 
</PARAMETERS>