XSLT:如何删除同义名称空间
Posted
技术标签:
【中文标题】XSLT:如何删除同义名称空间【英文标题】:XSLT: How to remove synonymous namespaces 【发布时间】:2011-07-16 00:35:28 【问题描述】:我有大量的 XML 文件需要使用 XSLT 进行转换。问题是这些文件中有许多是由不同的人手写的,并且它们没有使用一致的名称来引用模式。例如,一个文件可能使用:
xmlns:itemType="http://example.com/ItemType/XSD"
其他人可能会使用前缀“it”而不是“itemType”:
xmlns:it="http://example.com/ItemType/XSD"
如果这还不够糟糕,还有几个文件使用两个或三个同义词来表示同一件事!
(显然有很多剪切和粘贴操作)
现在,因为 XSLT 文件中的模式匹配似乎适用于名称空间前缀(与其相关的模式相反),所以该模式仅匹配其中一个变体。所以如果我写这样的东西:
... 模板>然后它只匹配我想要它的案例的一个子集。
问题 1: 有没有办法让 XSLT 匹配所有变体?
问题 2: 有没有办法删除重复项,以便所有输出文件使用一致的命名?
我天真地尝试使用“命名空间别名”,但我想我误解了它的作用,因为我根本无法让它做任何事情 - 要么匹配所有变体,要么影响输出 XML。
【问题讨论】:
您使用的是哪种 XSLT 处理器? XSLT 应该使用 URI 进行匹配,而不是文本前缀。 xsltproc --version 使用 libxml 20626、libxslt 10117 和 libexslt 813 xsltproc 是针对 libxml 20626、libxslt 10117 和 libexslt 813 编译的 libxslt 10117 是针对 libxml 20626 编译的 libexslt 813 是针对 libxml 20626 编译的显然,构建,但我相信我们也有一个行为相同的 windows 目标。 嗯,这确实很令人困惑。看起来它有时确实匹配变体,但有时不匹配。我将尝试找出导致不同行为的原因。如果它确实使用 URI 而不是前缀,那么这将消除第一个问题。在哪种情况下,您知道后续问题的任何答案吗? 好的,我更新了问题以反映一个绝对不匹配的实例。可能是因为在那个例子中“itemType”的用法有点复杂。 查看我的答案以获得解释和 XSLT 1.0 解决方案。 【参考方案1】:除非您明确说明,否则不会将属性值或文本节点强制转换为 QName。虽然这仅在 XSLT/XPath 2.0 中可行
在 XSLT/XPath 1.0 中,您必须“手动”执行此操作:
<xsl:template match="SomeNode">
<xsl:variable name="vPrefix" select="substring-before(@xsi:type,':')"/>
<xsl:variable name="vNCName"
select="translate(substring-after(@xsi:type,$vPrefix),':','')"/>
<xsl:if test="namespace::*[
name()=$vPrefix
] = 'http://example.com/ItemType/XSD'
and
$vNCName = 'SomeType'">
<!-- Content Template -->
<xsl:if>
</xsl:template>
编辑:多合一模式(可能不太可读):
<xsl:template match="SomeNode[
namespace::*[
name()=substring-before(../@xsi:type,':')
] = 'http://example.com/ItemType/XSD'
and
substring(
concat(':',@xsi:type),
string-length(@xsi:type) - 7
) = ':SomeType'
]">
<!-- Content Template -->
</xsl:template>
【讨论】:
效果很好,非常感谢!我猜第二个版本更好,因为它自动匹配,但我还是使用第一个版本,因为我不确定第二个版本中的“-7”是做什么用的。这意味着我必须在其中使用另一个“if”来处理匹配“SomeNode”但不匹配内部条件的节点,如果这一切都有意义的话。 @Andrew:不客气。第二个条件是 XPath 1.0“以”结尾的表达式:substring( $str, string-length( $str ) - string-lenght( $sub ) + 1 ) = $sub
【参考方案2】:
在 XSLT 2.0 中(无论您是否使用模式感知),您都可以将谓词编写为 [@xsi:type=xs:QName('it:SomeType')]
,其中“it”是此命名空间的样式表中声明的前缀。它不必与源文档中使用的前缀相同。
在 XSLT 1.0 和 XSLT 2.0 中,元素和属性名称的匹配(与 QName 值的内容不同)当然使用名称空间 URI 而不是前缀。
【讨论】:
+1 正确示例。这就是我所说的 XSLT/XPath 2.0 转换。以上是关于XSLT:如何删除同义名称空间的主要内容,如果未能解决你的问题,请参考以下文章