使用应用模板在 XSLT 输出中保留   和其他特殊字符

Posted

技术标签:

【中文标题】使用应用模板在 XSLT 输出中保留   和其他特殊字符【英文标题】:Keep   and other special characters in XSLT output with apply-templates 【发布时间】:2012-09-16 18:27:27 【问题描述】:

我正在使用 XSLT 从 XML 文件中提取一些带有特殊字符(如  )的 html 内容。内容存储在<content> 节点中。我已经定义了像这样的大多数特殊字符:<!ENTITY nbsp " ">,所以这个表达式工作得很好:

<xsl:copy-of select="content" disable-output-escaping="yes"/>

现在,我想将target="_blank" 添加到该内容中的每个链接。这是我想出的解决方案:

<xsl:template match="a" mode="html">
    <a>
        <xsl:attribute name="href"><xsl:value-of select="@*"/></xsl:attribute>
        <xsl:attribute name="target">_blank</xsl:attribute>
        <xsl:apply-templates select="text()|* "/>
    </a>
</xsl:template>

而不是“复制”元素,我使用这个:

<xsl:apply-templates select="content" mode="html"/>

现在所有这些特殊字符(以及 nbsp 也是)从输出中消失了。我该如何保留它们?似乎disable-output-escaping="yes" 在这里没有帮助。

好的,我在 php 中使用 XSLTProcessor 类。 disable-output-escaping 属性实际上并没有报错,但是当我删除它时,输出是一样的,所有 nbsp 的,所以没关系。


UPD。使用我之前展示的 XSL 模板,我的输入示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE page SYSTEM "html-entities.xsl">
<content>There is a&nbsp;non-breaking <a href="http://localhost">space</a> inside.</content>

html-entities.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY nbsp "&#160;">

PHP 代码:

$xp = new XSLTProcessor();
$xsl = new DOMDocument();
$xsl->load($xsl_filename);
$xp->importStylesheet($xsl);
$xml_doc = new DOMDocument();
$xml_doc->resolveExternals = true;
$xml_doc->load($xml_filename);
$html = $xp->transformToXML($xml_doc);

我目前的输出:

There is anon-breaking &lt;a href="http://localhost" target="_blank"&gt;space&lt;/a&gt; inside.

我想要的输出:

There is a&amp;nbsp;non-breaking &lt;a href="http://localhost" target="_blank"&gt;space&lt;/a&gt; inside.

【问题讨论】:

是否可以显示您的“内容”XML 示例?谢谢! 我在w3.org/TR/xslt20/#copy-of 中的copy-of 元素上看不到任何disable-output-escaping 属性,所以我希望您的代码示例&lt;xsl:copy-of select="content" disable-output-escaping="yes"/&gt; 只会由XSLT 处理器给出错误。考虑向我们展示有关输入样本、所需输出、当前输出和您使用的 XSLT 处理器的更多详细信息。 好的,我在 PHP 中使用 XSLTProcessor 类。 disable-output-escaping 属性实际上并没有报错,但是当我删除它时,输出是一样的。 更新了我的问题,请您的想法... 【参考方案1】:

基本上,输入 XML 文档的源代码是否具有像 &amp;#160; 这样的字符引用或像 &amp;nbsp; 这样的实体引用,或者这样的字符对于 XSLT 来说并不重要,也不会影响输入的处理方式以及输出的外观;基本上,XSLT 在一个树上运行,Unicode 字符存储在文本节点中。至少理论上是这样,您的 PHP 代码似乎可以与 DOM 树模型一起使用,该模型可能存储实体引用节点,但即便如此,对于 XSLT 来说也无关紧要。在输入树中应该有包含 Unicode 字符的文本节点(如果可能是 Unicode 160 的不间断空格字符),如果将这样的文本复制到输出,则结果树有一个文本节点具有相同的 Unicode 字符.

对于输出方法html,一些 XSLT 处理器(例如 Saxon 6.5.5)可能会帮助您确保在 HTML 中定义为实体的字符使用相应的实体引用进行序列化,但即使它们不这样做结果树的序列化应该是具有正确 Unicode 字符的文件,按照xsl:output 元素的encoding 属性的指示进行编码。

您当前完全删除字符的结果(例如There is anon-breaking)对我来说没有意义。

【讨论】:

您认为我的将target="_blank" 属性添加到链接的模板的编写方式正确吗? 我认为模板并不重要,因为不间断空格甚至不在 a 元素内,而是在兄弟文本节点内。如果我要写这样一个模板,我会使用&lt;xsl:template match="a[@href]"&gt;&lt;a target="_blank"&gt;&lt;xsl:copy-of select="@*"/&gt;&lt;xsl:apply-templates/&gt;&lt;/a&gt;&lt;/xsl:template&gt;。在您的尝试中,&lt;xsl:attribute name="href"&gt;&lt;xsl:value-of select="@*"/&gt;&lt;/xsl:attribute&gt; 看起来很奇怪,因为它用@* 而不是@href 填充href(并且@* 将采用当前实现在代码运行中认为第一个属性的值)。

以上是关于使用应用模板在 XSLT 输出中保留   和其他特殊字符的主要内容,如果未能解决你的问题,请参考以下文章

应用所有模板

XSLT 转换从混合内容中删除 HTML 元素

xslt for-each 和排序问题

XSLT:分析字符串并保留子节点

Selenium 不可见使用 XSLT 模板创建的元素

使用php应用XSLT,但保留原始的xml结构