ubichupas.net

XML文書をLINQで作成してみるサンプル

LINQ(Language INtegrated Query)を使うとXML文書をSQL風の構文で簡単に読むことができるというのはよく聞く話ですが、実はXML文書を書くときの方が便利になっているのです。 ただこれはLINQの効果でなく、LINQ用に作られた新しいXMLクラス群の効果なのですけども。

XML要素(タグ)を表現するときDOMではSystem.Xml.XmlElementクラスを使用しましたが、LINQではSystem.Xml.Linq.XElementクラスを使用します。 このXElementクラスのコンストラクタが可変長引数を受け取れるようになっていて、コンストラクタを入れ子にして並べるだけで目的のXML文書が完成してしまうという目から鱗な効果をもたらします。

LINQ to XMLプログラム3の実装

お題としてGundamList.xmlを出力するプログラム(GundamLinq3.cs)を作成してみました。

GundamLinq3.cs
using System.Xml.Linq;

namespace GundamLinq
{
    class GundamLinq3
    {
        static void Main(string[] args)
        {
            // 名前空間を表すオブジェクトを用意
            XNamespace ns = "urn:gundam:anime";

            // XML文書を表すオブジェクトと同時に中身も生成
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "shift_jis", "no"),
                new XDocumentType("gundamList", null, "GundamList.dtd", null),
                new XElement(ns + "gundamList",
                    new XElement(ns + "gundam",
                        new XAttribute("media", "TV"),
                        new XElement(ns + "name", "機動戦士ガンダム"),
                        new XElement(ns + "calendar", "0079",
                            new XAttribute("jpn", "宇宙世紀"),
                            new XAttribute("eng", "U.C.")
                        ),
                        new XElement(ns + "director", "富野由悠季")
                    ),
                    new XElement(ns + "gundam",
                        new XAttribute("media", "TV"),
                        new XElement(ns + "name", "機動戦士Zガンダム"),
                        new XElement(ns + "calendar", "0087",
                            new XAttribute("jpn", "宇宙世紀"),
                            new XAttribute("eng", "U.C.")
                        ),
                        new XElement(ns + "director", "富野由悠季")
                    )
                )
            );

            // ルート要素にコメントと子要素を追加
            doc.Root.Add(
                new XComment("中略"),
                new XElement(ns + "gundam",
                    new XAttribute("media", "TV"),
                    new XElement(ns + "name", "機動戦士ガンダム00 セカンドシーズン"),
                    new XElement(ns + "calendar", 2312,
                        new XAttribute("jpn", "西暦"),
                        new XAttribute("eng", "A.D.")
                    ),
                    new XElement(ns + "director", "水島精二")
                )
            );
            
            // XML文書をファイルに出力
            doc.Save(@"..\..\GundamList.xml");
        }
    }
}

XElementクラスの素晴らしさはソースコードから一目瞭然でしょう。 その影でXNamespaceクラスが縁の下の力持ち的活躍をしているので着目してください。 これは複数の名前空間が混在する場合に威力を発揮します。

LINQ to XMLプログラム3の出力

C#で書いた通りのXML文書がファイルに出力されました。 XDeclarationクラスに"utf-8"を指定しておくとUTF-8で出力されます。

GundamList.xml
<?xml version="1.0" encoding="shift_jis" standalone="no"?>
<!DOCTYPE gundamList SYSTEM "GundamList.dtd">
<gundamList xmlns="urn:gundam:anime">
 <gundam media="TV">
   <name>機動戦士ガンダム</name>
   <calendar jpn="宇宙世紀" eng="U.C.">0079</calendar>
   <director>富野由悠季</director>
 </gundam>
 <gundam media="TV">
   <name>機動戦士Zガンダム</name>
   <calendar jpn="宇宙世紀" eng="U.C.">0087</calendar>
   <director>富野由悠季</director>
 </gundam>
 <!--中略-->
 <gundam media="TV">
   <name>機動戦士ガンダム00 セカンドシーズン</name>
   <calendar jpn="西暦" eng="A.D.">2312</calendar>
   <director>水島精二</director>
 </gundam>
</gundamList>

使ってみるとXMLの処理にはもうLINQしかありえないという印象でした。 ただそうなるとDOMSAXを試験範囲にしているXMLマスタープロフェッショナル資格の形骸化が心配です。

