目次
Linq
の使える XDocument
の方が便利らしいけどとりあえず XmlDocument
を覚えた。
XMLの読み込み操作
※いろいろと飛び交う可能性のある様々な例外を以下のコードでは処理してない
// XmlDocumentにXMLファイルを読み込む
string xmlFilepath = @"XMLファイルの場所";
XmlDocument xml = new XmlDocument();
xml.Load(xmlFilepath);
// XPathにマッチするノードを取り出す
string xpath01 = @"//hoge/piyo";
XmlNodeList nodes = xml.SelectNodes(xpath01);
foreach (XmlNode node in nodes)
{
// XPathにマッチする単一のノードを取り出す
string xpath02 = @"foo/bar";
XmlNode aNode = node.SelectSingleNode(xpath02);
// XMLの内容をテキストで取得
string a = aNode.InnerText; // テキストノードのみ
string b = aNode.InnerXml; // XML要素も含めたテキスト
string c = aNode.OuterXml; // 自分自身の要素も含めたテキスト
}
XmlDocument#Load
はいろんな例外投げるので注意。
XPath
の構文がおかしい場合は XmlNode#SelectNodes
で XPathException
が発生する。
もう少し丁寧に読み込む場合
InnerText
プロパティは XmlNode
の全ての ChildNode
のテキストノードを結合した文字列を返す。
もう少し丁寧に値を取り出したい場合は、NodeType
プロパティで XmlNodeType
を確認して、Value
プロパティでデータを取得する。
XmlDocument xml = new XmlDocument();
// 文字列を読み込む
xml.LoadXml(
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<R>
<A attr=""XYZ"">Text</A>
<B><![CDATA[<"">]]>ccc</B>
<C></C>
</R>"
);
Debug.WriteLine(xml.FirstChild.OuterXml); // <?xml version="1.0" encoding="utf-8" ?>
Debug.WriteLine(xml.FirstChild.InnerXml); // (空文字)
Debug.WriteLine(xml.LastChild.InnerText); // Text<">ccc
XmlElement a = xml.LastChild.FirstChild as XmlElement;
Debug.WriteLine(a.NodeType == XmlNodeType.Element); // True
Debug.WriteLine(a.OuterXml); // <A attr="XYZ">Text</A>
Debug.WriteLine(a.ChildNodes.Count); // 1
Debug.WriteLine(a.SelectSingleNode("@attr").Value); // XYZ
Debug.WriteLine(a.SelectSingleNode("@attr").NodeType == XmlNodeType.Attribute); // True
Debug.WriteLine(a.Attributes[0].Value); // XYZ
Debug.WriteLine(a.Attributes[0].Name); // attr
Debug.WriteLine(a.FirstChild.Value); // Text
Debug.WriteLine(a.LastChild.Value); // Text : 属性は ChildNodes に含まれず、 Attributes に含まれる
Debug.WriteLine(a.FirstChild.NodeType == XmlNodeType.Text);// True
XmlElement b = xml.LastChild["B"];
Debug.WriteLine(b.OuterXml); // <B><![CDATA[<">]]></B>
Debug.WriteLine(b.ChildNodes.Count); // 1
Debug.WriteLine(b.FirstChild.NodeType == XmlNodeType.CDATA); // TRUE
Debug.WriteLine(b.FirstChild.Value); // <">
Debug.WriteLine(b.LastChild.NodeType == XmlNodeType.Text); // TRUE
Debug.WriteLine(b.LastChild.Value); // ccc
XmlElement c = xml.LastChild["C"];
Debug.WriteLine(c.ChildNodes.Count); // 0;
※XmlDocument#LoadXml
は 不正なXML文字列を渡すと XmlException
を投げる
XMLの作成操作
XmlDocument xml = new XmlDocument();
// XML宣言の生成
XmlDeclaration declaration
= xml.CreateXmlDeclaration(@"1.0", @"utf-8", null);
// ルートノードの生成
XmlElement root = xml.CreateElement("Hoge");
// 子ノードの生成
XmlElement child = xml.CreateElement("Piyo");
// 子ノードにテキストをセット
child.InnerText = @"FOO<&>BAR"; // <>& は自動的にエスケープされる
// 組み立てて返す
root.AppendChild(child);
xml.AppendChild(declaration);
xml.AppendChild(root);
// 出力してみる
Console.WriteLine(xml.InnerXml);
結果
<?xml version="1.0" encoding="utf-8"?><Hoge><Piyo>FOO<&>BAR</Piyo></Hoge>
という文字列が表示される
※XmlElement#CreateElement
で XML要素名 として利用できない文字列を指定すると XmlException
が飛ぶので注意すること! XML要素名が正しいかどうかをチェックする場合は XmlConvert.VerifyName
メソッドを利用する。
XmlDocument#Load
例外投げすぎワロタ
どんだけ色んな種類の例外投げれば気が済むの…
[TestClass]
public class CreateAndLoadXmlDocumentTest
{
XmlDocument CreateAndLoadXmlDocument(string filePath, Action<Exception> errorHandler)
{
XmlDocument xml = new XmlDocument();
try
{
xml.Load(filePath);
error = null;
return xml;
}
catch (Exception ex)
{
if (ex is XmlException ||
ex is ArgumentException ||
ex is FileNotFoundException ||
ex is DirectoryNotFoundException ||
ex is PathTooLongException ||
ex is UnauthorizedAccessException ||
ex is SecurityException)
{
errorHandler(ex);
return null;
}
else
{
throw;
}
}
}
[TestMethod]
public void CreateAndLoadXmlDocument_正常()
{
string path = GetExecutingPath("valid.xml");
if(!File.Exists(path))
{
Assert.Inconclusive("ValidなXMLを用意して読み込んでください");
}
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNotNull(actual);
Assert.IsNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_不正なXML()
{
string path = GetExecutingPath("invalid.xml");
if (!File.Exists(path))
{
Assert.Inconclusive("InvalidなXMLを用意して読み込んでください");
}
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_不正な引数()
{
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(null, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_ファイルが存在しない()
{
string temp = Path.GetTempPath();
string path = Path.Combine(temp, "存在しない.xml");
if (File.Exists(path)) Assert.Inconclusive("存在しないファイルパスを指定してください");
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_ディレクトリが存在しない()
{
string path = @"C:/存/在/し/な/い/デ/ィ/レ/ク/ト/リ";
if (Directory.Exists(path)) Assert.Inconclusive("存在しないディレクトリパスを指定してください");
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_長すぎるパス()
{
StringBuilder pathBuilder = new StringBuilder(@"c:\長すぎるパス");
for(int i = 0; i < 1000; i++) pathBuilder.Append("x");
string path = Path.Combine(pathBuilder.ToString(), "test.xml");
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_許可されないパス()
{
string path = null;
if (path == null) Assert.Inconclusive("UnauthorizedAccessExceptionが発生するパスを指定してください");
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
[TestMethod]
public void CreateAndLoadXmlDocument_アクセスを禁止されたパス()
{
string path = null;
if (path == null) Assert.Inconclusive("SecurityExceptionが発生するパスを指定してください");
string actualError = null;
var actual = GetTarget().CreateAndLoadXmlDocument(path, out actualError);
Assert.IsNull(actual);
Assert.IsNotNull(actualError);
}
public CreateAndLoadXmlDocumentTest GetTarget()
{
return new CreateAndLoadXmlDocumentTest();
}
public string GetExecutingPath(string fileName)
{
string location = System.Reflection.Assembly.GetExecutingAssembly().Location;
return Path.Combine(Path.GetDirectoryName(location), fileName);
}
}