我有一个web.config文件,我需要在其中插入<configSections />
元素或操作该节点的子节点(如果已存在)。
如果它已经存在,我不想再插入它(显然,因为它只允许存在一次)。
通常情况下,这不会有问题:
如果此元素位于配置文件中,则它必须是元素的第一个子元素。
因此,如果我使用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中指定的那样。
为什么不考虑定位条件?
答案 0 :(得分:41)
所以在面对同样的问题之后,我想出了一个解决方案。它不漂亮也不优雅,但它有效。 (至少在我的机器上)
我只是将逻辑拆分为3个不同的语句。首先,我在正确的位置添加一个空的configSections(第一个)。然后我将新配置插入 last 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不考虑Locator条件。或者为什么我无法处理InsertBefore的空匹配集,因为这样可以让我做一些有趣的事情,比如
//configuration/*[position()=1 and not(local-name()='configSections')]
说实话,这是一种更清晰的方式来实现我想要实现的目标。