C-Sharp/XML


XML構造(ノード)からXML構造(ノード)を削除する

とあるXML構造があり
<books>
  <book>
    <title>book1</title>
    <price>100</price>
  </book>
  <book>
    <title>book2</title>
    <price>200</price>
  </book>
</books>

ここからこのノードを削除して
<book>
  <title>book1</title>
  <price>100</price>
</book>

こうしたい
<books>
  <book>
    <title>book2</title>
    <price>200</price>
  </book>
</books>

System.Xml.XmlDocumentにRemoveChildとかいうメソッドとSelectSingleNodeとかいうメソッドがあるのでとりあえずコードを書いてみる
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(
    "<books>" +
    "    <book>" +
    "        <title>book1</title>" +
    "        <price>100</price>" +
    "    </book>" +
    "    <book>" +
    "        <title>book2</title>" +
    "        <price>200</price>" +
    "    </book>" +
    "</books>"
);

doc.RemoveChild(doc.SelectSingleNode("/books/book"));
MessageBox.Show(doc.OuterXml);
実行するとSystem.ArgumentExceptionなる例外が発生し、内容は「削除するノードはこのノードの子ではありません。」だそうだ。

よく分からんので公式ドキュメント通りやってみる。(XMLの定義部分は割愛)
System.Xml.XmlNode root = doc.DocumentElement;
root.RemoveChild(root.FirstChild);
MessageBox.Show(doc.OuterXml);
できた。
ポイントはDocumentElementか?

もう一回今度はDocumentElement使ってやってみる。
doc.DocumentElement.RemoveChild(doc.DocumentElement.SelectSingleNode("/books/book"));
MessageBox.Show(doc.OuterXml);
できた!
ポイントはDocumentElementだったか!

じゃあ今度は最初のtitleだけ抜くとかできるのかな。
doc.DocumentElement.RemoveChild(doc.DocumentElement.SelectSingleNode("/books/book/title"));
MessageBox.Show(doc.OuterXml);
削 除 す る ノ ー ド は こ の ノ ー ド の 子 で は あ り ま せ ん 。

え・・・なんでだ・・・
まさか、子は削除できるけど孫は削除できないってことか?
じゃあ最初のやつはもしかして・・・
doc.RemoveChild(doc.SelectSingleNode("/books"));
MessageBox.Show(doc.OuterXml);
これで例外が出ないということはDocumentElementは必須ということではなく、単にちゃんと子要素にフォーカスするということか。

ということは最初のtitleだけ削除したい場合はちゃんと一つ上のノードから消す必要があると。
doc["books"]["book"].RemoveChild(doc.SelectSingleNode("/books/book/title"));
MessageBox.Show(doc.OuterXml);
これも正常。やっと分かってきた。

あとはSelectSingleNodeでXPath使えばいろいろできそう。

これでbook2が削除される。
doc["books"].RemoveChild(doc.SelectSingleNode("/books/book[last()]"));
MessageBox.Show(doc.OuterXml);

これもbook2が削除される。
doc["books"].RemoveChild(doc.SelectSingleNode("/books/book[title = 'book2']"));
MessageBox.Show(doc.OuterXml);

親の["books"]決め打ちをやめて子に合わせる形にする。
System.Xml.XmlNode node = doc.SelectSingleNode("/books/book[title = 'book2']");
node.ParentNode.RemoveChild(node);
MessageBox.Show(doc.OuterXml);

理解しました。

XML構造(ノード)内に別のXML構造(ノード)を追加する

とあるXML構造があり
<books>
  <book>
    <title>book1</title>
    <price>100</price>
  </book>
  <book>
    <title>book2</title>
    <price>200</price>
  </book>
</books>

これにこのノードを足して
<book>
  <title>book3</title>
  <price>300</price>
</book>

こうしたい
<books>
  <book>
    <title>book1</title>
    <price>100</price>
  </book>
  <book>
    <title>book2</title>
    <price>200</price>
  </book>
  <book>
    <title>book3</title>
    <price>300</price>
  </book>
</books>

System.Xml.XmlDocumentにAppendChildとかいうメソッドがあるのでとりあえずコードを書いてみる
System.Xml.XmlDocument doc1 = new System.Xml.XmlDocument();
doc1.LoadXml(
    "<books>" +
    "    <book>" +
    "        <title>book1</title>" +
    "        <price>100</price>" +
    "    </book>" +
    "    <book>" +
    "        <title>book2</title>" +
    "        <price>200</price>" +
    "    </book>" +
    "</books>"
);

System.Xml.XmlDocument doc2 = new System.Xml.XmlDocument();
doc2.LoadXml(
    "<book>" +
    "    <title>book3</title>" +
    "    <price>300</price>" +
    "</book>"
);

doc1["books"].AppendChild(doc2.DocumentElement);
MessageBox.Show(doc1.DocumentElement.OuterXml);
実行するとSystem.ArgumentExceptionなる例外が発生し、内容は「挿入するノードは、異なるドキュメント コンテキストのものです。」だそうだ。

調べてみたところ、どうやら異なるXMLドキュメントオブジェクトの情報を利用するにはまずインポートが必要なようだ。
なので、インポートする処理を追加してみる。
更にインポートしただけではだめなので、インポートしたノードをAppendChildするように処理を変更する。
System.Xml.XmlDocument doc1 = new System.Xml.XmlDocument();
doc1.LoadXml(
    "<books>" +
    "    <book>" +
    "        <title>book1</title>" +
    "        <price>100</price>" +
    "    </book>" +
    "    <book>" +
    "        <title>book2</title>" +
    "        <price>200</price>" +
    "    </book>" +
    "</books>"
);

System.Xml.XmlDocument doc2 = new System.Xml.XmlDocument();
doc2.LoadXml(
    "<book>" +
    "    <title>book3</title>" +
    "    <price>300</price>" +
    "</book>"
);

// この行を追加
// doc1にdoc2のエレメントをインポートする
// 返り値はdoc1にインポートしたエレメントそのもの
System.Xml.XmlNode node = doc1.ImportNode(doc2.DocumentElement, true);

// 更にこの行は変更
// doc1のbooksに対し、インポートしたノードをぶら下げる
//doc1["books"].AppendChild(doc2.DocumentElement);
doc1["books"].AppendChild(node);

MessageBox.Show(doc1.DocumentElement.OuterXml);
無事追加されました。

  • 最終更新:2016-01-28 10:14:27

このWIKIを編集するにはパスワード入力が必要です

認証パスワード