「ツイートキャッチ★★★」で xml 形式でファイルに出力するために、ExDoc を拡張している途中です。ExDoc の主旨として「ユーザーインターフェースを優先する」という項目があるので(勝手に自分で付けたw)、ユーザーから使いやすいコーディングの仕方に合わせて拡張していきます。ユーザーってのは、「コーディングをするプログラマ」ってことですね、新しい UIDD(User Interface Developement Driven)の一環です(というのも、勝手に自分で付けたw)
と前置きはそれくらいにして、コードを晒しておきます。
TwiCatchStar の内部データを直接 xml に書き出します。
■XmlDocument を使う場合
通常の XmlDocument を使う場合です。まあ、旧来の DOM インターフェースを知っていれば作れるので、java などの他言語から入った人にはいいのでしょうが、結構手間です。
// 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 よりは直感的かも。
// 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 という「名前」を使わずにやりたいのですが、ちょっと模索中。
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 に備わっているので、これを使うと…
''' ''' コレクション ''' ''' 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 な感じでコレクションを渡すと、自動的に子に配列として付け加わるのですね。なるほど。
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(…)) のように羅列できるように改造しようかな。
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”)))))));
コメントありがとうございます。なるほど、XElement に複数の子要素を追加するときはそうするのか( items.Select のところ)。この部分がよくわからなくて、避けていたんですが、これができると XElement は使いやすそうですね。
記事のほうに追記しました。