XPathを使うとXmlDocumentでのXMLパーシングがよりシンプルになります。
XPathを使ったXmlDocumentの操作方法を紹介します。
従来のXMLをDOMでパージングする場合、ノードを一つづつたどる必要があります。
<root>
<node>
<sub-node>
<data type="text">データ</data>
<sub-node>
</node>
</root>
上記のXMLをパージングする場合、以下のコードになります。
ノードの階層をたどって取得したいノードにアクセスする必要があります。ノードの階層が多い場合、コードは量は多くなり、可読性も落ちます。
取得したいノードを直接、"/root/node/sub-node/data" のようにパスで指定できれば、非常にシンプルにノードにアクセスできます。XPathを利用すると、ノードへのアクセスがパス形式でシンプルに実装できます。
XmlDocument xmlDocument = new XmlDocument();
//XML読み込み
/*(何らかのXML読み込み処理)*/
//rootノードの取得
XmlElement elem = xmlDocument.DocumentElement;
//子ノードの確認
if (elem.HasChildNodes == true){
//子ノードの取得
XmlNode childNode = elem.FirstChild;
//孫ノードの確認
if (childNode.HasChildNodes == true){
//孫ノードの取得
XmlNode childNode2 = childNode.FirstChild;
//データノードの確認
if (childNode2.HasChildNodes == true) {
XmlNode dataNode = childNode2.ChildNodes[i];
//データの取得
string value = dataNode.Name;
}
}
}
XPathを用いる場合は、XmlDocumentクラスのSelectNodesメソッドを用います。SelectNodesメソッドの引数にXPath式を与えることでXPath式に一致するノードをまとめて選択できます。
private void button3_Click(object sender, EventArgs e)
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(textBox1.Text);
XmlNodeList nodeList = xmlDocument.SelectNodes("/root/node/data");
for (int i=0; i < nodeList.Count; i++){
textBox2.Text += "NodeType: " + nodeList[i].NodeType + "\r\n";
textBox2.Text += "Name: " + nodeList[i].Name + "\r\n";
textBox2.Text += "LocalName: " + nodeList[i].LocalName + "\r\n";
textBox2.Text += "Value: " + nodeList[i].Value + "\r\n";
textBox2.Text += "InnerText: " + nodeList[i].InnerText + "\r\n";
textBox2.Text += "\r\n";
if (nodeList[i].HasChildNodes == true){
for (int j=0; j < nodeList[i].ChildNodes.Count; j++) {
textBox2.Text += "NodeType: " + nodeList[i].ChildNodes[j].NodeType + "\r\n";
textBox2.Text += "Name: " + nodeList[i].ChildNodes[j].Name + "\r\n";
textBox2.Text += "LocalName: " + nodeList[i].ChildNodes[j].LocalName + "\r\n";
textBox2.Text += "Value: " + nodeList[i].ChildNodes[j].Value + "\r\n";
textBox2.Text += "InnerText: " + nodeList[i].ChildNodes[j].InnerText + "\r\n";
}
}
textBox2.Text += "\r\n";
}
}
XmlDocumentの宣言とインスタンスの作成をします。
XmlDocument xmlDocument = new XmlDocument();
Load()メソッドでXMLファイルを読み込みます。
xmlDocument.Load(textBox1.Text);
XPath書式を用いて複数ノードを選択します。
XmlNodeList nodeList = xmlDocument.SelectNodes("/root/node/data");
ループで選択されたノードの数だけループします。
for (int i=0; i<nodeList.Count; i++){
ノードの情報をtextBox2に出力します。
textBox2.Text += "NodeType: " + nodeList[i].NodeType + "\r\n";
textBox2.Text += "Name: " + nodeList[i].Name + "\r\n";
textBox2.Text += "LocalName: " + nodeList[i].LocalName + "\r\n";
textBox2.Text += "Value: " + nodeList[i].Value + "\r\n";
textBox2.Text += "InnerText: " + nodeList[i].InnerText + "\r\n";
textBox2.Text += "\r\n";
ノードに子ノードがあるか確認します。
if (nodeList[i].HasChildNodes == true){
子ノードがある場合は、子ノードの内容をtextBox2に表示します。
for (int j=0; j<nodeList[i].ChildNodes.Count; j++) {
textBox2.Text += "NodeType: " + nodeList[i].ChildNodes[j].NodeType + "\r\n";
textBox2.Text += "Name: " + nodeList[i].ChildNodes[j].Name + "\r\n";
textBox2.Text += "LocalName: " + nodeList[i].ChildNodes[j].LocalName + "\r\n";
textBox2.Text += "Value: " + nodeList[i].ChildNodes[j].Value + "\r\n";
textBox2.Text += "InnerText: " + nodeList[i].ChildNodes[j].InnerText + "\r\n";
}
<?xml version="1.0" encoding="UTF-8"?>
<root>
<node>
<data type="text">データ1です</data>
</node>
<node>
<data type="text">データ2です</data>
</node>
<node>
<data type="text">データ3です</data>
</node>
</root>
NodeType: Element
Name: data
LocalName: data
Value:
InnerText: データ1です
NodeType: Text
Name: #text
LocalName: #text
Value: データ1です
InnerText: データ1です
NodeType: Element
Name: data
LocalName: data
Value:
InnerText: データ2です
NodeType: Text
Name: #text
LocalName: #text
Value: データ2です
InnerText: データ2です
NodeType: Element
Name: data
LocalName: data
Value:
InnerText: データ3です
NodeType: Text
Name: #text
LocalName: #text
Value: データ3です
InnerText: データ3です
実行時にXPathのノードが取得できない場合があります。XMLでネームスペースが指定されている場合に動作しない現象が発生します。ネームスペースが指定されているXMLでXPathを利用してノードを取得するコードに関してはこちらの記事を参照してください。