XSLT Transformation添加新节点

时间:2013-06-27 11:28:40

标签: xslt

我有一个如下所示的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">
  <xsl:output method="xml" indent="yes" />
    <xsl:template match="/configuration">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:element name="system.diagnostics">
        <trace autoflush="true">
          <listeners>
            <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics" name="AzureDiagnostics"></add>
          </listeners>
        </trace>
      </xsl:element>      
    </xsl:copy>
  </xsl:template>
<xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template> 
 <xsl:template match="configuration">    
       <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:element name="location">
        <xsl:attribute name="path">securfolder1</xsl:attribute>
        <system.web>
          <authorization>
            <deny users="*"/>
          </authorization>
        </system.web>
      </xsl:element>      
    </xsl:copy>
  </xsl:template>  
</xsl:stylesheet>

我期待上面应该产生以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.diagnostics>
      <trace autoflush="true">
         <listeners>
            <add name="AzureDiagnostics"
                 type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics"/>
         </listeners>
      </trace>
  </system.diagnostics>
   <location path="securfolder1">
      <system.web>
         <authorization>
            <deny users="*"/>
         </authorization>
      </system.web>
   </location>
</configuration>

但是有些原因它没有用。您可能会问为什么我有两个模板匹配。问题是由第三方提供的以下顶部我们无法改变。

<xsl:template match="/configuration">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" />
          <xsl:element name="system.diagnostics">
            <trace autoflush="true">
              <listeners>
                <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics" name="AzureDiagnostics"></add>
              </listeners>
            </trace>
          </xsl:element>      
        </xsl:copy>
      </xsl:template>

以下是INPUT XML:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>  
</configuration>

1 个答案:

答案 0 :(得分:0)

即使您要应用这两个模板,它们都会输出配置元素,这会导致您的输出有两个配置元素,而不仅仅是您的需要。

然而,我可以想到一个相当hacky的解决方案,如果你真的,真的不能让第一个模板改变。

您可以做的是创建一个与文档元素匹配的模板,该模板元素高于根配置元素,因此将首先匹配

<xsl:template match="/">

然后,在此模板中,您可以应用其配置匹配模板,但将结果存储在变量

 <xsl:variable name="theirs">
    <xsl:apply-templates select="configuration" />
 </xsl:variable>

我假设您在这里使用的是Microsoft平台,因为它非常适用于Microsoft应用程序配置文件。这意味着您应该可以访问Microsoft的扩展功能。您将需要这些,因为他们的变量是“结果树片段”,但要使此解决方案起作用,您需要将其作为节点集进行访问。

基本上,您可以在自己的模板(现在匹配/)中执行的操作是:

<configuration>
    <xsl:copy-of select="msxsl:node-set($theirs)/configuration/*" />
    <!-- You own elements -->
</configuration>

换句话说,复制第一个模板生成的元素,然后输出自己的元素。

这是完整的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">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/configuration">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
         <xsl:element name="system.diagnostics">
            <trace autoflush="true">
               <listeners>
                  <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics" name="AzureDiagnostics"/>
               </listeners>
            </trace>
         </xsl:element>
      </xsl:copy>
   </xsl:template>

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

   <xsl:template match="/">
      <xsl:variable name="theirs">
         <xsl:apply-templates select="configuration" />
      </xsl:variable>
      <configuration>
         <xsl:copy-of select="msxsl:node-set($theirs)/configuration/*"/>
         <xsl:element name="location">
            <xsl:attribute name="path">securfolder1</xsl:attribute>
            <system.web>
               <authorization>
                  <deny users="*"/>
               </authorization>
            </system.web>
         </xsl:element>
      </configuration>
   </xsl:template>
</xsl:stylesheet>

当应用于输入XML时,输出以下内容

<configuration>
   <system.diagnostics>
      <trace autoflush="true">
         <listeners>
            <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics" name="AzureDiagnostics"/>
         </listeners>
      </trace>
   </system.diagnostics>
   <location path="securfolder1">
      <system.web>
         <authorization>
            <deny users="*"/>
         </authorization>
      </system.web>
   </location>
</configuration>