しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

FatAntelope を使って XML Document Transform (XDT) を自動で生成する

主に ASP.NET アプリケーションの Web.config 変換で使われている XML Document Transform (XDT) ですが、個人的にはあれを手書きするのはかなり嫌いでした。

XML の差分を持っているだけなので、自動生成できるのではないかと長い間思ってましたが、最近 FatAntelope というまさに待ち望んでいたライブラリが公開されました。

2 つの XML を指定すると、自動的に差分を取って XDT として書き出してくれます。最高ですね。コマンドラインツールやライブラリの形で公開されているので、簡単に使い方の紹介をしておきます。

XDT を生成する

FatAntelope のコマンドラインツールは GitHub で公開されているので最新版をダウンロードしてきます。

今回はサンプルとして Web.config っぽいものを適当に用意しました。開発時に使うものになります。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="DefaultConnection"
         connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=DevelopmentDB;Integrated Security=True"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" />
  </system.web>
</configuration>

そしてこっちが本番用の Web.config になります。内容としては接続文字列を本番向けにして、リリースビルドを行うというものです。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="DefaultConnection"
         connectionString="Server=tcp:***.database.windows.net,1433;Database=ProductionDB;User ID=***;Password=***;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" />
  </system.web>
</configuration>

この 2 つのファイルを FatAntelope に与えると、XDT が生成されます。生成された XDT はひとまず Web.Release.config とでも名前を付けて保存するようにします。

FatAntelope Web.config Production.config Web.Release.config

コマンドを実行すると、コンソールにメッセージが出るのでエラーにならなければ成功です。

そして出力された XDT が以下のようになります。ちゃんと差がある部分だけを抽出してくれています。

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings>
    <add connectionString="Server=tcp:***.database.windows.net,1433;Database=ProductionDB;User ID=***;Password=***;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;" xdt:Transform="SetAttributes(connectionString)" />
  </connectionStrings>
  <system.web>
    <compilation xdt:Transform="RemoveAttributes(debug)" />
  </system.web>
</configuration>

手書きの場合と比較すると xdt:Locator が無かったりと、少し違和感があるかもしれませんが、XDT の仕様としてはこれで問題はありません。XML 宣言は何故か付かないので、後で追加しましょう。

C# から XDT を生成する

FatAntelope は NuGet でライブラリが公開されているので、API には多少癖がありますが、自分のアプリケーションなどに簡単に組み込むことが可能です。

当然ながら NuGet を使って FatAntelope をインストールする必要があります。

Install-Package FatAntelope

FatAntelope の API は多少癖があるので、最低限の XDT 生成を行うコードを紹介しておきます。

using System;
using System.Xml;

using FatAntelope;
using FatAntelope.Writers;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            // 元になる XML
            var baseXml = new XmlDocument();

            baseXml.Load(@"C:\Users\shibayan\Downloads\FatAntelope.v0.2.3\Web.config");

            // 新しい XML
            var newXml = new XmlDocument();

            newXml.Load(@"C:\Users\shibayan\Downloads\FatAntelope.v0.2.3\Production.config");

            // XmlDocument から XTree を作成しておく
            var baseTree = new XTree(baseXml);
            var newTree = new XTree(newXml);

            // XDiff を使って差分を計算し、newTree に格納
            XDiff.Diff(baseTree, newTree);

            // 差分が格納された XTree を元に XDT として書き出し
            var patch = new XdtDiffWriter().GetDiff(newTree);

            patch.Save(Console.Out);

            Console.WriteLine();
        }
    }
}

XDiff.Diff を呼び出した結果がイマイチな感じですね。これを実行すると XDT がコンソールに出力されます。

生成された XDT をどのように使うかはお任せします。MSBuildTask などにしてしまうのも手だと思います。

おまけ:XDT を XML に反映させる

完全におまけですが、元になる XML と XDT を使って、差分が反映された XML を生成する方法も紹介しておきます。ちなみにこちらは Microsoft 純正のライブラリが提供されています。

http://blogs.msdn.com/b/webdev/archive/2013/04/23/xdt-xml-document-transform-released-on-codeplex-com.aspx

ライブラリは NuGet で公開されているので、FatAntelope と同じようにサクッと使えます。

基本的に XmlDocument を継承したクラスを使って XML に対して XDT を適用する形になります。こちらもサンプルコードを紹介しておきます。

using System;

using Microsoft.Web.XmlTransform;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            // 変換元の XML を読み込む
            var source = new XmlTransformableDocument();

            source.Load(@"C:\Users\shibayan\Downloads\FatAntelope.v0.2.3\Web.config");

            // XDT を読み込んで Apply で反映させる
            var xdt = new XmlTransformation(@"C:\Users\shibayan\Downloads\FatAntelope.v0.2.3\Web.Release.config");

            xdt.Apply(source);

            source.Save(Console.Out);

            Console.WriteLine();
        }
    }
}

実行すると XDT の内容が反映された XML がコンソールに出力されます。

これまでは XDT を適用するという一方向のみの対応でしたが、FatAntelope のリリースによって XML から XDT を作成するという、双方向の変換が可能になりました。

個人的には Web.config 変換を書きやすくするための Visual Studio 拡張を作りたいですね。