在<xsl:attribute> </xsl:attribute>中包含HTML节点

时间:2013-09-04 22:34:56

标签: xml xslt symphony-cms

我想在元素的属性中包含HTML(对于此处使用的数据清除属性:http://foundation.zurb.com/docs/components/clearing.html)。我的<caption>数据有两种可用方式:

<caption mode="formatted">
    <p>A fairly long looking <a href="http://www.stackoverflow.com">caption with a link</a> that goes to an external site.</p>
</caption>
<caption mode="unformatted">
    <![CDATA[A fairly long looking <a href="http://www.stackoverflow.com">caption with a link</a> that goes to an external site.]]>
</caption>

这是我的模板:

<xsl:template match="images/entry">
    <!-- process contents of caption node-->
    <xsl:variable name="cap">
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
        <xsl:apply-templates select="caption/*" mode="html" />
        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:variable>

    <li>
        <xsl:copy-of select="$cap"/> //outside of attribute it works
        <img>
            <xsl:attribute name="src">/image/2/150/112/5<xsl:value-of select="@path"/>/<xsl:value-of select="filename"/></xsl:attribute>
            <xsl:attribute name="data-caption">
                <xsl:copy-of select="$cap"/> //inside of attribute it removes the <a> tag
            </xsl:attribute>
        </img>
    </li>
</xsl:template>

mode=html<a>节点中的<caption>标记与此模板匹配:

<!-- mark external links -->
<xsl:template match="a" mode="html">
<a href="{@href}" title="{@title}">
    <xsl:if test="number(substring(@href,1,4)='http')">
        <xsl:attribute name="class">external</xsl:attribute>
        <xsl:attribute name="target">_blank</xsl:attribute>
    </xsl:if>
    <xsl:apply-templates select="* | @* | text()" mode="html"/>
</a>
</xsl:template>

如果我使用“未格式化”标题,它会保留<a>标记(所需行为)。但是,当我使用该标题时,我无法使用“标记外部链接”模板来修复<a>标记。使用“格式化”标题,我可以像我想的那样处理<a>标记,但是当我在xsl:copy-of <img>内使用<xsl:attribute>时,它会丢失。它将在属性外显示,如下所示:

<![CDATA[<p>A fairly long looking <a href="http://www.stackoverflow.com" title="" class="external" target="_blank">caption with a link</a> that goes to an external site.</p>]]>

有没有办法让我的最终结果看起来像:

<img src="/image/2/150/112/5/images/my-image.jpg" 
    data-caption="<![CDATA[A fairly long looking <a class="external" target="_blank" href="http://www.stackoverflow.com">caption with a link</a> that goes to an external site.]]>;" />

感谢阅读。

1 个答案:

答案 0 :(得分:3)

首先,让我们清楚你没有在你的属性中包含“节点”;你想要的是序列化包含XML标记的属性。我们在词汇级别而不是树级别进行讨论,节点仅存在于树级别。

要生成此输出,有两个挑战。首先,您需要构造一个包含词法XML的字符串,然后将此字符串作为属性的值传递。其次,您需要防止此字符串中的特殊字符被转义。

对于第一个问题,有两种方法:您可以调用外部serialize()函数,将树转换为词汇XML作为字符串,如saxon:serialize()如果您使用Saxon,或者您可以编写你自己的(对于简单的情况来说并不困难,而且已经完成了--David Carlisle在XSLT中编写了一个完整的XML序列化程序。)

第二个问题很棘手。 XSLT序列化规范(所有版本)坚持HTML序列化方法不应该转义为“&lt;”出现在属性值中,但它对“&gt;”几乎没什么可说的。撒克逊逃脱“&gt;”作为"&gt;",表面上是因为这是旧版浏览器所需要的(现在可能已经很老了!),但我不认为这是规范所要求的,其他处理器可能会有所不同。禁用 - 输出 - 转义对属性值不起作用,因此您可能不得不使用disable-output-escaping手动构建整个元素序列化。或者,使用XSLT 2.0,您可以使用字符映射来强制输出“&gt;”在属性值中。

在您的示例代码中,您在编写变量值时使用disable-output-escaping。在规范中有一个yoyo历史。 XSLT 1.0的错误(所谓的“粘性doe”错误)表示允许,但在XSLT 2.0中这是相反的,因为它与允许对变量中保存的结果树片段进行完全导航访问是不兼容的。所以最重要的是,根据您使用的处理器,它可能会也可能不会起作用 - 当然,一般来说,禁用 - 输出 - 逃避也是如此。

对此要求的完全不同的解决方案可能是输出不同的东西 - 例如使用V形代替尖括号 - 然后通过文本过滤器过滤序列化输出,该过滤器将相关字符替换为您实际需要的字符。 / p>