web-dev-qa-db-ja.com

XDT変換:InsertBefore-ロケーター条件は無視されます

<configSections />要素を挿入するか、ノードの子がすでに存在する場合はその子を操作する必要があるweb.configファイルがあります。
すでに存在している場合は、再度挿入したくありません(明らかに、存在は1回しか許可されていないため)。

通常、これは問題にはなりませんが、次のようになります。

この要素が構成ファイルにある場合は、要素の最初の子要素である必要があります。

出典: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パッケージに含めようとしているため、カスタム変換を使用できないことに注意することが重要です( AppHarborが使用するもののように )。

要素がまだ存在しない場合にのみ、要素を適切な場所に配置する他の賢い方法はありますか?

これをテストするには、 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>

結果には、InsertBefore Transformで指定されているように、2つの<configSections />要素が表示されます。1つは「mySection」を含む要素が最初です。ロケーター条件が考慮されなかったのはなぜですか?

24
sebastiaan

それで、同じ問題に直面した後、私は解決策を思いつきました。かわいくもエレガントでもありませんが、機能します。 (少なくとも私のマシンでは)

ロジックを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')]

正直に言うと、私が達成したいことを行うためのはるかに明確な方法です。

42
Itamaram