使用 XSLT 转换在 XML 中创建 xmlns 属性

Posted

技术标签:

【中文标题】使用 XSLT 转换在 XML 中创建 xmlns 属性【英文标题】:Create xmlns attribute in the XML using XSLT Transformation 【发布时间】:2012-08-24 03:23:44 【问题描述】:

我正在尝试使用 JDK Transformer(Oracle XML v2 Parser 或 JAXP)在 XSLT 转换期间通过参数传递的值将 xmlns 属性添加到生成的 XML,但它始终默认为 http://www.w3.org/2000/xmlns/

我的源 XML

<test/>

我的 XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://example.com">
    <xsl:param name="myNameSpace" select="'http://neilghosh.com'"/>
    <xsl:template match="/">
        <process>
            <xsl:attribute name="xmlns:neil">
                <xsl:value-of select="$myNameSpace"/>
            </xsl:attribute>
        </process>
    </xsl:template>
</xsl:stylesheet>

我的结果

<?xml version="1.0"?>
<process xmlns="http://www.w3.org/2000/xmlns/" xmlns:neil="neilghosh.com">
</process>

我想要的结果

<?xml version="1.0"?>
<process xmlns="http://example.com"  xmlns:neil="neilghosh.com">
</process>

【问题讨论】:

您应该为命名空间使用有效的 URI,例如http://example.com/,不是http://example.com。如果您将浏览器输入到位置栏中,浏览器会将后者更正为前者,但这是在纠正输入时的明显错误。不能有没有路径部分的 HTTP URI。 【参考方案1】:

首先,在 XSLT 数据模型中,您不想创建属性节点,而是要创建命名空间节点。

命名空间节点通常是自动创建的:如果您在特定命名空间中创建元素或属性,处理器会自动添加必要的命名空间节点(因此,在序列化时,命名空间声明)会自动添加。

如果您想创建一个不必要的名称空间节点(因为它没有用于任何元素或属性的名称中),那么在 XSLT 2.0 中您可以使用 xsl:namespace。如果您坚持使用 XSLT 1.0,那么有一个解决方法,即在相关命名空间中创建一个元素,然后复制其命名空间节点:

<xsl:variable name="ns">
  <xsl:element name="neil:dummy" namespace="$param"/>
</xsl:variable>
<process>
  <xsl:copy-of select="$ns/*/namespace::neil"/>
</process>

【讨论】:

$ns 变量持有RTF 而不是节点集时,这是否有效?我本来预计需要一个 exslt:node-set() 电话或类似电话来首先转换它。 感谢模板下的以下代码不起作用 xsl:variable> 您能否将您的解决方案编辑为我需要为这个问题编写的确切 XSLT? @NeilGhosh,也许您听说过xxx:node-set() 扩展功能? 是的,我认为它需要 xx:node-set()。抱歉,我只为人们指明正确的方向,我不会牵着他们的手走到那里——尤其是涉及 XSLT 1.0 时,因为那总是一段不愉快的旅程。【参考方案2】:

Michael Kay 为您提供了正确答案,但根据您的 cmets,您不确定如何在转换中使用它。

这是一个完整的转换

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pNamespace" select="'neilghosh.com'"/>

 <xsl:variable name="vDummy">
   <xsl:element name="neil:x" namespace="$pNamespace"/>
 </xsl:variable>

 <xsl:template match="/*">
  <xsl:element name="process" namespace="http://example.com">
    <xsl:copy-of select="namespace::*"/>
    <xsl:copy-of select="ext:node-set($vDummy)/*/namespace::*[.=$pNamespace]"/>
  </xsl:element>
 </xsl:template>
 </xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<test/>

产生了想要的正确结果:

<process xmlns="http://example.com" xmlns:neil="neilghosh.com" />

【讨论】:

感谢您的回答。我收到以下错误 a.xsl: XML-23049: (Error) FOTY0021: invalid node type 这是因为我的 JDeveloper 的 oracle.xml.parser.v2.XSLProcessor 吗?有更好的 v2 解析器方法吗? 删除了 Oracle v2 解析器库并运行了上述代码,但输出为 example.com" xmlns:neil="neilghosh.com"/> @NeilGhosh,我已经使用我正在使用的所有 9 个 XSLT 处理器运行了它——所有这些都会产生我复制并粘贴到这个答案中的输出。你可以使用 MSXML、.NET XslCompiledTransform、Saxon、XQSharp 或 AltovaXML (XML-SPY) 吗? 我不确定是否可以在我的代码中使用上述解析。我在 NetBeans 中运行了相同的代码,它也不必要地给出了 ns0 前缀【参考方案3】:

XML 中的命名空间声明不是属性,即使它们看起来像属性。在 XSLT 2.0 中,您可以使用 &lt;xsl:namespace name="neil" select="$myNameSpace" /&gt; 将命名空间声明动态添加到结果树,但该功能在 XSLT 1.0 中不可用。

【讨论】:

我添加了 在模板下,但它仍然给我输出 neilghosh.com">【参考方案4】:

不要尝试自己创建“xmlns”属性。在 XSLT 中创建名称空间,它们将自动完成。 这个 XSLT 工作(用 Saxon 9.4 测试):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:neil="neilghosh.com"    
xpath-default-namespace="http://example.com"
xmlns="http://example.com" version="2.0">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="myDynamicNamespace" select="'http://neilghosh.com'"/>

<xsl:template match="/">
    <xsl:element name="process">   
        <xsl:namespace name="neil" select="$myDynamicNamespace"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

并给出以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://example.com" xmlns:neil="http://neilghosh.com"/>

【讨论】:

问题的关键在于 xmlns 的值应该来自参数 [sent by transformer.setParameter("myNameSpace", "example.com") ] "myNameSpace" ok - 所以元素“process”应该在来自参数的命名空间中。我将尝试在 内部创建一个元素,该元素具有来自参数的命名空间... 跨度> 我需要将它放在进程的根标签中 xsl:namespace 甚至无法正常工作 【参考方案5】:

终于找到了一个适用于我的 XSLT 处理器(Oracle XML V2 解析器)的解决方法

我必须 transform it to a DOM Document 然后将该 DOM 持久化到文件系统,而不是直接输出到 StreamResult

我在transform method 中使用了DOMResult

以下 XSLT 片段有效,但有一个额外的 xmlns:xmlns="http://www.w3.org/2000/xmlns/" 可能已被 Document 吸收,当我没有出现在最终输出中时持久化到文件系统。

 <process>    
      <xsl:attribute name="xmlns">
        <xsl:value-of select="'http://example.com'"/>
      </xsl:attribute> 
 <process>

我知道这不是最好的方法,但考虑到解析约束,这是我现在唯一的选择。

【讨论】:

以上是关于使用 XSLT 转换在 XML 中创建 xmlns 属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 xslt 获取位于另一个路径中的另一个 xml 值

xslt 中的 XML 命名空间处理

无法使用 Ant 在 Javascript 或 Jython 中创建 XSLT 扩展

使用 xslt 转换多个 xml 模式文档

使用 XSLT 将 XML 转换为 XML 删除前导空格和零

XSLT 中的自定义根节点