ノード作成時のXmlDocument.CreateElementが面倒
XMLファイルをXmlDocumentで作成する場合、testAノードの下にtestBノードを作成したい時に、testA.AppendChild(testB)としたいのに、毎回XmlDocument.CreateElement(新しいノード)をする必要があるため、より直感的にAppendできように簡単なラッパークラスを考えてみました。
環境
IDE:VisualStudio2019
アプリケーション:コンソールアプリ
フレームワーク:.NET Core 3.1
XmlDocumentを持ちまわる
XmlElementをラップし、さらにXmlDocumentを持ちまわって、Append時にそのXmlDocumentでCreateElementさせます。
usingSystem.Xml;namespaceTestProject{/// <summary>/// XmlDocument拡張クラス/// </summary>publicclassXmlDocumentExtension:XmlDocument{/// <summary>/// ルート要素を作成/// ※既存の子ノードはすべて削除します/// </summary>/// <param name="el">要素</param>/// <param name="version">バージョン</param>/// <param name="encoding">エンコーディング</param>/// <param name="standalone">外部依存</param>/// <returns>XmlElementWrapper</returns>publicXmlElementWrapperCreateRootOfElementWrapper(stringel,stringversion="1.0",stringencoding="utf-8",stringstandalone=null){this.RemoveAll();this.AppendChild(this.CreateXmlDeclaration(version,encoding,standalone));varcreateEl=this.CreateElement(el);returnnewXmlElementWrapper(this.AppendChild(createEl));}}/// <summary>/// XmlElementラッパークラス/// </summary>publicclassXmlElementWrapper{/// <summary>/// XmlElement/// </summary>privateXmlElement_el;/// <summary>/// XmlDocument/// </summary>privateXmlDocument_doc;/// <summary>/// コンストラクタ/// </summary>/// <param name="node">XmlNode</param>publicXmlElementWrapper(XmlNodenode){// 自身のXmlElementを保持this._el=nodeasXmlElement;// XmlDocumentを保持this._doc=this._el.OwnerDocument;}/// <summary>/// 子要素を追加/// </summary>/// <param name="el">要素</param>/// <returns>追加した子要素</returns>publicXmlElementWrapperAppendChild(stringel){varaddEl=this._el.AppendChild(this._doc.CreateElement(el));returnnewXmlElementWrapper(addEl);}}}AppendChildで追加した子要素を新たにXmlElementWrapperでラップすることで、後続のエレメントでもAppendが楽になります。
※AppendChildの引数はstringですがXmlNode版もあるといいのかもしれません。
また、最初のrootエレメントを起点とすることにしたため、XmlDocumentの拡張クラスを用意しています。
このクラスの使用イメージは以下です。
usingSystem;usingSystem.IO;usingTestProject.Extension;namespaceTestProject{/// <summary>/// メインクラス/// </summary>publicclassProgram{/// <summary>/// メインエントリ/// </summary>/// <param name="args">実行時引数</param>publicstaticvoidMain(string[]args){// XmlDocument拡張クラスvardoc=newXmlDocumentExtension();// root要素作成varroot=doc.CreateRootOfElementWrapper("root");// rootの直下にtestAを作成vartestA=root.AppendChild("testA");// testAの下にtestBを作成vartestB=testA.AppendChild("testB");// xml保存doc.Save(Path.Combine(Environment.CurrentDirectory,"test.xml"));}}}以下のxmlが作成されます。
<?xml version="1.0" encoding="utf-8"?><root><testA><testB/></testA></root>必要なメソッドを実装していく
値設定/値取得や、XPath、属性設定等 必要に応じてメソッドを用意し、ラップしたXElementの各処理を実装します。
/// <summary>/// 値を設定/// </summary>/// <param name="value">値</param>publicvoidSetValue(stringvalue){this._el.InnerText=value;}/// <summary>/// 値を取得/// </summary>/// <returns>値</returns>publicstringGetValue(){returnthis._el.InnerText;}/// <summary>/// 要素検索/// </summary>/// <param name="xPath">XPath</param>/// <returns>XmlElementWrapper</returns>publicXmlElementWrapperSelectSingleNode(stringxPath){varnode=this._el.SelectSingleNode(xPath);returnnode==null?null:newXmlElementWrapper(node);}全文サンプル
usingSystem.Xml;namespaceTestProject.Extension{/// <summary>/// XmlDocument拡張クラス/// </summary>publicclassXmlDocumentExtension:XmlDocument{/// <summary>/// ルート要素を作成/// ※既存の子ノードはすべて削除します/// </summary>/// <param name="el">要素</param>/// <param name="version">バージョン</param>/// <param name="encoding">エンコーディング</param>/// <param name="standalone">外部依存</param>/// <returns>XmlElementWrapper</returns>publicXmlElementWrapperCreateRootOfElementWrapper(stringel,stringversion="1.0",stringencoding="utf-8",stringstandalone=null){this.RemoveAll();this.AppendChild(this.CreateXmlDeclaration(version,encoding,standalone));varcreateEl=this.CreateElement(el);returnnewXmlElementWrapper(this.AppendChild(createEl));}}/// <summary>/// XmlElementラッパークラス/// </summary>publicclassXmlElementWrapper{/// <summary>/// XmlElement/// </summary>privateXmlElement_el;/// <summary>/// XmlDocument/// </summary>privateXmlDocument_doc;/// <summary>/// タグ名/// </summary>publicstringName=>this._el.Name;/// <summary>/// コンストラクタ/// </summary>/// <param name="node">XmlNode</param>publicXmlElementWrapper(XmlNodenode){this._el=nodeasXmlElement;this._doc=this._el.OwnerDocument;}/// <summary>/// 子要素を追加/// </summary>/// <param name="el">要素</param>/// <returns>追加した子要素</returns>publicXmlElementWrapperAppendChild(stringel){varaddEl=this._el.AppendChild(this._doc.CreateElement(el));returnnewXmlElementWrapper(addEl);}/// <summary>/// 値を設定/// </summary>/// <param name="value">値</param>publicvoidSetValue(stringvalue){this._el.InnerText=value;}/// <summary>/// 値を取得/// </summary>/// <returns>値</returns>publicstringGetValue(){returnthis._el.InnerText;}/// <summary>/// 属性を設定/// </summary>/// <param name="attrName">属性名</param>/// <param name="value">属性値</param>publicvoidSetAttribute(stringattrName,stringattrValue){this._el.SetAttribute(attrName,attrValue);}/// <summary>/// 属性を取得/// </summary>/// <param name="attrName">属性名</param>/// <returns>属性値</returns>publicstringGetAttribute(stringattrName){returnthis._el.GetAttribute(attrName);}/// <summary>/// 要素検索/// </summary>/// <param name="xPath">XPath</param>/// <returns>XmlElementWrapper</returns>publicXmlElementWrapperSelectSingleNode(stringxPath){varnode=this._el.SelectSingleNode(xPath);returnnode==null?null:newXmlElementWrapper(node);}}}usingSystem;usingSystem.IO;usingTestProject.Extension;namespaceTestProject{/// <summary>/// メインクラス/// </summary>publicclassProgram{/// <summary>/// メインエントリ/// </summary>/// <param name="args">実行時引数</param>publicstaticvoidMain(string[]args){try{// XmlDocument拡張クラスvardoc=newXmlDocumentExtension();// root要素作成varroot=doc.CreateRootOfElementWrapper("root");// rootの直下にtestAを作成vartestA=root.AppendChild("testA");// testAの下にtestBを作成vartestB=testA.AppendChild("testB");// testBの下に同じタグを追加vartestTag1=testB.AppendChild("testTag");vartestTag2=testB.AppendChild("testTag");// 値設定varvalue1="valueTag1";varvalue2="valueTag2";testTag1.SetValue(value1);testTag2.SetValue(value2);// 属性設定testTag1.SetAttribute("testAttr","testAttrValue");// XPath(あえてrootから)varfindEl=root.SelectSingleNode($"//testB/testTag[text()='{value1}']");Console.WriteLine("SelectSingleNode結果 XMLタグ名:"+findEl.Name);Console.WriteLine("属性testAttr:"+findEl.GetAttribute("testAttr"));// xml保存doc.Save(Path.Combine(Environment.CurrentDirectory,"test.xml"));}catch(Exceptionerr){Console.WriteLine(err.Message);}finally{Console.Read();}}}}<?xml version="1.0" encoding="utf-8"?><root><testA><testB><testTagtestAttr="testAttrValue">valueTag1</testTag><testTag>valueTag2</testTag></testB></testA></root>おわりに
ラップせずともXmlElementを継承して実現できるのであれば、各メソッドやプロパティを実装しなくてよいのですが・・・
アドバイス等ありましたら、いただけると幸いです。
