Top > Programming > .NetFramework > LINQ > LinqAndXmlNamespace
Last-modified: Tue, 11 Jun 2013 01:56:13 JST
Counter:4959 Today:1 Yesterday:3 Online:12
このエントリーをはてなブックマークに追加

LINQで名前空間がついたXMLをあつかう場合の注意

About

LINQはXML(Database/データベース)も操作することができます。XElementクラスを利用することでXMLをファイルから読み取ったり、対象のノード(子/要素)を走査することができますが、名前空間がついたXMLの場合、ノードなどを取得する際に特別な手続きが必要になります。手続きを行わない場合、"取得できるはずのノードが取得できない"などの不具合が起きます。ここでは名前空間付きXMLからノードを取得できない状況の例をあげて、その解決方法について解説します。

HowTo

解説するにあたり、次のようなXMLファイルを用意しました。名前空間"SampleNamespace"が与えられる点に注意してください。

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="SampleNamespace">
  <Items>
    <Item>
      <Name>SampleA</Name>
      <Value>10</Value>
    </Item>
    <Item>
      <Name>SampleB</Name>
      <Price>20</Price>
    </Item>
  </Items>
</root>

名前空間が与えられない場合、"XElement.Elementsメソッド"や"XElement.Descendantsメソッド"を利用することでノードを取得することができます。しかしながら、引数に対象のノード名だけを与えても、取得できないことを確認します。これは対象のXMLが名前空間を持っていることに起因する問題です。またここではメソッドによるノードの取得を例にしていますが、LINQ特有のクエリ文を記述しても同様の問題が発生します。

この問題を解決するには名前空間を指定します。名前空間は"XNamespaceクラス"によって定義します。もしも対象のノード以下のノードがすべて同じ名前空間に属することが分かっている場合には、"XElement.Name.Namespace"によって、現在対象としているノードの名前空間を取得し、そのノードから子ノードを取得する際に、利用します。

名前空間の指定は文字列(string)の操作に似ています。引数を"Xnamespace + 対象ノードの名前"として与えることで、名前空間を指定した走査が行われるようになります。

        static void Main(string[] args)
        {
            string xmldata = "../../sample.xml";
            XElement root = XElement.Load(xmldata);
            XNamespace nspace = root.Name.Namespace;

            //名前空間を指定しない場合、取得できていないことを確認する
            //IEnumerable<XElement> items = root.Elements("Items");
            //IEnumerable<XElement> item = root.Descendants("Item");

            //名前空間を指定しなければ取得できない
            IEnumerable<XElement> items = root.Elements(nspace + "Items");
            IEnumerable<XElement> item = root.Descendants(nspace + "Item");

            Console.WriteLine("items : " + items.Count());
            Console.WriteLine("item : " + item.Count());

            Console.ReadLine();

        }
    }

引数に与えた対象とするノードが、その親ノードの名前空間に属することが保障されないため、の仕様だと思われます。