我有两种类型的输入xml,一种带有名称空间前缀,另一种没有前缀,我想替换名称空间。
的Sample1
<v1:Library xmlns:v1="http://testlibrary" xmlns:v2="http://commonprice">
<v1:Books_details>
<v1:Name>test1</v1:Name>
<v1:title>test2</v1:title>
<v2:price xmlns="http://commonprice">12</v2:price>
</v1:Books_details>
</v1:Library>
样品2
<Library xmlns="http://testlibrary">
<Books_details>
<Name>test1</Name>
<title>test2</title>
<price xmlns="http://commonprice">12</price>
</Books_details>
</Library>
我已经编写了以下XSLT来将命名空间从“ http:// testlibrary ”更改为“ http:// newlibrary ”并且它适用于sample1但它可以正常工作不适用于sample2。它给出了错误的结果。它也改变了price元素的命名空间,即使它没有要替换的命名空间。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="old_namespace"/>
<xsl:param name="new_namespace"/>
<xsl:template match="/">
<xsl:apply-templates select="@* | node()"/>
</xsl:template>
<xsl:template match="text() | comment() | processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="text() | comment() | processing-instruction()"/>
</xsl:copy>
</xsl:template>
<!-- Template used to copy elements -->
<xsl:template match="*">
<xsl:variable name="name">
<xsl:choose>
<xsl:when test="contains(name(), ':')">
<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="local-name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$name}" namespace="{$new_namespace}">
<!-- Copy all namespace through except for namespace to be changed -->
<xsl:for-each select="namespace::*">
<xsl:if test="string(.)!=$old_namespace">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:0)
注意:我的第一个答案是错误的,因为在XSLT 1.0中,您不能在匹配模式中使用变量引用。
此样式表将Sample1或Sample2作为输入文档,并使用新命名空间替换元素名称中所有出现的旧命名空间。注意:您可以为xsl:param更改xsl:变量。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="old_namespace" select="'http://testlibrary'" />
<xsl:variable name="new_namespace" select="'http://newlibrary'" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:choose>
<xsl:when test="namespace-uri()=$old_namespace">
<xsl:element name="{local-name()}" namespace="{$new_namespace}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
上面的样式表只会更改元素的名称空间。它将不更改属性的名称空间,也不会删除无关的名称空间节点。
对变量名称空间的操作要求通用解决方案是非常罕见的。命名空间,它们往往是固定和已知的。如果你真的需要一个通用的解决方案,请仔细考虑。如果您需要一个特定的解决方案,意味着替换特定命名空间的出现,那么事情变得更容易,例如使用此样式表......
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://testlibrary"
xmlns:new="http://newlibrary">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="old:*">
<xsl:element name="{local-name()}" namespace="http://newlibrary">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>