「ツイートキャッチ★★★」で 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(…)) のように羅列できるように改造しようかな。
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 は使いやすそうですね。
記事のほうに追記しました。