XML文書をLINQで処理してみるサンプル

LINQ(Language INtegrated Query)は.NET Framework 3.5から登場した新しい構文で、XMLに限らずSQLや配列の要素を検索・集計する定番の処理をより端的に記述できるようにしたものです。

入力するXMLファイル

お題として次のXML文書(GundamList.xml)を使用しました。

GundamList.xml
<?xml version="1.0" encoding="Shift_JIS" ?>

<!DOCTYPE gundamList SYSTEM "GundamList.dtd">

<gundamList xmlns="urn:gundam:anime">
 <gundam media="TV">
     <name>機動戦士ガンダム</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0079</calendar>
     <director>富野由悠季</director>
 </gundam>
 <gundam media="TV">
     <name>機動戦士Zガンダム</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0087</calendar>
     <director>富野由悠季</director>
 </gundam>
 <gundam media="TV">
     <name>機動戦士ガンダムZZ</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0088</calendar>
     <director>富野由悠季</director>
 </gundam>
 <gundam media="MOVIE">
     <name>機動戦士ガンダム 逆襲のシャア</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0093</calendar>
     <director>富野由悠季</director>
 </gundam>
 <gundam media="OVA">
     <name>機動戦士ガンダム0080 ポケットの中の戦争</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0080</calendar>
     <director>高山文彦</director>
 </gundam>
 <gundam media="MOVIE">
     <name>機動戦士ガンダムF91</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0123</calendar>
     <director>富野由悠季</director>
 </gundam>
 <gundam media="OVA">
     <name>機動戦士ガンダム0083 STARDUST MEMORY</name>
     <calendar jpn="宇宙世紀" eng="U.C.">0083</calendar>
     <director>加瀬充子</director>
<director>今西隆志</director> </gundam> <gundam media="TV"> <name>機動戦士Vガンダム</name> <calendar jpn="宇宙世紀" eng="U.C.">0153</calendar> <director>富野由悠季</director> </gundam> <gundam media="TV"> <name>機動武闘伝Gガンダム</name> <calendar jpn="未来世紀" eng="F.C.">60</calendar> <director>今川泰宏</director> </gundam> <gundam media="TV"> <name>新機動戦記ガンダムW</name> <calendar jpn="アフターコロニー" eng="A.C.">195</calendar> <director>池田成</director> <director>高松信司</director> </gundam> <gundam media="TV"> <name>新機動戦記ガンダムX</name> <calendar jpn="アフターウォー" eng="A.W.">15</calendar> <director>高松信司</director> </gundam> <gundam media="OVA"> <name>機動戦士ガンダム 第08MS小隊</name> <calendar jpn="宇宙世紀" eng="U.C.">0079</calendar> <director>神田武幸</director> <director>飯田馬之介</director> </gundam> <gundam media="OVA"> <name>新機動戦記ガンダムW Endless Waltz</name> <calendar jpn="アフターコロニー" eng="A.C.">196</calendar> <director>青木康直</director> </gundam> <gundam media="OVA"> <name>機動戦士ガンダム 第08MS小隊 特別編 ラスト・リゾート</name> <calendar jpn="宇宙世紀" eng="U.C.">0079</calendar> <director>森邦宏</director> <director>仕舞屋鉄</director> </gundam> <gundam media="TV"> <name>∀ガンダム</name> <calendar jpn="正暦" eng="C.C.">2345</calendar> <director>富野由悠季</director> </gundam> <gundam media="TV"> <name>機動戦士ガンダムSEED</name> <calendar jpn="コズミック・イラ" eng="C.E.">71</calendar> <director>福田己津央</director> </gundam> <gundam media="TV"> <name>機動戦士ガンダムSEED DESTINY</name> <calendar jpn="コズミック・イラ" eng="C.E.">73</calendar> <director>福田己津央</director> </gundam> <gundam media="OVA"> <name>機動戦士ガンダムSEED C.E.73 STARGAZER</name> <calendar jpn="コズミック・イラ" eng="C.E.">73</calendar> <director>西澤晋</director> </gundam> <gundam media="TV"> <name>機動戦士ガンダム00 ファーストシーズン</name> <calendar jpn="西暦" eng="A.D.">2307</calendar> <director>水島精二</director> </gundam> <gundam media="TV"> <name>機動戦士ガンダム00 セカンドシーズン</name> <calendar jpn="西暦" eng="A.D.">2312</calendar> <director>水島精二</director> </gundam> </gundamList>

