如何使用 XSLT 从 XML 中删除名称空间
Posted
技术标签:
【中文标题】如何使用 XSLT 从 XML 中删除名称空间【英文标题】:How to remove namespaces from XML using XSLT 【发布时间】:2011-07-13 04:42:16 【问题描述】:我有一个 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>
【问题讨论】:
How to remove all namespaces from XML with C#?的可能重复 【参考方案1】:您的 XSLT 也会删除属性,因为您没有可以复制它们的模板。 <xsl:template match="*">
只匹配元素,不匹配属性(或文本、cmets 或处理指令)。
下面是一个样式表,它从已处理的文档中删除所有命名空间定义,但复制所有其他节点和值:元素、属性、cmets、文本和处理指令。请注意两点
-
仅复制属性不足以删除所有命名空间。即使包含元素不属于命名空间,属性也可以属于命名空间。因此,还需要创建属性,如元素。使用
<xsl:attribute>
元素创建属性。
有效的 XML 文档不能包含具有两个或多个具有相同扩展名称的属性的元素,但元素可以包含具有相同本地名称的多个属性如果属性具有不同的命名空间。这意味着删除如果有一个元素具有至少两个具有相同本地名称的属性,则属性名称的命名空间前缀将导致数据丢失。这些属性中的其他一个将被删除(或覆盖)。
...和代码:
<?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 ***, 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
属性来防止元素与此模板匹配。
【讨论】:
完美的兄弟谢谢。网上有很多其他解决方案,但这是唯一有效的。【参考方案2】:如何在其中包含属性?
只需将此模板附加到您已有的模板:
<xsl:template match="@*">
<xsl:copy/>
</xsl:template>
【讨论】:
【参考方案3】:<?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>
【讨论】:
如果你能在你的代码周围添加一些解释会很好。以上是关于如何使用 XSLT 从 XML 中删除名称空间的主要内容,如果未能解决你的问题,请参考以下文章