将xmlns属性合并到根元素?

时间:2010-10-30 04:37:14

标签: xml xslt xml-namespaces

我正在将一组XML文档从一种格式(不包括名称空间前缀)转换为另一种格式。 一切都相对简单,但在XMLNS输出中有点重复。以下是一个例子。

(非常简单)输入XML

<?xml version="1.0"?>
<a/>

XSLT

<!-- xmlns="http://www.w3.org/1999/xhtml" -->

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"

    xmlns:a="urn:data.test-a"
    xmlns:b="urn:data.test-b"
    xmlns:c="urn:data.test-c"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:local.test schema/test.xsd"

    version="1.0">

    <xsl:output method="xml" indent="yes" />

    <xsl:template match="/a">
        <xsl:element name="a:test-a">
            <!-- attempted fix -->
            <xsl:copy-of select="namespace::*"/>

            <!-- is there a better way to get this in there? -->
            <xsl:attribute name="xsi:schemaLocation">urn:local.test schema/test.xsd</xsl:attribute>

            <xsl:element name="b:test-b">
                <xsl:element name="c:test-c">content</xsl:element>
            </xsl:element>

        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0"?>
<a:test-a
    xmlns:a="urn:data.test-a"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:local.test schema/test.xsd">
  <b:test-b xmlns:b="urn:data.test-b">
    <c:test-c xmlns:c="urn:data.test-c">content</c:test-c>
    <c:test-c xmlns:c="urn:data.test-c">content</c:test-c>
  </b:test-b>
  <b:test-b xmlns:b="urn:data.test-b">
    <c:test-c xmlns:c="urn:data.test-c">content</c:test-c>
    <c:test-c xmlns:c="urn:data.test-c">content</c:test-c>
  </b:test-b>
</a:test-a>

期望输出

<?xml version="1.0"?>
<a:test-a
    xmlns:a="urn:data.test-a"
    xmlns:b="urn:data.test-b"
    xmlns:c="urn:data.test-c"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:local.test schema/test.xsd">
  <b:test-b>
    <c:test-c>content</c:test-c>
    <c:test-c>content</c:test-c>
  </b:test-b>
  <b:test-b>
    <c:test-c>content</c:test-c>
    <c:test-c>content</c:test-c>
  </b:test-b>
</a:test-a>

基本上,我想将命名空间属性合并到根元素中。 我一直在做一些研究,我认为我已经锁定了here。但是,它没有达到预期的效果;我假设我正在使用它不正确或受到xsltproc功能的限制。

执行第二遍以清理XMLNS条目也是一个很好的解决方案。

另外,如果它限制了解决方案,我认为我的环境将仅限于XSLT 1.0。

感谢您的任何提示。

PS。一个较小的问题是,是否有更好的方法在输出中获取schemaLocation属性,但这是次要的。

1 个答案:

答案 0 :(得分:2)

这可能是满足您要求的最短转换

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

    xmlns:a="urn:data.test-a"
    xmlns:b="urn:data.test-b"
    xmlns:c="urn:data.test-c"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:local.test schema/test.xsd">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="a">
        <a:test-a xmlns:a="urn:data.test-a"
           xmlns:b="urn:data.test-b"
           xmlns:c="urn:data.test-c"
           xsi:schemaLocation="urn:local.test schema/test.xsd">
            <b:test-b>
                <c:test-c>content</c:test-c>
            </b:test-b>
        </a:test-a>
    </xsl:template>
</xsl:stylesheet>

对提供的XML文档执行此转换

<a/>

产生了想要的正确结果

<a:test-a xmlns:a="urn:data.test-a"
   xmlns:b="urn:data.test-b"
   xmlns:c="urn:data.test-c"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="urn:local.test schema/test.xsd">
   <b:test-b>
      <c:test-c>content</c:test-c>
   </b:test-b>
</a:test-a>

但是,请注意:将所有命名空间节点放在顶部元素上,即使它们不需要它们也不是建议的做法,因为所有命名空间节点都被复制到所有后代元素,这导致浪费大量记忆。