动态名称空间

时间:2013-12-19 16:09:13

标签: xml xslt xml-namespaces

我是XML转换(XSLT)的新手。 我试图弄清楚我面临的命名空间问题,需要一些帮助。

以下详细信息:

XSLT文件:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <Address xmlns="http://gov.co.uk">
            <xsl:variable name="NameSpace">http://gov.co.uk/Test/1</xsl:variable>
            <xsl:element name="Name" namespace="{$NameSpace}">
              <ForeName>Rex</ForeName>
              <MiddleName>XYZ</MiddleName>
            </xsl:element>
            <xsl:element name="street" namespace="{$NameSpace}">
              <DoorNo>123</DoorNo>
            </xsl:element>
        </Address>
    </xsl:template>
</xsl:stylesheet>

OutPut XML:

<?xml version="1.0" encoding="utf-8"?>
<Address xmlns="http://gov.co.uk">
    <Name xmlns="http://gov.co.uk/Test/1">
        <ForeName xmlns="http://gov.co.uk">Rex</ForeName>
        <MiddleName xmlns="http://gov.co.uk">XYZ</MiddleName>
    </Name>
    <street xmlns="http://gov.co.uk/Test/1">
        <DoorNo xmlns="http://gov.co.uk">123</DoorNo>
    </street>
</Address>

正如您所看到的,ForeName的命名空间是xmlns =“http://gov.co.uk”,它是从根节点Address派生的,但我需要它派生自最近的父节点Name,即xmlns =“http://gov.co.uk/test/1”。

我有以下这样的事情

<xsl:element name="ForeName" namespace="{$NameSpace}">REX</xsl:element>

但我不相信这一点,因为我的XSLT文件中有数百个元素,我需要修改上面的每个元素。

我们有什么方法可以强制子元素命名空间从其父节点派生?

3 个答案:

答案 0 :(得分:0)

这不是关于XSLT,而是关于命名空间的更多信息。声明命名空间时,对该节点和所有后续节点都是活动的。

因此,如果您希望ForeNameMiddlename的默认命名空间与父Name的默认命名空间匹配,则只需要在子元素上声明它,如下所示: / p>

<?xml version="1.0" encoding="utf-8"?>
<Address xmlns="http://gov.co.uk">
    <Name xmlns="http://gov.co.uk/Test/1">
        <ForeName>Rex</ForeName>
        <MiddleName>XYZ</MiddleName>
    </Name>
    <street xmlns="http://gov.co.uk/Test/1">
        <DoorNo>123</DoorNo>
    </street>
</Address>

答案 1 :(得分:0)

  

我们有什么方法可以强制子元素命名空间从其父节点派生?

不直接,最简单的方法可能是分两个阶段进行转换。首先进行当前转换,将结果存储在变量中,然后重新处理该变量的内容,以将任何无命名空间元素“移动”到您作为参数的特定命名空间中:

<xsl:param name="NameSpace" select="'http://gov.co.uk/Test/1'" />

<xsl:template match="/">
  <xsl:variable name="stageOne">
    <!-- your current processing here -->
  </xsl:variable>
  <xsl:apply-templates mode="fix-ns" select="msxsl:node-set($stageOne)" />
</xsl:template>

<!-- copy everything as-is ... -->
<xsl:template match="@*|node()" mode="fix-ns">
  <xsl:copy><xsl:apply-templates select="@*|node()" mode="fix-ns" /></xsl:copy>
</xsl:template>

<!-- ... except element in no namespace, which we move into $NameSpace -->
<xsl:template match="*[namespace-uri() = '']" mode="fix-ns">
  <xsl:element name="{local-name()}" namespace="{$NameSpace}">
    <xsl:apply-templates select="@*|node()" mode="fix-ns" />
  </xsl:element>
</xsl:template>

如果您确实希望无命名空间节点继承其父级命名空间而不是为它们使用固定命名空间,那么您可以将最终模板更改为更像

<xsl:template match="*[namespace-uri() = '']" mode="fix-ns">
  <xsl:element name="{local-name()}" namespace="{namespace-uri(..)}">
    <xsl:apply-templates select="@*|node()" mode="fix-ns" />
  </xsl:element>
</xsl:template>

第三个选项 - 你提到你已经知道你可以在任何地方使用<xsl:element>来做你需要的但你

  

我的XSLT文件中有数百个元素,我需要修改上面的每个元素。

请记住,XSLT样式表本身就是一个XML文档,因此您可以使用如下所示的简单一次性样式表对现有样式表进行必要的编辑。请注意使用xsl:namespace-alias输出XSLT标记:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns:out-xsl="urn:result" exclude-result-prefixes="out-xsl">

  <xsl:namespace-alias stylesheet-prefix="out-xsl" result-prefix="xsl" />

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

  <!-- match any literal result element <foo> which is not in a namespace -->
  <xsl:template match="xsl:template//*[namespace-uri() = '']">
    <!-- replace it with <xsl:element name="foo" namespace="{$NameSpace}"> -->
    <out-xsl:element name="{local-name()}" namespace="{{$NameSpace}}">
      <xsl:apply-templates select="@*|node()" />
    </out-xsl:element>
  </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:0)

<Address><ForeName><MiddleName>具有相同名称空间的原因是您将它们添加为文字结果元素。 文字元素获取样式表范围内的命名空间定义的副本。在您的示例中,这是在行<Address xmlns="http://gov.co.uk">上完成的。 另一方面,使用xslt命令生成的元素(如<xsl:element><xsl:copy>不会复制样式表中定义的名称空间。

如果您需要将除<Address>之外的所有文字元素放入命名空间http://gov.co.uk/Test/1,只需在xmlns="http://gov.co.uk/Test/1"元素中添加默认命名空间定义<xsl:stylesheet>并创建{{ 1}}元素<Address>

如果文字元素有多个不同的命名空间,则将该命名空间定义添加到文字元素的最近父元素中。例如,使用<xsl:element name="Address" namespace="http://gov.co.uk"><xsl:element name="Address" namespace="http://gov.co.uk" xmlns="http://gov.co.uk/Test/1">的所有文字后代置于<Address>命名空间。