XDT Transform: InsertBefore - условие локатора игнорируется
У меня есть файл 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, поэтому я не смогу использовать пользовательское преобразование ( как тот, который использует AppHarbor).
Есть ли какой-нибудь другой умный способ поместить мой элемент в нужное место, только если он еще не существует?
Чтобы проверить это, используйте тестер преобразования конфигурации AppHarbors. Замените 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", как указано в Transform InsertBefore. Почему условие локатора не было учтено?
1 ответ
Поэтому, столкнувшись с той же проблемой, я нашел решение. Это не красиво и не элегантно, но работает. (По крайней мере на моей машине)
Я просто разделил логику на 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)" />
Вопрос, который до сих пор остается без ответа, заключается в том, почему условия Locator не учитываются для InsertBefore. Или почему я не могу обработать пустой набор совпадений для InsertBefore, потому что это позволило бы мне делать забавные вещи, такие как
//configuration/*[position()=1 and not(local-name()='configSections')]
Честно говоря, гораздо более ясный способ сделать то, чего я хочу достичь.