【问题标题】:How to preserve XML namespace in XSLT output?如何在 XSLT 输出中保留 XML 命名空间?
【发布时间】:2010-06-30 09:13:34
【问题描述】:

XSL 样式表应向 Internet Explorer 输出以下代码:

<xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>

但是当我使用任何 XML 执行以下模板时

<xsl:template match="*|node()">
    <xml:namespace prefix="vml"
                   ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>

IE 抛出解析错误:样式表不包含文档元素。 同时 Firefox 在输出中删除 xml 命名空间...

那么,如何在输出中保留 xml 命名空间?

重要

一个。我使用的输出方法是 html

b.以下代码不能解决我的问题:

<xsl:template match="*|node()">
    <namespace prefix="vml"
               xmlns="http://www.w3.org/XML/1998/namespace"
               ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>

【问题讨论】:

  • 我是否正确理解您要为每个元素添加命名空间节点?
  • @Sawa:我必须说我同意 Dimitre 反对使用 xml:namespace 和 MS 允许的其他非标准元素。此外,这可以通过正确的命名空间声明 xmlns:vml="urn:schemas-microsoft-com:vml" 来完成

标签: xml xslt namespaces


【解决方案1】:

您不能使用保留的xml 前缀。使用这样的东西:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dummy="dummy">
<xsl:namespace-alias stylesheet-prefix="dummy" result-prefix="xml"/>
<xsl:template match="/">
    <dummy:namespace prefix="vml"
                   ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>
</xsl:stylesheet>

任何输入,你都会得到这个结果:

<xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml" />

【讨论】:

    【解决方案2】:

    如果你真的想要问题中显示的结果,这很容易实现

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes"/>
    
     <xsl:template match="/">
      <xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>
     </xsl:template>
    </xsl:stylesheet>
    

    当应用于任何 XML 文档(未使用)时,此转换会产生所需的结果

    <xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>
    

    但是,在我看来,您想为给定 XML 文档的每个元素添加一个命名空间节点(如果不是这样,请通过评论告诉我,我将删除此答案)。

    如果是这样,这里有一个简单有效的方法:

    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:vml="urn:schemas-microsoft-com:vml"
         exclude-result-prefixes="vml">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vNamespace" select=
         "document('')/*/namespace::*[name()='vml']"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/*">
         <xsl:copy>
           <xsl:copy-of select="$vNamespace"/>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于任何文档时,例如这个

    <t>
        <a x="3">
            <b y="4"/>
        </a>
    </t>
    

    产生想要的结果

    <t xmlns:vml="urn:schemas-microsoft-com:vml">
       <a x="3">
          <b y="4"/>
       </a>
    </t>
    

    乍一看可能令人困惑,因为只有结果的顶部元素明显具有所需的命名空间节点。但是,根据定义(查看 XML Namespace spec),如果(子)树根部的元素具有给定的命名空间节点,则其所有后代元素也具有该命名空间节点。即使您将命名空间复制到每个元素,XSLT 序列化程序也会将其从除顶部元素之外的所有元素的序列化(文本)表示中剥离。

    在 XSLT 2.0 中,您可以简单地使用 &lt;xsl:namespace&gt; 指令

    <xsl:namespace name="vml" select="urn:schemas-microsoft-com:vml"/>
    

    【讨论】:

    • 我认为您的答案并未涵盖所有情况。如果样式表必须在客户端用 IE 解析,你会得到这样的结果:El prefijo del espacio de nombres no puede comenzar con la cadena reservada "xml"
    • @Alejandro:我不知道 MSXML3(IE 使用)的这种行为。嗯...这可能被视为一个功能和一个错误。事实上,我使用的所有其他 XSLT 处理器都允许这样做。事实上,MSXML4 允许这样做,这意味着他们纠正了 MSXML4 中的 MSXML3 错误。没关系,尝试在 xml: 命名空间中使用非标准元素是一种严重的滥用行为,我不鼓励作者这样做。
    • 我同意你反对使用 xml:namespace 和 MS 允许的其他非标准元素。此外,这可以通过正确的命名空间声明 xmlns:vml="urn:schemas-microsoft-com:vml" 来完成
    猜你喜欢
    • 2012-03-29
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2019-03-13
    • 2013-04-11
    相关资源
    最近更新 更多