C# で XML ファイルを作成するときの比較(XmlDocument, XDocument, ExDoc)

「ツイートキャッチ★★★」で xml 形式でファイルに出力するために、ExDoc を拡張している途中です。ExDoc の主旨として「ユーザーインターフェースを優先する」という項目があるので(勝手に自分で付けたw)、ユーザーから使いやすいコーディングの仕方に合わせて拡張していきます。ユーザーってのは、「コーディングをするプログラマ」ってことですね、新しい UIDD(User Interface Developement Driven)の一環です(というのも、勝手に自分で付けたw)

と前置きはそれくらいにして、コードを晒しておきます。
TwiCatchStar の内部データを直接 xml に書き出します。

■XmlDocument を使う場合

通常の XmlDocument を使う場合です。まあ、旧来の DOM インターフェースを知っていれば作れるので、java などの他言語から入った人にはいいのでしょうが、結構手間です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// XmlDocument を使う場合
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("TwiCatchStar");
root.SetAttribute("version", APPVERSION);
root.SetAttribute("created_at", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
doc.AppendChild(root);
XmlElement user = doc.CreateElement("user");
root.AppendChild(user);
user.AppendChild(doc.CreateElement("screen_name")).InnerText= username;
user.AppendChild(doc.CreateElement("profile_image_url")).InnerText= profile_image_url;
XmlElement statuses = doc.CreateElement("statuses");
statuses.SetAttribute("type", "array");
root.AppendChild(statuses);
foreach (Tweet twi in items)
{
    XmlElement status = doc.CreateElement("status");
    statuses.AppendChild(status);
    status.AppendChild(doc.CreateElement("id")).InnerText= twi.ID;
    status.AppendChild(doc.CreateElement("text")).InnerText= twi.text;
    status.AppendChild(doc.CreateElement("created_at")).InnerText= twi.CreatedAt.ToString("yyyy/MM/dd HH:mm:ss");
}

■LINQ to XML を使う場合

今後、.NET 言語でデータストレージ絡み(XML形式も含む)のは、一括して LINQ が推奨、ってことになるんでしょうが、LINQ to XML っていまいち使いづらいんですよね。それでも、XmlDocument よりは直感的かも。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// LINQ to XML を使う場合
XDocument doc = new XDocument();
XElement root = new XElement("TwiCatchStar");
doc.Add(root);
root.SetAttributeValue("version", APPVERSION);
root.SetAttributeValue("created_at", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
XElement user = new XElement("user");
root.Add(user);
user.Add(new XElement("screen_name", username));
user.Add(new XElement("profile_image_url", profile_image_url));
XElement statuses = new XElement("statuses");
statuses.SetAttributeValue("type", "array");
foreach (Tweet twi in items)
{
    XElement status = new XElement("status");
    statuses.Add(status);
    status.Add(new XElement("id", twi.ID));
    status.Add(new XElement("text", twi.text));
    status.Add(new XElement("created_at", twi.CreatedAt.ToString("yyyy/MM/dd HH:mm:ss")));
}

■ExDoc を使う場合

ExDoc は「もう LINQ to XML はいらない」を主旨にして作っているので、+= 演算子や []演算子を適当にオーバーライドして作成できるようにします。
本来ならば、CreateElement とか AppendElement という「名前」を使わずにやりたいのですが、ちょっと模索中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
EXDocument doc = new EXDocument("TwiCatchStar");
doc.Root["version"] = APPVERSION;
doc.Root["created_at"] = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
EXElement user = doc.Root.AppendElement("user");
user += doc.CreateElement("screen_name", username);
user += doc.CreateElement("profile_image_url", profile_image_url);
EXElement statuses = doc.Root.AppendElement("statuses");
statuses["type"] = "array";
foreach (Tweet twi in items)
{
    EXElement status = statuses.AppendElement("status");
    status += doc.CreateElement("id", twi.ID);
    status += doc.CreateElement("text", twi.text);
    status += doc.CreateElement("created_at", twi.CreatedAt.ToString("yyyy/MM/dd HH:mm:ss"));
}

LINQ to XML では、Add メソッド内で要素を作成していますが、実は適当な拡張メソッドを作れば AppendElement のような形でアクセスが可能なので、ExDoc の優位性というのはこの場合はあまりありません。

■VB で作る場合

実は、VB で作るのが一番直感的なんですよね。XML 用の拡張文法が VB に備わっているので、これを使うと…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
'''
''' コレクション
'''
'''
Public _tweets As List(Of Tweet)
'''
''' エンティティクラス
'''
'''
Public Class Tweet
    Public Property ID As String
    Public Property Text As String
    Public Property Create_at As Date
End Class
 
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim APPVERSION = "0.3"
    Dim username = "moonmile"
    Dim profile_image_url = ""
 
    Dim root As XElement =
     <TwiCatchStar version=<%= APPVERSION %> created_at=<%= Date.Now.ToString("yyyy/MM/dd HH:mm:ss") %>>
     </TwiCatchStar>
 
    Dim user As XElement =
     <user>
         <screen_name><%= username %></screen_name>
         <profile_image_url><%= profile_image_url %></profile_image_url>
     </user>
 
    Dim statuses =
     <statues>
         <%= From t In _tweets Select
             <status>
                 <id><%= t.ID %></id>
                 <text><%= t.Text %></text>
                 <create_at><%= t.Create_at.ToString("yyyy/MM/dd HH:mm:ss") %></create_at>
             </status> %>
     </statues>
 
    root.Add(user)
    root.Add(statuses)
 
    Me.TextBox1.Text = root.ToString()
 
End Sub

のように、なんて直感的に書けるんでしょうッ!!! まるで、ASP.NET の埋め込みか、PHP のように記述ができます。これには、ExDoc も脱帽 orz
一見、VB のほうが行数が長いので非効率に見えるのですが、保守性は抜群ですよね。一瞥しただけで変更が可能です。このために VB を使うのもいいかも(違

2012/07/08 追記

Egtra さんより教えて貰った方法で、LINQ to XML を書き直すとこんな感じ。
この記事を書いたときに、XElement に子のコレクションをどう入れれば分からなかったのですが、items.Select な感じでコレクションを渡すと、自動的に子に配列として付け加わるのですね。なるほど。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
XDocument doc = new XDocument(
    new XElement("TwiCatchStar",
        new XAttribute("version", APPVERSION),
        new XAttribute("created_at", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")),
        new XElement("user",
            new XElement("screen_name", username),
            new XElement("profile_image_url", profile_image_url)),
        new XElement("statuses",
            new XAttribute("type", "array"),
            items.Select(twi =>
                new XElement("status",
                    new XElement("id", twi.ID),
                    new XElement("text", twi.Text),
                    new XElement("created_at", twi.CreatedAt.ToString("yyyy/MM/dd HH:mm:ss")))))));

実は以前、XElement を扱った時「これってDOMに準拠していない」(DocumentからNodeを作成しない)という点でちょっと嫌っていたのですが、こういう書き方ができると、VB のように XML の構造通りに書けるからいいですよね。
ExDoc も doc.CreateElement のようにせずに、やっぱり doc += new EXElement(…) とか、doc.Append( new EXElement(…), new EXElemnet(…)) のように羅列できるように改造しようかな。

カテゴリー: UIDD, C#, VB パーマリンク

C# で XML ファイルを作成するときの比較(XmlDocument, XDocument, ExDoc) への2件のフィードバック

  1. Egtra のコメント:

    LINQ to XMLには関数型構築はどうでしょうか。VB .NETにはかなわないですが、XMLの構造を式で表現することを目指した書き方です。
    XDocument doc = new XDocument(
    new XElement(“TwiCatchStar”,
    new XAttribute(“version”, APPVERSION),
    new XAttribute(“created_at”, DateTime.Now.ToString(“yyyy/MM/dd HH:mm:ss”)),
    new XElement(“user”,
    new XElement(“screen_name”, username),
    new XElement(“profile_image_url”, profile_image_url)),
    new XElement(“statuses”,
    new XAttribute(“type”, “array”),
    items.Select(twi =>
    new XElement(“status”,
    new XElement(“id”, twi.ID),
    new XElement(“text”, twi.text),
    new XElement(“created_at”, twi.CreatedAt.ToString(“yyyy/MM/dd HH:mm:ss”)))))));

    • masuda のコメント:

      コメントありがとうございます。なるほど、XElement に複数の子要素を追加するときはそうするのか( items.Select のところ)。この部分がよくわからなくて、避けていたんですが、これができると XElement は使いやすそうですね。
      記事のほうに追記しました。

コメントは停止中です。