【问题标题】:Map XSLT input document prefixes to preferred values将 XSLT 输入文档前缀映射到首选值
【发布时间】:2011-03-19 06:01:16
【问题描述】:

使用 XSLT,我想知道如何让输出使用我的样式表的名称空间前缀而不是输入文档的前缀。举个例子,给定这个非常简化的文档:

<?xml version="1.0"?>
<a:node xmlns:a="urn:schemas:blah:"/>

以及以下 XSL 转换:

<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:blah="urn:schemas:blah:" version="2.0">
   <xsl:output indent="yes">
   <xsl:template match="/blah:node">
      <xsl:copy/><!-- marked -->
   </xsl:template>
</xsl:transform>

我可以说处理器(Saxon8,如果重要的话)识别前缀'blah:'和'a:'的等价性,但是fn:in-scope-prefixes() 例如不显示'blah',只显示'a'。将上面的&lt;!-- marked --&gt; 行更改为:

<node><xsl:value-of select="in-scope-prefixes(.)"/></node>

输出:

<?xml version="1.0" encoding="UTF-8"?>
<node xmlns:blah="urn:schemas:blah:">xml a</node>

如何在事先不知道输入文件调用该前缀“a”的情况下将输入前缀“a”映射到“blah”? (所以&lt;xsl:namespace-alias/&gt; 对我不起作用。)

作为进一步的上下文,如果它指向一个更好的解决方案,这是用于查看外部生成的 XML 文档。外部进程使用自动生成的前缀“a:”、“b:”、“c:”等创建输入文档。我希望能够使用“友好”命名空间前缀显示这些前缀。

更新the definition of Statically known namespaces

解释了 in-scope-prefixes() 行为

【问题讨论】:

  • 好问题 (+1)。有关完整的 XSLT 1.0 和 XSLT 2.0 解决方案,请参阅我的答案。

标签: xml xslt namespaces prefix


【解决方案1】:

这种转换在 XSLT 1.0 和 XSLT 2.0 中都(只需更改 version 属性)):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my"
 >
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <my:namespaces>
    <ns prefix="blah" uri="urn:schemas:blah:"/>
    <ns prefix="foo" uri="uff:anotherNamespace"/>
  </my:namespaces>

  <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
 "*[namespace-uri()=document('')/*/my:namespaces/*/@uri]">
  <xsl:variable name="vNS" select=
  "document('')/*/my:namespaces/*
                   [@uri=namespace-uri(current())]"/>
  <xsl:element name="{$vNS/@prefix}:{local-name()}"
       namespace="{namespace-uri()}">
   <xsl:copy-of select=
    "namespace::*[not(. = namespace-uri(current()))]"/>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

复制任何 XML 文档,并且仅将该文档用于选择命名空间的前缀替换为我们指定的前缀。

应用于此 XML 文档时

<t>
    <a:node xmlns:a="urn:schemas:blah:"/>
    <b:node xmlns:b="urn:schemas:blah:"/>
    <c:node xmlns:c="uff:anotherNamespace"/>
</t>

产生想要的结果

<t>
   <blah:node xmlns:blah="urn:schemas:blah:"/>
   <blah:node xmlns:blah="urn:schemas:blah:"/>
   <foo:node xmlns:foo="uff:anotherNamespace"/>
</t>

【讨论】:

  • 非常好。易于添加命名空间+前缀对,并且未更改的前缀可以很好地按原样传递。
【解决方案2】:

身份转换加上这个模板怎么样:

<xsl:template match="blah:*">
  <xsl:element name="blah:{local-name()}">
    <xsl:apply-templates select="*|@*" />
  </xsl:element>
</xsl:template>

我不确定这是否是 XSLT 2.0 中最优雅的方式,但它确实有效。

【讨论】:

  • 这看起来最终会为我工作(使用它作为第一遍清理前缀名称,然后使用我的旧 XSLT 作为第二遍)。有没有一种很好的方法来获取在根元素上声明的命名空间?事实上,如果我有 ,命名空间节点将附加到 而不是 .
【解决方案3】:

查看&lt;xsl:namespace-alias ...&gt; 顶级元素的规范。我相信它会完成你想要的。

【讨论】:

  • 我特别提到的规范不起作用。 :-) 我又看了一遍。它似乎对前缀名称进行操作,而不是命名空间 URI。所以,'urn:schemas:blah:' 在外部进程的一次运行中是 'a:' 而在另一次运行中是 'b:' 阻止它在这里工作,对吗?
猜你喜欢
  • 1970-01-01
  • 2022-08-10
  • 2021-09-11
  • 2012-03-29
  • 2021-04-12
  • 2023-04-03
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多