【问题标题】:How to change the namespace in xml using xslt如何使用 xslt 更改 xml 中的命名空间
【发布时间】:2018-02-08 06:39:50
【问题描述】:

我需要将 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>

输出

<?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" 但这给出的结果类似于

&lt;Fill&gt;&lt;ColorValue xmlns="styling/2.0.0"&gt;&lt;/ColorValue&gt;&lt;/Fill&gt;

命名空间嵌入到所有元素中,模板元素看起来相同

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

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

我正在用 C# 转换它。

请帮帮我。

【问题讨论】:

    标签: .net xml xslt


    【解决方案1】:

    要更改 所有 元素的命名空间,您可以使用 namespace 属性使用 xsl:element 重构它们。所以下面的代码改变了两个模板,增加了一个通用的“use-new-namespace”模板:

    <!-- 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>
    

    【讨论】:

    • 很抱歉我听不懂。能详细说明一下吗?
    • 简而言之,添加上面的第一个模板并在您的 XSLT 中更改另外两个。然后每个元素都会获得新的命名空间。
    • 我现在还有一个问题。这是我需要做的一个新的增强。实际上,在为符号 &lt;Name&gt;default.png&lt;/Name&gt; 编写输出时,名称属性必须以 C:\ 或 C:\dwg\ 为前缀,这取决于 Name 属性中包含“png”或“dwg”的内容。我尝试将条件放在此&lt;xsl:template match="@*"&gt; 中。但我无法让这个工作。你能帮我解决这个问题吗?
    • @shansfk:我想这是一个全新的问题。我无法从评论中看出你希望改变什么......也许xsl:choose的一个案例......一个好的minimal reproducible example的新问题肯定会有所帮助。
    【解决方案2】:

    实现目标的一种方法是使用新的命名空间重写 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:Style|s:Template 匹配模板

    更清楚:

    <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>
    

    【讨论】:

    • 你不认为 OP 可能希望将新的命名空间应用于 所有 元素,而旧的命名空间基本上被丢弃了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    相关资源
    最近更新 更多