こんがりめも🍞

ちょっとした伝えたいことや備忘録を🍞

【C#でXMLファイルの読み込み】指定した属性のノードから別の属性の値を取得する方法 おまけでSelectNodes利用時にXMLの名前空間でつまずいた話

f:id:kongarimemo:20190517140315p:plain

指定した属性のノードから別の属性の値を取得する方法(良い言い方がわからん!)・・・
と言っても分かり辛いと思うので具体的に

<setting id="week1" value="月曜" />

こんなノードがあるXMLファイルで、「week1」を指定したら「月曜」を取得するようなサンプルコードがあまりなかったのでメモします。

また、タイトルにあるようにXML名前空間でちょっとつまずいたのでその話も。

指定した属性のノードから別の属性の値を取得する方法

下記のようなXMLファイルから、「week1」を指定したら「月曜」を取得したい

Setting.xml

<?xml version="1.0"?>
<settings>
  <setting id="week1" value="月曜" />
  <setting id="week2" value="火曜" />
  <setting id="week3" value="水曜" />
  <setting id="week4" value="木曜" />
  <setting id="week5" value="金曜" />
  <setting id="week6" value="土曜" />
  <setting id="week7" value="日曜" />
</settings>

名前空間を指定(以降、説明省略)

using System.Xml;

csコードの上の所に追加

SelectNodesを使うサンプルコード(おすすめ)

中にコメントで説明

// XMLファイルパスを指定
string xmlPath = @"C:\Work\Setting.xml";

// XmlDocumentオブジェクトのインスタンスを生成
XmlDocument doc = new XmlDocument();

// 指定したファイルパスからXMLドキュメントを読み込み
doc.Load(xmlPath);

// 属性idが「week1」のノードリストの取得
XmlNodeList nodes = doc.SelectNodes("//setting[@id='week1']");

// 取得したノードリストの一つ目の属性valueの値を取得
// ※idが一意であるXMLファイルのためこのように取得しています。
string value = nodes[0].Attributes["value"].Value;

// 取得した属性valueの値を表示
// ※この場合「月曜」と表示されます。
Console.WriteLine(value);

エラー処理はいれてません。
もっと良い書き方があったら教えてほしい・・・

GetElementsByTagNameを使うサンプルコード

おすすめじゃないけど、GetElementsByTagNameを使った別のコードも書いたので載せて置きます。
こっちの方がやりたいことに近い方もいるかもしれないですからね。

// XMLファイルパスを指定
string xmlPath = @"C:\Work\Setting.xml";

// XmlDocumentオブジェクトのインスタンスを生成
XmlDocument doc = new XmlDocument();

// 指定したファイルパスからXMLドキュメントを読み込み
doc.Load(xmlPath);

// 指定したタグ名のノードリストを取得
XmlNodeList nodes = doc.GetElementsByTagName("setting");

// 取得したノードリストをループ処理する
string value = string.Empty;
foreach (XmlNode node in nodes)
{
    if (node.Attributes["id"].Value == "week1")
    {
        // 属性idが「week1」のノードがあれば、属性valueの値を取得
        value = node.Attributes["value"].Value;

        // 取得したら繰り返す必要がないため、ループ処理を抜ける
        // ※idが一意であるXMLファイルのためこのようにしています。
        break;
    }
}

// 取得した属性valueの値を表示
// ※この場合「月曜」と表示されます
Console.WriteLine(value);

SelectNodesを使用する場合に、XMLファイルに名前空間があると呼び出し方が違う

下記のように、名前空間が指定されているXMLファイル(下記XMLファイルだと「xmlns="http://sample.hoge/hoge/settings"」の部分)だと、SelectNodesの引数の書き方が変わる事がわからず、少しつまずいたのでメモ。

<?xml version="1.0"?>
<settings xmlns="http://sample.hoge/hoge/settings">
  <setting id="week1" value="月曜" />
  <setting id="week2" value="火曜" />
  <setting id="week3" value="水曜" />
  <setting id="week4" value="木曜" />
  <setting id="week5" value="金曜" />
  <setting id="week6" value="土曜" />
  <setting id="week7" value="日曜" />
</settings>

XMLファイルに名前空間がある時のサンプルコード

中にコメントで説明

// XMLファイルパスを指定
string xmlPath = @"C:\Work\Setting_ns.xml";

// XmlDocumentオブジェクトのインスタンスを生成
XmlDocument doc = new XmlDocument();

// 指定したファイルパスからXMLドキュメントを読み込み
doc.Load(xmlPath);

// 名前空間の設定
// 下記記述では「ns:」と書いたら名前空間"http://sample.hoge/hoge/settings"を指すようにしています
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ns", "http://sample.hoge/hoge/settings");

// 属性idが「week1」のノードリストの取得
// ※本来 SelectNodes("//setting[@id='week1']") でidが"week1"のノードリストが取得可能ですが、
//  名前空間があるXMLのため「ns:」を付けて名前空間を指定し取得します。
//  後ろに「, nsmgr」を書き忘れないようにしましょう。
XmlNodeList nodes = doc.SelectNodes("//ns:setting[@id='week1']", nsmgr);

// 取得したノードリストの一つ目の属性valueの値を取得
// ※idが一意であるXMLファイルのためこのように取得しています。
string value = nodes[0].Attributes["value"].Value;

// 取得した属性valueの値を表示
// ※この場合「月曜」と表示されます。
Console.WriteLine(value);

引数がXPathの場合、他も同様みたいですね。

XPath 式にプレフィックスが含まれていない場合、名前空間 URI が空の名前空間であると見なされます。 引き続き使用する必要がある、XML には、既定の名前空間が含まれている場合、XmlNamespaceManagerプレフィックス名前空間 URI を追加してあり、それ以外の場合、選択されたノードをすべて表示されません。 詳細については、次を参照してください。 XPath ナビゲーションを使用してノードを選択します。

引用元:
https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlnode.selectnodes?view=netframework-4.8