如何使用XSLT从XML中删除命名空间

时间:2011-03-11 02:03:20

标签: xml xslt xml-namespaces

我有150 MB(有时甚至可以更多)XML文件。我需要删除所有名称空间。 它在Visual Basic 6.0上,所以我使用DOM来加载XML。加载是可以的,我一开始就持怀疑态度,但不知何故,那部分工作正常。

我正在尝试以下XSLT,但它也会删除所有其他属性。我想保留所有属性和元素,我只需要删除命名空间。显然这是因为我有xsl:element但没有属性。我如何在那里包含属性?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="UTF-8" />
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

3 个答案:

答案 0 :(得分:30)

您的XSLT也会删除属性,因为您没有可以复制它们的模板。 <xsl:template match="*">仅匹配元素,而不匹配属性(或文本,注释或处理说明)。

下面是一个样式表,它从已处理的文档中删除所有名称空间定义,但复制所有其他节点和值:元素,属性,注释,文本和处理指令。请注意2件事

  1. 复制属性不足以删除所有名称空间。即使包含元素不属于命名空间,属性也可以属于命名空间。因此,还需要创建属性,如元素。使用<xsl:attribute>元素创建属性。
  2. 有效的XML文档不能包含具有两个或多个具有相同扩展名称的属性的元素,但如果属性具有不同的名称空间,则元素可以包含具有相同本地名称的多个属性。这意味着删除如果存在具有两个具有相同本地名称的属性的元素,则属性名称中的名称空间前缀将导致数据集。其他一个属性将被删除(或覆盖)。
  3. ...和代码:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>
    
        <!-- Stylesheet to remove all namespaces from a document -->
        <!-- NOTE: this will lead to attribute name clash, if an element contains
            two attributes with same local name but different namespace prefix -->
        <!-- Nodes that cannot have a namespace are copied as such -->
    
        <!-- template to copy elements -->
        <xsl:template match="*">
            <xsl:element name="{local-name()}">
                <xsl:apply-templates select="@* | node()"/>
            </xsl:element>
        </xsl:template>
    
        <!-- template to copy attributes -->
        <xsl:template match="@*">
            <xsl:attribute name="{local-name()}">
                <xsl:value-of select="."/>
            </xsl:attribute>
        </xsl:template>
    
        <!-- template to copy the rest of the nodes -->
        <xsl:template match="comment() | text() | processing-instruction()">
            <xsl:copy/>
        </xsl:template>
    
    </xsl:stylesheet>
    

    您也可以使用<xsl:template match="node()">代替最后一个模板,但之后应使用priority属性来阻止元素与此模板匹配。

答案 1 :(得分:1)

  

如何在那里添加属性?

只需将此模板附加到您已有的模板:

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>

答案 2 :(得分:-1)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="/">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
        <xsl:value-of select="current()"/>
    </xsl:attribute>
</xsl:template>
<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="@* | * | text()"/>
    </xsl:element>
</xsl:template>
<xsl:template match="text()">
    <xsl:copy>
        <xsl:value-of select="current()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>