連載:[完全版]究極のC#プログラミング

Chapter18 LINQ to XML

川俣 晶
2010/05/06

18.3 DOMの憂鬱

 ここで、とあるXML文書から、id属性がMという値を持つname属性(とある名前空間URIを持つ)の値を出力する例、リスト18.1を見てみよう。

 まず、DOMの基本機能のみを使用し、XPathのような別機能の力を借りないで書いてみよう(なお、GetElementsByTagNameメソッドの代わりにGetElementsByIdメソッドを使うという選択肢もあるが、ここでは使用していない)。

using System;
using System.Xml;

class Program
{
  private const string xmldoc =
@"<?xml version='1.0'?>
<names xmlns='http://www.piedey.co.jp/example/linqtoxml200811'>
  <name id='X'>Xenogears</name>
  <name id='M'>Mystic Quest</name>
  <name id='L'>LEGEND OF MANA</name>
</names>
";

  static void Main(string[] args)
  {
    var dom = new XmlDocument();
    dom.LoadXml(xmldoc);

    foreach (XmlElement node in dom.GetElementsByTagName("name",
      "http://www.piedey.co.jp/example/linqtoxml200811"))
    {
      if (node.Attributes["id"].Value == "M")
      {
        Console.WriteLine(node.InnerText);
      }
    }
    // 出力:Mystic Quest
  }
}
リスト18.1 XPathの力を借りないDOM

 このサンプルコードは、要求された処理内容に比して記述量が多すぎる傾向が見られる。量が増える理由は次のとおりである。

  • GetElementsByTagNameメソッドは、ごく基本的でよく使われるにもかかわらず、あまりに名前が長すぎる(20文字)
  • 名前が長いわりに、指定した名前と一致した要素を列挙する機能しか持たない
  • 要素の名前以外で絞り込むには、さらに別途if文が必要となる
  • その結果、求める要素は1つだけなのに、繰り返し処理が要求される

 従来、筆者がC#でのDOMプログラミングを「耐えがたい水準とまではいえない」と判断して継続して行ってきた理由は、XPath式を併用することでこれらの問題を緩和できるからである。

 GetElementsByTagNameメソッドの代わりに、XPathのSelectSingleNodeメソッドを使えば、上記の問題はほぼ解消される。SelectSingleNodeという名前も長いが、GetElementsByTagNameよりは短いし、読みやすく高機能なので許容範囲内である。

 これを使ってリスト18.1を書き直した例をリスト18.2に示す。

static void Main(string[] args)
{
  var dom = new XmlDocument();
  dom.LoadXml(xmldoc);

  var nsmgr = new XmlNamespaceManager(dom.NameTable);
  nsmgr.AddNamespace(
      "ex", "http://www.piedey.co.jp/example/linqtoxml200811");

  var node = dom.SelectSingleNode("//ex:name[@id='M']", nsmgr);
  if (node != null)
  {
    Console.WriteLine(node.InnerText);
  }
}
リスト18.2 XPathの力を借りたDOM(Mainメソッド以外はリスト18.1と同じ)

 しかし、このサンプルソースには別の憂鬱が入り込んできている。

 XPath式で名前空間URIを持つ値の検索を行うには、XmlNamespaceManagerオブジェクトを作成しなければならないのである。しかも、このオブジェクトには厄介な点がいくつもある。

  • XmlNamespaceManagerは名前が長すぎる。GetElementsByTagNameメソッドの20文字に匹敵する19文字。従来は「var nsmgr」を「XmlNamespaceManager nsmgr」と記述する必要があったが、varキーワードが導入されて少しマシになっている。しかし、それでも長い
  • XmlNamespaceManagerオブジェクトのコンストラクタに指定したDOMドキュメントのNameTableと、実際に使用するDOMドキュメントの対応関係は、プログラマーが注意して維持しなければならない。食い違ってもコンパイラは教えてくれない
  • AddNamespaceメソッドで追加した名前空間接頭辞(ここではex)と、XPath式の中に書き込んだ名前空間接頭辞が正しく同じであるよう、プログラマー自身が注意深く維持しなければならない。食い違ってもコンパイラは教えてくれない

 つまり、確かにSelectSingleNodeメソッドやSelectNodesメソッドのおかげでなんとかDOMは使える水準にまで達してくれたわけではあるが、それでも名前空間が絡むと憂鬱なものになってしまったのである。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter18 LINQ to XML
    1.18.1 LINQプロバイダーを導入する別の理由
    2.18.2 XML最大の災厄
  3.18.3 DOMの憂鬱
    4.18.4 E4XのXMLサポート
    5.18.5 LINQ to XMLというブレークスルー
    6.18.6 単純化されたXML文書生成
    7.18.7 まとめ―ストレスレスなXMLの扱い/練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間