避免在应用XSLT时在xml响应中添加xmlns属性

时间:2013-06-05 21:08:49

标签: xslt xml-namespaces

我有一个XML文档,我需要更改根节点。凭借我可以从网上获取的一点点知识,我能够看到我想要的东西,除了我的XML的子节点中有新的xmlns属性。我正在应用转换的XML看起来像:

<gmd:MD_Metadata xmlns="http://www.isotc211.org/2005/gmd" 
  xmlns:gco="http://www.isotc211.org/2005/gco" 
  xmlns:gmd="http://www.isotc211.org/2005/gmd" 
  xmlns:gmi="http://www.isotc211.org/2005/gmi" 
  xmlns:gml="http://www.opengis.net/gml" 
  xmlns:gmx="http://www.isotc211.org/2005/gmx" 
  xmlns:gsr="http://www.isotc211.org/2005/gsr" 
  xmlns:gss="http://www.isotc211.org/2005/gss" 
  xmlns:gts="http://www.isotc211.org/2005/gts" 
  xmlns:srv="http://www.isotc211.org/2005/srv" 
  xmlns:xlink="http://www.w3.org/1999/xlink" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://www.isotc211.org/2005/gmd 
  http://www.ngdc.noaa.gov/metadata/published/xsd/schema/gmd/gmd.xsd">
  <gmd:language>
    <gmd:LanguageCode 
      codeList="http://www.loc.gov/standards/iso639-2/php/code_list.php" 
      codeListValue="eng" codeSpace="ISO639-2"
      >eng</gmd:LanguageCode>
    </gmd:language>
    ......
</gmd:MD_Metadata>

我的XSLT看起来像这样:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:gmd="http://www.isotc211.org/2005/gmd"
  xmlns:gco="http://www.isotc211.org/2005/gco"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:gml="http://www.opengis.net/gml" 
  xmlns:gmi="http://www.isotc211.org/2005/gmi">

  <xsl:output omit-xml-declaration="yes"  indent="yes"/> 

  <xsl:template match="/">
    <gmi:MI_Metadata 
      xmlns="http://www.isotc211.org/2005/gmi" 
      xmlns:gco="http://www.isotc211.org/2005/gco" 
      xmlns:gmd="http://www.isotc211.org/2005/gmd"  
      xmlns:gmi="http://www.isotc211.org/2005/gmi"  
      xmlns:gml="http://www.opengis.net/gml"  
      xmlns:gmx="http://www.isotc211.org/2005/gmx"  
      xmlns:gsr="http://www.isotc211.org/2005/gsr"  
      xmlns:gss="http://www.isotc211.org/2005/gss"  
      xmlns:gts="http://www.isotc211.org/2005/gts"  
      xmlns:xlink="http://www.w3.org/1999/xlink"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xmlns:srv="http://www.isotc211.org/2005/srv"  
      xsi:schemaLocation="http://www.isotc211.org/2005/gmi  
      http://www.ngdc.noaa.gov/metadata/published/xsd/schema.xsd" >
      <xsl:for-each select="/*/node()|@*">
        <xsl:copy-of select="." />
      </xsl:for-each>
    </gmi:MI_Metadata>
  </xsl:template>
</xsl:stylesheet>

输出如下:

<gmi:MI_Metadata xmlns="http://www.isotc211.org/2005/gmi"  
      xmlns:gco="http://www.isotc211.org/2005/gco"  
      xmlns:gmd="http://www.isotc211.org/2005/gmd"  
      xmlns:gmi="http://www.isotc211.org/2005/gmi"  
      xmlns:gml="http://www.opengis.net/gml"  
      xmlns:gmx="http://www.isotc211.org/2005/gmx"  
      xmlns:gsr="http://www.isotc211.org/2005/gsr"  
      xmlns:gss="http://www.isotc211.org/2005/gss"  
      xmlns:gts="http://www.isotc211.org/2005/gts"  
      xmlns:srv="http://www.isotc211.org/2005/srv"  
      xmlns:v1="http://www.isotc211.org/2005/gmd"  
      xmlns:xlink="http://www.w3.org/1999/xlink"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://www.isotc211.org/2005/gmi  
      http://www.ngdc.noaa.gov/metadata/published/xsd/schema.xsd">
  <gmd:language xmlns="http://www.isotc211.org/2005/gmd">
    <gmd:LanguageCode  
      codeList="http://www.loc.gov/standards/iso639-2/php/code_list.php"  
      codeListValue="eng" codeSpace="ISO639-2" 
      >eng</gmd:LanguageCode>
    </gmd:language>
    .......
</gmi:MI_Metadata>

我想避免在子节点的输出中使用 xmlns =“http://www.isotc211.org/2005/gmd”,有什么办法可以实现吗?当我将xslt的部分更改为:

时,我注意到了
<xsl:template match="/">
<gmi:MI_Metadata xmlns="http://www.isotc211.org/2005/gmd" ....

xmlns消失但是头/节点不是客户端在输出中想要的!所以我不确定我能做什么。非常感谢您的见解,谢谢。

2 个答案:

答案 0 :(得分:1)

无论exclude-result-prefixes如何,xsl:copy-of都会根据spec复制名称空间:

  

xsl:copy-of元素可用于将结果树片段插入到结果树中... [w]如果结果是节点集,则集合中的所有节点按文档顺序复制到结果树;复制元素节点会复制属性节点,命名空间节点以及元素节点的子节点以及元素节点本身......

因此,您需要自己进行(更多)复制。例如,这是解决方案的一部分,即复制元素的规则:

<xsl:template match="*" mode="copy" priority="1">
    <xsl:element name="{name()}">
        <xsl:apply-templates select="node()|@*" mode="copy"/>
    </xsl:element>
</xsl:template>

然后正常复制内容

<xsl:template match="node()|@*" mode="copy">
    <xsl:copy />      
</xsl:template>

然后,在您的代码中,您可以执行

<xsl:for-each select="/*/node()|@*">
    <xsl:apply-templates mode="copy" select="." />
</xsl:for-each>

答案 1 :(得分:0)

您可能想要阅读exclude-result-prefixes属性。

当然,它们具有gmd命名空间的默认命名空间声明,因为它们是从输入中复制的,这使得该命名空间成为默认命名空间(以及将其绑定到前缀gmd)。我尝试将xsl:copy-of更改为更像传统的身份转换,以便您可以尝试覆盖子元素中的默认命名空间声明。

<xsl:copy>
  <xsl:for-each
    select="$ns-carrier/namespace::*[local-name() = 'xmlns']">
    <xsl:copy/>
  <xsl:for-each>
  <xsl:for-each select="@*|node()">
    <xsl:copy-of select="."/>
  </xsl:for-each>
</xsl:copy>

(未经测试,所以请加上一粒盐。)

可能有助于提醒自己(和客户端!),除非你正在做一些与命名空间绑定不同寻常的事情,然后对于任何相当不错的XML工具链,这是一个纯粹的装饰性问题而不是实质性的问题。 。 (也就是说,准备好告诉自己和你的客户,如果你不能设法让样式表做你想做的事情,那真的应该没关系。通过尝试让命名空间管理自动发生,XSLT的设计者有这很难手动完成。)