如何使用xslt更改xml中的名称空间

问题描述:

我需要将xml中的所有属性转换为具有某些条件的元素。举例来说,一些属性应该以“Value”作为前缀。我实现了这个目标。除此之外,我还需要更改我的名称空间。我无法做到这一点。如何使用xslt更改xml中的名称空间

XML

<Template xmlns="styling/1.0.0" Name="TemplateFromDictionary"> 

    <Style Name="Default"> 
    <Fill Color=""/> 
    <Stroke Color="0000FF" LineStyle="Single" Width="1"/> 
    <Symbol Color="FFFFFF" Name="default.png" ScaleX="100" ScaleY="100" ScaleMode="Drawing"/> 
    </Style> 

    <Style Name="Parcel"> 
    <Fill Color="48F5F5F5"/> 
    <Stroke Color="C0C0C0" LineStyle="Single" Width="1"/> 
    <Symbol Color="FFFFFF" Name="default.png" ScaleX="100" ScaleY="100" ScaleMode="Drawing"/> 
    </Style> 

</Template> 

XSLT

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       exclude-result-prefixes="msxsl" 
       xmlns:s="styling/1.0.0" 
       xmlns="styling/1.0.0"> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="s:Style|s:Template"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="@*"> 
    <xsl:variable name="name"> 
     <xsl:apply-templates select="." mode="name"/> 
    </xsl:variable> 
    <xsl:element name="{$name}"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="@Color|@Width|@ScaleX|@ScaleY|@LeftIndent|@RightIndent|@FirstLineIndent|@SpaceBefore|@SpaceAfter|@Size" mode="name"> 
    <xsl:value-of select="concat(name(), 'Value')"/> 
    </xsl:template> 

    <xsl:template match="@*" mode="name"> 
    <xsl:value-of select="name()"/> 
    </xsl:template> 

</xsl:stylesheet> 

OUTPUT

<?xml version="1.0" encoding="utf-8"?> 
<Template Name="TemplateFromDictionary" xmlns="styling/1.0.0"> 

    <Style Name="Default"> 
    <Fill> 
     <ColorValue></ColorValue> 
    </Fill> 
    <Stroke> 
     <ColorValue>0000FF</ColorValue> 
     <LineStyle>Single</LineStyle> 
     <WidthValue>1</WidthValue> 
    </Stroke> 
    <Symbol> 
     <ColorValue>FFFFFF</ColorValue> 
     <Name>default.png</Name> 
     <ScaleXValue>100</ScaleXValue> 
     <ScaleYValue>100</ScaleYValue> 
     <ScaleMode>Drawing</ScaleMode> 
    </Symbol> 
    </Style> 

    <Style Name="Parcel"> 
    <Fill> 
     <ColorValue>48F5F5F5</ColorValue> 
    </Fill> 
    <Stroke> 
     <ColorValue>C0C0C0</ColorValue> 
     <LineStyle>Single</LineStyle> 
     <WidthValue>1</WidthValue> 
    </Stroke> 
    <Symbol> 
     <ColorValue>FFFFFF</ColorValue> 
     <Name>default.png</Name> 
     <ScaleXValue>100</ScaleXValue> 
     <ScaleYValue>100</ScaleYValue> 
     <ScaleMode>Drawing</ScaleMode> 
    </Symbol> 
    </Style> 

</Template> 

在输出,而不是这个

<Template Name="TemplateFromDictionary" xmlns="styling/1.0.0"> 

我需要这个

<Template Name="TemplateFromDictionary" xmlns="styling/2.0.0"> 

我试图通过改变XSLT的命名空间xmlns="styling/2.0.0"但是,这是给像

<Fill><ColorValue xmlns="styling/2.0.0"></ColorValue></Fill>

命名空间中的结果嵌入到所有元素和Template元素看起来相同

<Template Name="TemplateFromDictionary" xmlns="styling/1.0.0">

我需要的输出与上面提到的输出完全相同,只是需要更改Template元素中的名称空间。

我正在用C#进行转换。

请帮我解决这个问题。

要改变命名空间全部您可以使用namespace属性使用xsl:element重建它们的元素。所以,下面的代码改变两个模板,并增加了一个一般的“使用新的命名空间”模板:

