无法处理cdata中的元素

时间:2014-12-08 21:50:19

标签: xml xslt xslt-1.0

我试图编辑CDATA中的链接:

 <paragraph>
    <![CDATA[
        <strong><a href="http://example.com/2014/12/08/article-title">Article Title</a></strong>Article Excerpt.
    ]]>
 </paragraph>

目标是将段落更改为<p>,同时在链接中添加其他标记。例如,所需的输出可以是:(并非所有<paragraph>都有链接,有些只包含文本)

<p>
    <strong><a href="http://example.com/2014/12/08/article-title?tacking_id=12345" style="font-size:1.1em; color:#067ab4; line-height:100%">Article Title</a></strong>Article Excerpt.
</p>

我尝试过以下代码,但它没有用。

<xsl:template match="paragraph">
    <xsl:copy-of select="@*"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[<p>]]></xsl:text>
    <xsl:value-of select="." disable-output-escaping="yes"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[</p>]]></xsl:text>
</xsl:template>

<xsl:template match="text()[contains(.,'&lt;a href=&#34;') and contains(.,'&#34;>')]">

    <xsl:variable name="link" select="substring-before(substring-after(., '&lt;a href=&#34;'), '&#34;>')"/>

    <xsl:text disable-output-escaping="yes"><![CDATA[<a href="]]></xsl:text>
    <xsl:value-of disable-output-escaping="yes" select="$link"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[&tracking_id=12345" ]]></xsl:text>
    <xsl:value-of select="$link_style"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[>]]></xsl:text>
    <xsl:apply-templates select="child::node()"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[</a>]]></xsl:text>

</xsl:template>

1 个答案:

答案 0 :(得分:4)

就XML处理器而言,paragraph节点中的CDATA不包含链接,标记或单个文本节点以外的任何内容。它只是一串字符,所以如果你真的想改变它,你必须采用一些棘手的字符串操作。

您遇到的第一个问题是,在模板匹配&#34;段落#34;中,您不执行任何xsl:apply-templates,因此您的第二个模板可以与{{{{}}下的文本节点匹配1}}永远不会被调用。

你的第一个模板应该是这样的

paragraph

现在,在与文本节点匹配的模板中,这是令人讨厌的地方,但你的主要问题是你做<xsl:template match="paragraph"> <p> <xsl:apply-templates /> </p> </xsl:template> 。但它是一个文本节点。单个文本节点。它没有可以匹配的子节点。

如果你真的,真的想让它以这种方式工作,模板看起来就像这样

<xsl:apply-templates select="child::node()"/>

这个答案可能说明为什么试图操纵CDATA是一个坏主意。

另一种不太令人不愉快的方法是进行两次XSLT转换。

第一个看起来像这样

<xsl:template match="text()[contains(.,'&lt;a href=&#34;') and contains(.,'&#34;>')]">
    <xsl:variable name="firstbit" select="substring-before(., '&lt;a href=&#34;')"/>
    <xsl:variable name="link" select="substring-before(substring-after(., '&lt;a href=&#34;'), '&#34;>')"/>
    <xsl:variable name="lastbit" select="substring-after(substring-after(., '&lt;a href=&#34;'), '&#34;>')"/>

    <xsl:value-of disable-output-escaping="yes" select="$firstbit"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[<a href="]]></xsl:text>
    <xsl:value-of disable-output-escaping="yes" select="$link"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[?tracking_id=12345" ]]></xsl:text>
    <xsl:value-of select="$link_style"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[>]]></xsl:text>
    <xsl:value-of disable-output-escaping="yes" select="$lastbit"/>
</xsl:template>

这将输出以下内容:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="paragraph">
        <p>
            <xsl:value-of disable-output-escaping="yes" select="." />
        </p>
    </xsl:template>
</xsl:stylesheet>

然后对此进行必要的转换<p> <strong><a href="http://example.com/2014/12/08/article-title">Article Title</a></strong>Article Excerpt. </p> 标记变得微不足道了......

a

然后输出以下内容:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="a">
        <a href="{@href}?tracking_id=12345" style="color:#067ab4;">
            <xsl:apply-templates />
        </a>
    </xsl:template>
</xsl:stylesheet>

因此,如果您可以更改输入XML以消除CDATA,那么它将变得更加轻松......