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 文件中的模式匹配似乎适用于名称空间前缀(与其相关的模式相反),所以该模式仅匹配其中一个变体。所以如果我写这样的东西:

【问题讨论】:

您使用的是哪种 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:如何删除同义名称空间的主要内容,如果未能解决你的问题,请参考以下文章

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

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

如何从xslt输出xml中删除xmlns =“”?

如何使用 XSLT 为所有元素和属性添加名称空间和前缀?

如何使用 XSLT 向 XML 有效负载添加不同的名称空间

如何使用 XSLT 将名称空间添加到我的 XML 的根元素?