如何在 XSLT 输出中控制名称空间前缀(特别是默认名称空间)?

Posted

技术标签:

【中文标题】如何在 XSLT 输出中控制名称空间前缀(特别是默认名称空间)?【英文标题】:How do I control namespace prefixes (specifically the default namespace) in XSLT output? 【发布时间】:2021-03-22 03:11:10 【问题描述】:

在 XSLT 中有什么方法可以控制输出元素中名称空间前缀的选择?

在我的特定情况下,我实际上想要转换看起来像的输入

<h:html xmlns:h='http://www.w3.org/1999/xhtml'
        xmlns:m='http://www.w3.org/1998/Math/MathML'>
....
<h:p>Equation: <m:math>...</m:math></h:p>

进入

<html xmlns='http://www.w3.org/1999/xhtml'>
....
<p>Equation: <math xmlns='http://www.w3.org/1998/Math/MathML'>...</math></p>

也就是说,一种简单地更改命名空间前缀的身份转换,以适当地为 XHTML 和 MathML 元素使用默认命名空间。

这是纯 XML 工作流结束时的整理步骤。以上当然在 XML 术语中是等价的,因此在 XHTML 术语中是等价的,但浏览器似乎并不总是知道这一点(在我不太系统的测试中,Firefox 管理上述两者,将它们呈现为数学 -干得好 Firefox!——Safari 管理第二个但不是第一个,Chrome 也不管理;我实际上是针对 EPUB 阅读器,但对那里的 XHTML 解析器持悲观态度似乎是明智的)。尝试使用&lt;output method='html'/&gt; XSLT 元素不会对输出产生影响。 XHTML Compatibility Guidelines 没有提到命名空间,这很令人惊讶。添加 doctype 声明,甚至是 &lt;meta http-equiv=''...&gt; hack 以提示 application/xhtml+xml,似乎对浏览器的行为没有任何影响。

在 XSLT 1.0 规范中我看不到任何东西来控制它。那里提到的命名空间别名解决了一个不同的问题;在 XSLT 中使用默认命名空间并没有提供任何 libxslt 似乎倾向于接受的提示。其他stackexchange 问题(例如this one 或this one)似乎很大程度上是对XSLT 和命名空间的误解。我确信在我漫长的 XSLT 过去的某个时刻我已经设法实现了这一点,但如果我做到了,我就无法恢复它。

我非常喜欢 XSLT 1.0 中的解决方案,因为我拥有可以快速使用的工具和经验,在 libxslt 和 xsltproc 中(Saxon 确实很棒,但我不愿意支付可能很多个连续转换的Java启动成本)。这可能是迫使我使用更高版本的 XSLT 的原因,当然,如果更高版本确实是唯一可以提供帮助的东西。

从(不是很透彻)查看 XSLT 3 规范(例如 section 11.1),我看不到任何明显解决此问题的内容。

如果我说错了树,或者如果已知 EPUB 处理器始终对命名空间更敏感,那么我实际上是在解决问题的错误部分,我也愿意接受这些信息.

【问题讨论】:

【参考方案1】:

你需要转型

<xsl:template match="*">
  <xsl:element name="local-name()" namespace="namespace-uri()">
     <xsl:apply-templates select="@* | node()"/>
  </xsl:element>
</xsl:template>

为其余部分设置身份转换模板。

而在 XSLT 1 中,您有点依赖 XSLT 处理器及其序列化程序来获得所需的输出,但我认为对于上述模板,即使在 1.0 世界中您也可以期待一些一致性。

【讨论】:

这看起来很有希望,并且在我尝试过的简单案例中确实有效。真正的代码当然比我的问题稍微复杂一些,但我会试一试,然后回到这个答案。 这在实践中确实工作得很好,从某种意义上说,这似乎为序列化程序提供了足够的提示。序列化程序没有完全接受提示(如您所建议的那样):在此构造中处理的任何包含例如 &lt;h:p xmlns:h='http://www.w3.org/1999/xhtml'&gt;...&lt;/h:p&gt; 的模板都不幸地使用该前缀进行序列化,而不是默认的前缀,此时仍在范围内。这意味着我不能将 XSLT 元素留在默认名称空间中,但是……我会活下去。谢谢,马丁,让我放心,我没有遗漏任何东西。

以上是关于如何在 XSLT 输出中控制名称空间前缀(特别是默认名称空间)?的主要内容,如果未能解决你的问题,请参考以下文章

在 XSLT 中匹配具有名称空间前缀的元素

XSLT:如何删除同义名称空间

删除 XSLT 映射生成的元素的名称空间前缀

重命名元素的 XSLT 问题——更改命名空间

如何使用 XSLT 替换命名空间中的元素?

xsd:any 元素的命名空间前缀并使用 XSLT 添加命名空间前缀