XSLT 1.0 是否可以在选择子句中使用 xmlns 属性上的变量?



我试图了解是否有可能使XSLT1.0脚本可与具有相似但不相等的架构共享相同命名空间前缀的xml文件重用。

变量ns-uri包含所需的命名空间,但似乎 XSLT 1.0 无法识别xmlns:emp='$ns-uri'中的这种用法,尽管将同一属性与带有命名空间的字符串一起使用是有效的。

我不想遵循使用构造*[name()='emp:department']的建议,因为这会使 xslt 完全不可读。

还有其他建议,或者这是对 XSLT 1.0 的最终限制吗?

注意:由于我使用的是前缀,因此如何将 XMLNS 属性从 XSL 模板自动传播到另一个模板中的答案不适用。

谢谢。


示例代码

以下方法不起作用

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="ns-uri" select="/child::*[1]/namespace-uri()"/>
<xsl:template match="emp:employee" xmlns:emp="http://www.example.com/ns/employee/2006">
First Name "<xsl:value-of select="emp:first" xmlns:emp="http://www.example.com/ns/employee/2006"/>"
Last Name  "<xsl:value-of select="emp:last"  xmlns:emp='$ns-uri'/>"
Department "<xsl:value-of select="*[name()='emp:department']"/>"
</xsl:template>
</xsl:stylesheet>

我使用这些 xml 文件作为示例(来自 Finnbarr P. Murphy 的"XSLT 1.0 多命名空间问题"中的示例)

样本1.xml

<?xml version="1.0"?>
<emp:root xmlns:emp="http://www.example.com/ns/employee/2006">
<emp:employee status="Guru">
<emp:first>John</emp:first>
<emp:last>Kane</emp:last>
<emp:department>IT</emp:department>
<emp:country>IE</emp:country>
</emp:employee>
</emp:root>

样本2.xml

<?xml version="1.0"?>
<emp:root xmlns:emp="http://www.example.com/ns/employee/2012">
<emp:employee status="Guru">
<emp:first>John</emp:first>
<emp:last>Kane</emp:last>
<emp:department>IT</emp:department>
<emp:country>IE</emp:country>
</emp:employee>
</emp:root>

在这两种情况下,所需的结果应该是:

First Name "John"
Last Name  "Kane"
Department "IT"

您看到的问题是由不同的命名空间引起的:

  • sample1.xmlemp命名空间定义为"xmlns:emp="http://www.example.com/ns/employee/2006"
  • sample2.xmlemp命名空间定义为"xmlns:emp="http://www.example.com/ns/employee/2012"

因此,在一种情况下,您的模板将失败,因为由于命名空间前缀不同(...2006!=...2012),其<template...>规则将不匹配。


因此,要创建一个忽略命名空间的模板,必须忽略命名空间前缀
这是通过仅关注元素名称的local-name()而不是整个名称来完成的。

例如,命名空间元素的名称可能emp:first
所以name()会返回emp:first,而local-name()只会返回first.

忽略命名空间前缀(在本例中为emp)是通过只关注所有相关元素的local-name()来实现的。

所以下面的模板是由

  • 使用*选择所有元素
  • 并使用谓词[local-name() = '...']来限制这组元素,该谓词该谓词检查local-name()匹配的元素

整个模板如下所示

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="*[local-name() = 'employee']">
First Name "<xsl:value-of select="*[local-name() = 'first']" />"
Last Name  "<xsl:value-of select="*[local-name() = 'last']" />
Department "<xsl:value-of select="*[local-name() = 'department']" />"
</xsl:template>
</xsl:stylesheet>

并为两个 XML 输入文件返回相同的结果。

不可以,不能将前缀绑定到变量 URI。

但是,前缀本身没有意义 - 只有 URI 很重要。如果您知道预期的命名空间 URI 是什么,则可以将它们中的每一个绑定到其自己的前缀并同时使用两者,例如:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:emp6="http://www.example.com/ns/employee/2006"
xmlns:emp12="http://www.example.com/ns/employee/2012">
<xsl:output method="text"/>
<xsl:template match="emp6:employee | emp12:employee">
First Name "<xsl:value-of select="emp6:first | emp12:first"/>"
Last Name  "<xsl:value-of select="emp6:last | emp12:last" />"
Department "<xsl:value-of select="emp6:department | emp12:department"/>"
</xsl:template>
</xsl:stylesheet>

另一种选择是从传入的 XML 中获取命名空间 URI(就像您开始做的那样),并使用它来生成 XSLT 样式表,其中(常量)前缀绑定到提取的 URI。

然后将生成的样式表应用于原始XML以获得最终结果。

相关内容

  • 没有找到相关文章