如何在XSLT中替换CDATA中的标记

时间:2016-06-12 18:06:42

标签: xml xslt

我有一个要求,我需要在CDATA中替换特定标签。 例如,

<MASTER_COMMENTS>
<![CDATA[<pre> Nice Work done </pre>]]>
</MASTER_COMMENTS>

<MASTER_COMMENTS>
<![CDATA[<span> Nice Work done </span>]]>
</MASTER_COMMENTS>

使用XSLT子模板。

你能帮我写一下吗?

我尝试了以下但是它无效

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="//MASTER_COMMENTS"/>

 <xsl:template match="pre">
      <span><xsl:value-of select="."/></span>
 </xsl:template>

4 个答案:

答案 0 :(得分:1)

<xsl:template match="pre">

将不会匹配输入中的任何内容,因为CDATA部分包含纯文本数据,而不包含XML标记。

如果可以,请在两次传递中进行转换:首先,禁用MASTER_COMMENTS上的输出转义并将结果保存到文件中;然后将生成的文件作为“普通”XML处理。

或者,您可以尝试使用字符串函数处理内容,例如:

<xsl:template match="MASTER_COMMENTS">
    <xsl:copy>
        <xsl:value-of select="substring-before(., '&lt;pre&gt;')" />
        <xsl:text>&lt;span&gt;</xsl:text>
        <xsl:value-of select="substring-before(substring-after(., '&lt;pre&gt;'),'&lt;/pre&gt;') " />
        <xsl:text>&lt;/span>&gt;</xsl:text>
        <xsl:value-of select="substring-after(., '&lt;/pre&gt;') " />
    </xsl:copy>
</xsl:template>

请注意,此示例假定处理后的文本中只有一个pre“元素”。

答案 1 :(得分:1)

这是一个使用parse-xmlserialize来实现要求的XSLT 3.0样式表,它对Saxon 9.7 HE工作正常:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:output cdata-section-elements="MASTER_COMMENTS"/>

    <xsl:template match="MASTER_COMMENTS">
        <xsl:copy>
            <xsl:variable name="content">
                <xsl:apply-templates select="parse-xml(.)"/>
            </xsl:variable>
            <xsl:variable name="ser-params">
                <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
                    <output:omit-xml-declaration value="yes"/>
                </output:serialization-parameters>
            </xsl:variable>
            <xsl:value-of select="serialize($content, $ser-params/*)"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="pre">
        <span>
            <xsl:apply-templates/>
        </span>
    </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="UTF-8"?><MASTER_COMMENTS><![CDATA[<span> Nice Work done </span>]]></MASTER_COMMENTS>

答案 2 :(得分:0)

嗯,你可以,但是你必须使用文本替换而不是模板匹配...请注意,如果您可能没有<pre>或甚至多于一个的情况,这将非常困难这样的标签要被替换。如果这是你的样式表主要是关于什么,我建议使用文本转换

<xsl:transform version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text" />

<xsl:template match="/">
    <xsl:text>&lt;TOP></xsl:text>
        <xsl:apply-templates/>
    <xsl:text>&lt;/TOP></xsl:text>
</xsl:template>

<xsl:template match="MASTER_COMMENTS">
    <xsl:text>&lt;MASTER_COMMENTS></xsl:text>
        <xsl:value-of select="."/>
    <xsl:text>&lt;/MASTER_COMMENTS></xsl:text>
</xsl:template>

</xsl:transform>

使内容可用作“文本”,然后使用该文本作为xml输入进行转换,然后可以使用普通模板匹配CDATA部分中的内容。

对于文本方法,请参阅michael.hor257k的答案。

答案 3 :(得分:0)

如果包含XML标记的节点被错误地标记为CDATA,那么XML解析器将只返回字符数据,并且要提取标记,您需要将此字符数据放入第二阶段的解析。您可以通过调用parse-xml()函数在XSLT 3.0中执行此操作;在其他XSLT处理器中,您可以使用扩展功能执行相同的操作。