LINQ to XMLプログラム1の出力

最初に作成するLINQサンプルは「GundamList.xmlの中から高松信司監督のガンダム作品を抽出する」プログラムで、次のような出力結果を目指します。

cmd.exe
A.C.195  新機動戦記ガンダムW
A.W.15   新機動戦記ガンダムX
以上、2作品

LINQ to XMLプログラム1の実装

LINQではXML要素の表現にSystem.Xml.XmlElementでなくSystem.Xml.Linq.XElementを使用します。 一通りの型に対するExplicit変換演算子が用意されていて、XML要素の値をキャストで取得できるのが特徴です。

fromキーワードからセミコロンまでの5行がLINQのクエリで、その結果はIEnumerable<XElement>のオブジェクトです。 結果の型はselectするオブジェクトによって変わってしまうので、常にvarキーワードを使うのが好ましいでしょう。

GundamLinq1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace GundamLinq
{ class GundamLinq1
{ static void Main(string[] args) { // LINQ to XML用のオブジェクトを生成 XElement root = XElement.Load(@"..\..\GundamList.xml"); XNamespace ns = "urn:gundam:anime"; // 高松信司のガンダムを抽出するクエリ IEnumerable<XElement> gundams = from g in root.Elements(ns + "gundam") where ( from d in g.Elements(ns + "director") where "高松信司" == (string)d select d ).Any() select g; // 結果を出力 foreach (XElement g in gundams) { string name = (string)g.Element(ns + "name"); string year = (string)g.Element(ns + "calendar"); string eng = (string)g.Element(ns + "calendar").Attribute("eng"); Console.WriteLine("{0}{1,-4: } {2}", eng, year, name); } Console.WriteLine("以上、{0}作品", gundams.Count()); } } }

GundamLinq1.csでは複数あるdirector要素に対応するためLINQのクエリを二重にしてみました。 どう書くのが効率的なのかイマイチわかりません。

LINQ to XMLプログラム2の出力

次に作成するLINQサンプルは「GundamList.xmlの中から宇宙世紀(U.C.)のガンダムシリーズを抜き出して、作中の年表順にソートする」プログラムで、次のような出力結果を目指します。

cmd.exe
U.C.0079 機動戦士ガンダム
U.C.0079 機動戦士ガンダム 第08MS小隊
U.C.0079 機動戦士ガンダム 第08MS小隊 特別編 ラスト・リゾート
U.C.0080 機動戦士ガンダム0080 ポケットの中の戦争
U.C.0083 機動戦士ガンダム0083 STARDUST MEMORY
U.C.0087 機動戦士Zガンダム
U.C.0088 機動戦士ガンダムZZ
U.C.0093 機動戦士ガンダム 逆襲のシャア
U.C.0123 機動戦士ガンダムF91
U.C.0153 機動戦士Vガンダム
以上、10作品

LINQ to XMLプログラム2の実装

最初のサンプルでは出力処理のところに子要素を取得するコードを残していたため、垢抜けない感じになっていました。 そこで今度は匿名クラスを使って必要な値だけを抜き出してみました。 SQL的な言い方をすると射影でしょうか。

GundamLinq2.cs
using System;
using System.Linq;
using System.Xml.Linq;

namespace GundamLinq
{
    class GundamLinq2
    {
        static void Main(string[] args)
        {
            // LINQ to XML用のオブジェクトを生成
            XElement root = XElement.Load(@"..\..\GundamList.xml");
            XNamespace ns = "urn:gundam:anime";

            // 宇宙世紀のガンダムを抽出してソートするクエリ
            var query = from g in root.Elements(ns + "gundam")
                        let cal = g.Element(ns + "calendar")
                        where "U.C." == (string)cal.Attribute("eng")
                        orderby (string)cal
                        select new
                        {
                            name = (string)g.Element(ns + "name"),
                            year = (string)cal
                        };

            // 結果を出力
            foreach (var q in query)
            {
                Console.WriteLine("U.C.{0} {1}", q.year, q.name);
            }

            Console.WriteLine("以上、{0}作品", query.Count());
        }
    }
}

GundamLinq2.csではクエリ中にcalendar要素を3回も参照するため、letキーワードを使って一時変数に格納しています。 簡単に書けるからとXContainer.Element()メソッドを3回呼んでしまったら流石に非効率でしょう。

LINQを使う利点はorderbyキーワードでソート処理ができる点だと思います。 さらにgroup ~ by ~ into ~というキーワードでグループ化もできるようです。

意外な形で再評価された大番長の改造セーブデータ

地域制圧型SLGの3作目『大番長』。 大悪司と戦国ランスの下という評価が定着してしまった作品ですが、最近さらに下の作品が発売されたおかげでその評価を見直す動きが起きています。

大番長は学園編・県内編・全国編の3つに分かれているため周回プレイが煩わしいですけど、チュートリアル性が高く初心者に優しいとも言えるでしょう。 仲間同士の会話イベントが増えたことでキャラクターの魅力も増しました。 ただ同時に仲間にできないキャラが多く、キャラクリまで考えるとさらに組み合わせを制限されるため周回プレイが煩わしいですけど。

「こます」コマンドが無くなった替わりに毎月発生するヒロインとのHフェイズはもはや義務でしかなく、500BP欲しさにお嬢様を抱いてるときは虚しさすら覚えます。 でも回数を重ねることでバリエーションが増えてエロエロになっていく点は純愛厨でも楽しめるプチ調教ゲーと思えば評価できるのではないでしょうか。

そんな大番長には追加キャラデータも修正パッチもありません。


(σ・∀・)σ[daibanchou_ubichupas.zip]

「私は番長です、提督ではありません」

大きな帽子の女の子って可愛いですよね。 しかもデコ。 (*´Д`)ハァハァ  こんな神懸ったキャラデザなのに捕獲できなかったスカルサーペントの河野美潮を仲間に加えてみました。 当然ですが会話イベントの類はありません。

さらに学園編のキャラ選択に悩み疲れたので、全員を仲間にしてみました。 ウハウハでプレイしてたら資金難と信頼度低下に泣いた。 全国編の序盤は汎用闘賊団を尋問して凌ぎましょう。

Excel VBAエキスパートも取得してさらにMSオフィスに詳しくなる

MOS資格だけじゃ寂しいのでVBAエキスパートも取得してきました。 同じOdysseyの運営なので受験者IDはMOS試験で使ったものを再利用しましょう。 そこで重要なのが割引受験制度。 MOS資格を持っているとVBAエキスパートの受験料が1割引になります。 (・∀・)イイ!!

試験会場へ受験を申込むとき、申し込みフォームの備考欄などに「割引受験制度を利用したい」と記入しておけば対応してもらえます。

Excel VBAエキスパートはVBAの基礎知識を問う試験なので、Excel 2000 ~ 2010(Visual Basic for Applications 6.x ~ 7.0)までどれを使っていても変わりません。 また試験システムはExcel自体の操作を伴いませんので好きな環境で勉強できます。

バージョンに依存しない試験って話なんだけど、『VBA Professional Office 2003』が1つだけ宙に浮いてますね。 ナニコレ? そのうちバージョンアップするの? ( ゚Д゚)y─┛~~

Excel VBAエキスパート スタンダード スコアレポート

結果は867点(ボ-ダー700点)で合格。 記入問題がほとんどで、選択問題はUserForm関連だけでした。 しっかり勉強しておけばよかった。 (ノ∀`)アチャー  ブックとシートのイベント一覧を覚えておくと良いでしょう。

今回の教材は『VBAエキスパート公式テキスト』。 つかVBAエキスパートの対策本ってずっと新しいの出てないから実質これしかありません。 パソコン教室や職業訓練なんかでも必ずこの本を買わされるでしょう。 自分はちょうど新宿へ行く用事があったため紀伊国屋本店で購入しましたが、他の書店では売っていないので注意。

公式テキストと言うだけあって頭から読んでいけば理解できるようになっています。 ただこれだけだと不足に感じますね。 Excel VBAは逆引き辞典のようなものを眺めながら徐々に覚えていくものだと思うので、何で補うのが妥当なのかわかりませんけど。