<!-- use-new-namespace template for all s:* elements --> 
<xsl:template match="s:*"> 
    <xsl:element name="{local-name()}" namespace="styling/2.0.0"> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:element> 
</xsl:template> 

<!-- modified templates for new namespace --> 
<xsl:template match="s:Style|s:Template"> 
    <xsl:element name="{local-name()}" namespace="styling/2.0.0"> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:variable name="name"> 
     <xsl:apply-templates select="." mode="name"/> 
    </xsl:variable> 
    <xsl:element name="{$name}" namespace="styling/2.0.0"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
</xsl:template> 

所以整个XSLT文件:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       exclude-result-prefixes="msxsl" 
       xmlns:s="styling/1.0.0" 
       xmlns:t="styling/2.0.0"> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- use-new-namespace template for s:* elements --> 
    <xsl:template match="s:*"> 
    <xsl:element name="{local-name()}" namespace="styling/2.0.0"> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:element> 
    </xsl:template> 

    <!-- modified templates for new namespace --> 
    <xsl:template match="s:Style|s:Template"> 
    <xsl:element name="{local-name()}" namespace="styling/2.0.0"> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="@*"> 
    <xsl:variable name="name"> 
     <xsl:apply-templates select="." mode="name"/> 
    </xsl:variable> 
    <xsl:element name="{$name}" namespace="styling/2.0.0"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="@Color|@Width|@ScaleX|@ScaleY|@LeftIndent|@RightIndent|@FirstLineIndent|@SpaceBefore|@SpaceAfter|@Size" mode="name"> 
    <xsl:value-of select="concat(name(), 'Value')"/> 
    </xsl:template> 

    <xsl:template match="@*" mode="name"> 
    <xsl:value-of select="name()"/> 
    </xsl:template> 

</xsl:stylesheet> 
+0

我很抱歉,我无法理解。你能否详细说明一下? – shanmugharaj

+0

简而言之,添加上面的第一个模板,并在XSLT中更改其他两个模板。然后每个元素都会得到新的名称空间。 – zx485

+0

我现在还有一个问题。这是我需要做的一项新增强。实际上,在为符号' default.png'写入输出时,根据Name属性中的内容包含'png'或'dwg',name属性必须以C:\或C:\ dwg \为前缀。我试着把这个条件放在这个''里面。但我无法得到这个工作。你能帮我解决这个问题吗? – shanmugharaj

实现您的目标的一种方法是用新的名称空间重写Template元素。例如:添加下面的模板到您的XSLT:

<xsl:template match="s:Style"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:copy> 
    </xsl:template> 

<xsl:template match="s:Template" xmlns:ns2="styling/2.0.0"> 
    <ns2:Template> 
    <xsl:copy-of select="@*"/> 
    <xsl:apply-templates select="node()"/> 
    </ns2:Template> 
</xsl:template> 

,取出旧S:风格| S:模板匹配模板

更清晰:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       exclude-result-prefixes="msxsl" 
       xmlns:s="styling/1.0.0" 
       xmlns="styling/1.0.0"> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 
<!--  
    <xsl:template match="s:Style|s:Template"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:copy> 
    </xsl:template> 
-->  
<xsl:template match="s:Style"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="node()"/> 
    </xsl:copy> 
    </xsl:template> 

<xsl:template match="s:Template" xmlns:ns2="styling/2.0.0"> 
    <ns2:Template> 
    <xsl:copy-of select="@*"/> 
    <xsl:apply-templates select="node()"/> 
    </ns2:Template> 
</xsl:template> 

    <xsl:template match="@*"> 
    <xsl:variable name="name"> 
     <xsl:apply-templates select="." mode="name"/> 
    </xsl:variable> 
    <xsl:element name="{$name}"> 
     <xsl:value-of select="."/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="@Color|@Width|@ScaleX|@ScaleY|@LeftIndent|@RightIndent|@FirstLineIndent|@SpaceBefore|@SpaceAfter|@Size" mode="name"> 
    <xsl:value-of select="concat(name(), 'Value')"/> 
    </xsl:template> 

    <xsl:template match="@*" mode="name"> 
    <xsl:value-of select="name()"/> 
    </xsl:template> 

</xsl:stylesheet> 
+0

你不觉得OP可能希望将新的名称空间应用于_all_元素,并且旧的名称空间基本上被丢弃了? – kumesana