Skip to main content
 首页 » 编程设计

web-config之XDT 转换 : InsertBefore之Locator Condition is ignored

2024年12月31日9zdz8207

我有一个 web.config 文件,我需要在其中插入 <configSections />元素或操作该节点的子节点(如果它已经存在)。
如果它已经存在,我不想再次插入它(显然,因为它只允许存在一次)。

通常,这不会有问题,但是:

If this element is in a configuration file, it must be the first child element of the element.



Source: MSDN .

所以如果我使用 xdt:Transform="InsertIfMissing" <configSections />元素将始终插入在任何现有子元素之后(并且总是有一些),违反了上述限制它必须是 <configuration /> 的第一个子元素

我试图通过以下方式完成这项工作:

 <configSections 
    xdt:Transform="InsertBefore(/configuration/*[1])" 
    xdt:Locator="Condition(not(.))" /> 

如果 <configSections />,哪个工作完美元素不存在。但是,我指定的条件似乎被忽略了。

事实上,我已经尝试了一些条件,例如:
Condition(not(/configuration[configSections])) 
Condition(/configuration[configSections] = false()) 
Condition(not(/configuration/configSections)) 
Condition(/configuration/configSections = false()) 

最后,出于绝望,我尝试了:
Condition(true() = false())  

它仍然插入了 <configSections />元素。

请务必注意,我正在尝试将其包含在 NuGet 包中,因此我将无法使用自定义转换 ( like the one AppHarbor uses )。

有没有其他聪明的方法可以让我的元素仅在它不存在的时候放在正确的位置?

要对此进行测试,请使用 AppHarbors config transform tester .将 Web.config 替换为以下内容:

<?xml version="1.0"?> 
<configuration> 
  <configSections> 
    <section name="initialSection" /> 
  </configSections> 
</configuration> 

和 Web.Debug.config 具有以下内容:

<?xml version="1.0"?> 
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> 
 
  <configSections 
    xdt:Transform="InsertBefore(/configuration/*[1])" 
    xdt:Locator="Condition(true() = false())" /> 
 
  <configSections> 
    <section name="mySection" xdt:Transform="Insert" /> 
  </configSections> 
 
</configuration> 

结果会显示两个 <configSections />元素,第一个包含“mySection”的元素,如 InsertBefore Transform 中指定的那样。
为什么没有考虑定位条件?

请您参考如下方法:

所以在遇到同样的问题后,我想出了一个解决方案。它不漂亮也不优雅,但它有效。 (至少在我的机器上)

我只是将逻辑拆分为 3 个不同的语句。首先,我在正确的位置(第一个)添加一个空的 configSections。然后我将新配置插入 最后 configSections,如果它是唯一的,则为新的,否则为先前存在的。
最后,我删除了任何可能存在的空 configSections 元素。我无缘无故地使用 RemoveAll,您可能应该使用 Remove。

整体代码如下所示:

<configSections xdt:Transform="InsertBefore(/configuration/*[1])" /> 
<configSections xdt:Locator="XPath(/configuration/configSections[last()])"> 
    <section name="initialSection" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" /> 
</configSections> 
<configSections xdt:Transform="RemoveAll" xdt:Locator="Condition(count(*)=0)" /> 

仍然没有回答的问题是为什么 InsertBefore 没有考虑定位器条件。或者为什么我不能处理 InsertBefore 的空匹配集,因为这会让我做一些有趣的事情,比如
//configuration/*[position()=1 and not(local-name()='configSections')] 

老实说,这是做我想要实现的目标的更清晰的方法。