如何动态设置XSLT转换输出XML的默认命名空间声明?

时间:2010-03-12 13:00:00

标签: xslt

我可以这样做,但不是默认命名空间,使用<xsl:namespace>.如果我尝试为默认命名空间执行此操作:

<xsl:namespace name="" select"myUri"/>

它永远不会奏效。它要求我明确定义元素的名称空间,以便能够使用上面的空前缀声明 我想要这个的原因是因为我有一个任务是将输入XML文件转换为另一个输出xml。输出XML有很多元素,我不想为每个元素显式设置名称空间。这就是为什么我想设置默认值而不再打扰。但必须根据源XML中的某些数据计算默认值。它在整个转换期间不会改变,但它依赖于输入XML数据。 有解决方案吗

编辑1: 支持:

  1. 我想动态创建命名空间并将其设置为输出xml文档的默认命名空间。命名空间的uri是从输入XML中的一些数据派生的。
  2. 如果我在根输出元素中使用<xsl:namespace>,我就无法为它创建默认命名空间,只能为前缀命名空间。即使使用前缀,也不会传播给孩子。
  3. 编辑2:  dkackman建议:

    <xsl:template match="root">
      <xsl:param name ="ns">my-computed-namespace</xsl:param>
      <xsl:element name="newRoot" namespace="{$ns}"/>
    </xsl:template>
    

    它几乎解决了这个问题。不幸的是,孩子们被变压器注入“”(空白)命名空间。如果我放置一个子元素,这就是我得到的:

    <newRoot xmlns="my-computed-namespace"> 
        <child xmlns=""> ... 
        </child> 
     </newRoot>
    

    为什么变压器会将这个xmlns=""放在孩子身上?如果我可以阻止这一点,那么我找到了解决办法。

3 个答案:

答案 0 :(得分:7)

除了提供准确答案的@Tomalak之外,请注意<xsl:namespace>并非旨在创建一个名称空间声明,供XSLT处理器使用所有元素或属性。

<xsl:namespace>的目的是创建一个特定的命名空间节点。此节点仅具有有限的范围:当前元素或属性,以及当前节点的所有子节点,如果它们不将前缀重新分配给另一个名称空间-uri。

只有当我们想要为必须动态生成的namespace-uri动态创建名称空间时才需要使用<xsl:namespace>(在转换开始时不是静态地知道)。这种情况非常罕见。

在所有情况下,如果静态地知道所需的namspace-uri,只需将此命名空间声明为适当的可见性级别(通常在<xsl:stylesheet>指令处)然后只需使用关联的前缀,必须使用此命名空间的任何地方。

<强>更新 我刚刚在另一个论坛的专家对话中证实,<xsl:namespace>无法做到这一点。它为当前元素添加了一个没有名称的命名空间节点,但是文字结果元素以1:1的形式复制并保留在它们的(无)命名空间中。

以下是XSLT W3C WG编辑Michael Kay博士如何解释:

您需要使用正确的展开名称创建元素和属性 你创造它们的时间。如果这意味着使用xsl:element,那就这样吧。 xsl:namespace只能用于为这些创建其他命名空间节点 为元素和中使用的前缀/ uris自动创建的 属性名称;它不能用于修改元素的名称或 属性节点。 与往常一样,要了解这一点,您需要了解数据模型 命名空间。元素/属性名称是三元组,包含(prefix, uri, localname)。命名空间节点是一对(prefix, uri)。有一致性 规则如果存在包含prefix=P uri=U的元素或属性名称 那么必须有一个命名空间节点(P, U)。名称空间修复过程 确保在创建时自动创建此命名空间节点 元素或属性。 xsl:namespace允许您创建 其他命名空间节点,通常用于QName值中使用的命名空间 含量”。

如果需要这样的结果,解决方案是使用第二遍并将属于“no namespace”的任何元素转换为所需的新命名空间。

这是第二次传递中使用的转换(两次传递可以组合成一个样式表/转换):

<xsl:stylesheet  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:variable name="vUrl" select="'my:Url'"/>

 <xsl:template match="*[namespace-uri()='']">
   <xsl:element name="{name()}" namespace="{$vUrl}">
     <xsl:copy-of select="@*"/>
     <xsl:apply-templates/>
   </xsl:element>

 </xsl:template>
</xsl:stylesheet>

对以下示例(pass-1-result)xml文档应用上述转换时

<a>
  <b>
    <c/>
  </b>
</a>

产生了所需的结果

<a xmlns="my:Url">
    <b>
        <c/>
    </b>
</a>

答案 1 :(得分:1)

简单:

<xsl:stylesheet
 version="1.0"
 xmlns:xsl="..."
 xmlns="default output namespace for unprefixed elements"
>
  <!-- ... -->
</xsl:stylesheet>

答案 2 :(得分:0)

试试这个:

<xsl:template match="root">
  <xsl:param name ="ns">my-computed-namespace</xsl:param>
  <xsl:element name="newRoot" namespace="{$ns}"/>
</xsl:template>

然后你可以这样称呼:

    <xsl:apply-templates select="root">
      <xsl:with-param name="ns" select="computationXPath"/>
    </xsl:apply-templates>

修改 或者使用variable代替param

  <xsl:variable name ="ns">my-computed-namespace</xsl:variable>
  <xsl:template match="root">
    <xsl:element name="newRoot" namespace="{$ns}">
       <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

(无需调用模板with-param