XSLT 1.0可以在select子句中的xmlns属性上使用变量吗?

时间:2017-03-17 15:04:35

标签: xml variables xslt namespaces xslt-1.0

我试图了解是否可以使用具有类似但不等于模式的xml文件重用XSLT 1.0 脚本,这些模式共享相同的命名空间前缀。

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

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

还有更多建议或者这是对XSLT 1.0的最终限制吗?

注意:由于我使用的是前缀,How to automatically propagate the XMLNS attribute from on XSL template to another中的答案不适用。

谢谢。

示例代码

以下有效:

<?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's "XSLT 1.0 Multiple Namespace Issues"中的示例)

sample1.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>

sample2.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"

2 个答案:

答案 0 :(得分:1)

您见证的问题是由不同的命名空间引起的:

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

因此,在一种情况下,您的模板会失败,因为<template...>的规则由于不同的名称空间前缀...2006!= {而不匹配{1}})。

因此,要创建一个忽略命名空间的模板,必须忽略 namespace-prefixes
这是通过仅考虑元素名称的...2012而不是全名来完成的。

例如,名称空间元素的名称可能是local-name() 因此emp:first会返回name()emp:first只返回local-name()

忽略名称空间前缀(在本例中为first)是通过仅关注所有相关元素的emp来实现的。

因此,以下模板由

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

整个模板看起来像这样

local-name()

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

答案 1 :(得分:0)

不,您不能将前缀绑定到变量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,以获得最终结果。