基于值的XSL匹配元素

时间:2010-10-21 04:46:49

标签: c# xml xslt

我正在转换XML,我应该找到一个特定的元素(基于属性值)并更新Element及其子属性。

示例XML文件如下所示。

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Environments>
        <Environment id="Master"/>
        <Environment id="Developer"/>
    </Environments>
    <Common>
        <Logging>
            <LogFile>log\updater.log</LogFile>
        </Logging>
    </Common>
<Configuration>

我的XSLT文件如下。

<?xml version="1.0" encoding="utf-8"?>
<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:param name="EnvironmentId" />
    <xsl:param name="SelectEnvironment" />
    <!-- Copy All Elements -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- Modify Element with id = Developer-->
    <xsl:template match="Environment/@id[. ='Developer']">
        <xsl:attribute name="id">
            <xsl:value-of select="$EnvironmentId"/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

在这个XSLT中,变量EnvironmentId包含新的id;变量SelectEnvironment应包含值Developer(或通过C#.NET传递的任何其他用户提供的值)

问题

如何编写XSLT以使匹配基于用户定义的值工作?

我尝试了以下

<xsl:template match="Environment/@id[. ='$SelectEnvironment']">
    <xsl:attribute name="id">
        <xsl:value-of select="$EnvironmentId"/>
    </xsl:attribute>
</xsl:template>

没有错误。但是,attr id没有更新。

我试过了......

<xsl:template match="Environment/@id[. =$SelectEnvironment]">
    <xsl:attribute name="id">
        <xsl:value-of select="$EnvironmentId"/>
    </xsl:attribute>
</xsl:template>

我得到一个运行时错误,变量不能在这个表达式中使用。

2 个答案:

答案 0 :(得分:2)

模板匹配中不能包含变量;它们可以与编译时进行比较。你的难题的答案是将逻辑从竞争中移出(并且可能在性能上失去轻微的惩罚)。未经测试;

<xsl:template match="Environment/@id">
   <xsl:if test="[.=$SelectEnvironment]">
      <xsl:attribute name="id">
         <xsl:value-of select="$EnvironmentId"/>
      </xsl:attribute>
   </xsl:if>
</xsl:template>

然而,还有其他更好更快的方法来解决您的问题,这可能比您的示例问题所指出的要好一些吗?

这是我的完整XSLT,它可以完成您想要的任务,经过全面测试(复制粘贴中缺少元素的关闭是错误的吗?);

<?xml version="1.0" encoding="UTF-8"?>
<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:param name="EnvironmentId" />
    <xsl:param name="SelectEnvironment" />
    <!-- Copy All Elements -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- Modify Element with id = Developer-->
    <xsl:template match="Environment">
        <xsl:choose>
            <xsl:when test="@id=$SelectEnvironment">
                <Environment id="{$EnvironmentId}" />
            </xsl:when>
            <xsl:otherwise>
                <Environment id="{@id}" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

  

我试过了......

     <xsl:template match="Environment/@id[.
 =$SelectEnvironment]"> 
         <xsl:attribute name="id"> 
             <xsl:value-of select="$EnvironmentId"/> 
         </xsl:attribute> 
     </xsl:template>
  

我得到了一个运行时错误   变量不能在此范围内使用   表达

在XSLT 1.0中,匹配表达式不能包含对变量或参数的引用。这样做是为了防止循环定义。

但是在XSLT 2.0中they are allowed in a match pattern

因此,您可以使用XSLT 2.0来实现。

对于某些人来说,XSLT 2.0仍然是一个遥远的梦想 - 那么你总是可以按照接受的答案推荐。