示例XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslnsv="http://sample2.1">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//xslnsv:Activity">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:if test="not(@IsForCompensation)
and (./xslnsv:IsForCompensationSpecified)">
<xsl:attribute name="IsForCompensation">
<xsl:value-of
select="./xslnsv:IsForCompensationSpecified" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates
select="@*|node()[local-name()
!= 'IsForCompensationSpecified']" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这里我们有一个命名空间xmlns:xslnsv="http://sample2.2"当我们有相同命名空间
的xml时,它可以工作<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://sample2.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<ElementAtLevel1>
<ElementAtLevel2 Id="cf9d2" Name="Pool 1">
<Activities>
<Activity Id="ef84125a">
<IsForCompensationSpecified
>false</IsForCompensationSpecified>
</Activity>
<Activity Id="39c5b8d8" Name="Task 1">
<IsForCompensationSpecified
>true</IsForCompensationSpecified>
</Activity>
</Activities>
</ElementAtLevel2>
</ElementAtLevel1>
<ExtendedAttributes />
</Package>
产生如下输出:
<?xml version="1.0"?>
<Package xmlns="http://sample2.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ElementAtLevel1>
<ElementAtLevel2 Id="cf9d267d-e1ed-4616-adfb-d24d6844f775"
Name="Pool 1">
<Activities>
<Activity Id="ef84125a-0a01-4d76-9b3b-413ffb3c7a74"
IsForCompensation="false"/>
<Activity Id="39c5b8d8-9a72-40d1-b3e4-8cd973ccdf03"
Name="Task 1"
IsForCompensation="true"/>
</Activities>
</ElementAtLevel2>
</ElementAtLevel1>
<ExtendedAttributes/>
</Package>
但问题是:我们有一些具有不同名称空间(如http://sample2.1)的xml使用不同名称空间的xml示例
<?xml version="1.0"?>
<Package xmlns="http://sample2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ElementAtLevel1>
<ElementAtLevel2 Id="cf9d267d-e1ed-4616-adfb-d24d6844f775"
Name="Pool 1">
<Activities>
<Activity Id="ef84125a-0a01-4d76-9b3b-413ffb3c7a74"
IsForCompensation="false"/>
<Activity Id="39c5b8d8-9a72-40d1-b3e4-8cd973ccdf03"
Name="Task 1"
IsForCompensation="true"/>
</Activities>
</ElementAtLevel2>
</ElementAtLevel1>
<ExtendedAttributes/>
</Package>
那么我们就没有正确的输出。
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://sample2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<ElementAtLevel1>
<ElementAtLevel2 Id="cf9d2" Name="Pool 1">
<Activities>
<Activity Id="ef84125a">
<IsForCompensationSpecified
>false</IsForCompensationSpecified>
</Activity>
<Activity Id="39c5b8d8" Name="Task 1">
<IsForCompensationSpecified
>true</IsForCompensationSpecified>
</Activity>
</Activities>
</ElementAtLevel2>
</ElementAtLevel1>
<ExtendedAttributes />
</Package>
我修改了xslt以动态地更改名称空间。带有新更改的XSLT示例
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslnsv="http://sample2.2" >
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="vUrl" select="'http://sample2.2'"/>
<xsl:template match="*[namespace-uri()='http://sample2.1']">
<xsl:element name="{name()}" namespace="{$vUrl}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//xslnsv:Activity">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:if test="not(@IsForCompensation)
and (./xslnsv:IsForCompensationSpecified)">
<xsl:attribute name="IsForCompensation">
<xsl:value-of
select="./xslnsv:IsForCompensationSpecified" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*
|node()[local-name() != 'IsForCompensationSpecified']" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在我看来,它能够更改名称空间,但不能在更改名称空间后选择元素。可能是指旧的命名空间ie2.1从源xml
但我仍然没有得到正确的输出;我得到如下输出:
<?xml version="1.0"?>
<Package xmlns="http://sample2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ElementAtLevel1>
<ElementAtLevel2 Id="cf9d2" Name="Pool 1">
<Activities>
<Activity Id="ef84125a">
<IsForCompensationSpecified>false</IsForCompensationSpecified>
</Activity>
<Activity Id="39c5b8d8" Name="Task 1">
<IsForCompensationSpecified>true</IsForCompensationSpecified>
</Activity>
</Activities>
</ElementAtLevel2>
</ElementAtLevel1>
<ExtendedAttributes/>
</Package>
[根据OP对问题的修改而修改]
如果我正确理解您,您希望如果在输入中遇到具有localname Activity的命名空间http://sample2.1中的元素,那么(1)具有match="*[namespace-uri()='http://sample2.1']"
的模板将与其匹配并将其移动到命名空间http://sample2.2中,然后(2)具有match="//xslnsv:Activity"
的模板将触发。这是正确的理解吗?
如果是这样,这里有两个问题。
首先,更改名称空间的模板在名称空间http://sample2.2中生成一个新的元素节点,但是您所展示的代码中没有尝试将任何模板应用于该新元素节点。
第二个问题是XSLT 1.0模板只匹配输入文档中的元素;它们不匹配也不能匹配由样式表构造的节点。这是XSLT 1.0和XSLT 2.0之间最大的区别之一。XSLT 1.0的一个公共扩展允许模板匹配创建的节点;如果您想尝试,请查找有关节点集扩展的信息。
更简单的解决方案是将样式表分成两部分:一部分将元素从旧名称空间移动到新名称空间,另一部分处理新名称空间中的元素。
我还应该注意到我无法复制您的结果。当我在您提供的输入上运行您提供的样式表时,我在名称空间http://sample2.2中得到输出,而不是在名称空间http://sample2.1中。我猜您是复制/粘贴错误的受害者。)