XDT 转换:InsertBefore - 定位器条件被忽略
Posted
技术标签:
【中文标题】XDT 转换:InsertBefore - 定位器条件被忽略【英文标题】:XDT Transform: InsertBefore - Locator Condition is ignored 【发布时间】:2013-09-15 05:33:40 【问题描述】:我有一个 web.config 文件,我需要在其中插入 <configSections />
元素或操作该节点的子节点(如果它已经存在)。
如果它已经存在,我不想再次插入它(显然,因为它只允许存在一次)。
不过,通常情况下,这不是问题:
如果此元素在配置文件中,则它必须是该元素的第一个子元素。
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 转换中指定的那样。
为什么没有考虑定位条件?
【问题讨论】:
我在 runtime/assemblyBinding/dependentAssembly 节点上遇到了类似的问题。 【参考方案1】:所以在遇到同样的问题后,我想出了一个解决方案。它既不漂亮也不优雅,但它确实有效。 (至少在我的机器上)
我只是将逻辑拆分为 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 不考虑定位器条件。或者为什么我不能为 InsertBefore 处理一个空匹配集,因为这可以让我做一些有趣的事情,比如
//configuration/*[position()=1 and not(local-name()='configSections')]
说实话,这是一种更清晰的方式来实现我想要实现的目标。
【讨论】:
太棒了,就像一个魅力,甚至包含在 NuGet 包中!这确实是一个黑客,但这正是我所需要的。谢谢! 我认为这将是一个奇怪的怪癖,我找不到简单的解决方法,但这非常有效! 对于 unintall,我只是删除了部分的配置和部分本身,按名称:以上是关于XDT 转换:InsertBefore - 定位器条件被忽略的主要内容,如果未能解决你的问题,请参考以下文章
XML query() 有效,value() 需要找到单例 xdt:untypedAtomic