[上原ひろみ]ひろみちゃんのこと。

なれなれしくひろみちゃんとか言ってるけど、知り合いではありませんw
僕は上原ひろみさんがとっても大好きなんです。


この画像はモスクワでの写真。胸に手を当て、感謝の気持ちを噛み締めているところが印象的です。

今はすごく有名になりました。僕がひろみちゃんを知ったのは大学の頃。TBSの情熱大陸を見たのがきっかけでした。結構たくさんいると思います。情熱大陸を見たのがきっかけって。僕は情熱大陸のVTRをもっていたりするのですが、若かりし頃(ええ、今も若いですよ)のひろみちゃんは、テレビやMCのときと印象がとっても違う。なんというか、貪欲ですごい一生懸命なひろみちゃんなんですね。なんとも形容しがたいけど、主張するひろみちゃんというか、、。でも、そこが本人のパワー。マネージャーつけないで、日々海外を飛び回っているひろみちゃんって、ほんとすごいなって思うんです。

今年も年の瀬が近づいて来ました。ひろみちゃんの年末の日本ツアーは僕の毎年の行事です。今年もひろみちゃんのライブ楽しみだなー♪

今日のひろみちゃん。
創造のるつぼ:新盤発表、旅するジャズピアニスト・上原ひろみ 毎日新聞 2012年11月07日 大阪夕刊
http://mainichi.jp/feature/news/20121107ddf012040023000c.html

[C#]objectとJSONとXMLの変換。

JSON,object,XMLの変換のお話。

ちょっとした設定データやデータベースを作成するほどの量でもないデータにはXMLやJSONにシリアライズして保存すると便利。JSONはWebの言語では当たり前かもしれないけど、C#プログラマーにとってはまだまだマイナー。
でも、JSONはXMLと違ってタグと値がシンプルなので、その分データ量がXMLより少なくできる。データ量が多量になるとXMLではタグがある分、データ量が肥大するので、ネットワーク越しのやりとりにもJSON(文字列)するとまた便利。

JSONとXMLはデータ構造を表現するクラスと相性が良い。

例えば、次のような個人データクラスを作ったとする。

    class Person
    {
        public int Number { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string TEL { get; set; }
    }

このクラスのデータを複数保持できるような形にして、XMLとJSONに保存すると次のようになる。
・XML

<?xml version="1.0" encoding="utf-8"?>
<manage>
  <persons>
    <Number>0</Number>
    <FirstName>YOSHIKO</FirstName>
    <LastName>AOKI</LastName>
    <Address>TOKYO</Address>
    <TEL>1234578</TEL>
  </persons>
</manage>

・JSON

{"manage":{"persons":[{"Number":0,"FirstName":"YOSHIKO","LastName":"AOKI","Address":"TOKYO","TEL":"1234578"}]}}

データ量はJSONのほうが少なくできる。可視性はXMLのほうが優れているけど。

で、本題。自分で作成したクラスをJSONもしくはXMLにシリアライズするとする。ライブラリは.Net界では有名なJson.Netを使用する。.Net FrameworkのDataContractJsonSerializerはクラスに属性を付加しないといけないので、ちょっとめんどくさい。他にもDynamicJsonなどがある。

参照
.NET FrameworkでJSONデータを処理する
http://codezine.jp/article/detail/5868

Json.Net
http://json.codeplex.com/

DynamicJson
http://dynamicjson.codeplex.com/

Json(string)からobject,Json(string)からXMLなどはユーティリティとして関数化してもいいけど、拡張メソッドにするとちょっと便利。

ここでは、ExtensionsClassとして次のような拡張メソッドを定義した。

    /// <summary>
    /// object <-> JSON <-> XML の相互変換用の拡張メソッド
    /// </summary>
    public static class ExtensionsClass
    {
        /// <summary>
        /// object -> JSON(string)
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string Object2Json(this object obj)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// JSON(string) -> object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <returns></returns>
        public static object Json2Object<T>(this string str)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
        }

        /// <summary>
        /// JSON(string) -> XmlDocument
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static XmlDocument Json2XmlDocument(this string str)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeXmlNode(str);
        }

        /// <summary>
        /// JSON(string) -> XDocument
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static XDocument Json2XDocument(this string str)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeXNode(str);
        }

        /// <summary>
        /// XmlDocument -> XDocument
        /// </summary>
        /// <param name="xmldoc"></param>
        /// <returns></returns>
        public static XDocument XmlDocument2XDocument(this XmlDocument xmldoc)
        {
            return XDocument.Load(new XmlNodeReader(xmldoc));
        }

        /// <summary>
        /// object -> XDocument
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static XDocument Object2XDocument(this object obj)
        {
            return Json2XDocument(Object2Json(obj));
        }

        /// <summary>
        /// XDocument -> JSON(string)
        /// </summary>
        /// <param name="xdoc"></param>
        /// <returns></returns>
        public static string XDocumnet2Json(this XDocument xdoc)
        {
            return Newtonsoft.Json.JsonConvert.SerializeXNode(xdoc);
        }

        /// <summary>
        /// XDocument -> object
        /// </summary>
        /// <param name="xdoc"></param>
        /// <returns></returns>
        public static object XDocument2Object<T>(this XDocument xdoc)
        {
            return Json2Object<T>(XDocumnet2Json(xdoc));
        }
    }

上記のように汎用的な型(object,string)に拡張メソッドを書くのはちょっと、、、ってときは、ダミーのクラスを作成して、データクラスのベースクラスにするといいと思う(拡張メソッドの引数のthis の次の型にダミークラスを指定する)。

簡易的な拡張メソッドなので、使用にはちょっと注意が必要。データのフォーマットが間違っているとすぐふっとぶ。ライブラリを使用するときはtry-catchを入れておくのは必要かもね。ここでは省略しちゃうけど。

ここではJSONとXMLの両方を扱うので、両方のフォーマットに適合するようにデータクラスを定義する必要がある。Personクラスを複数保持できるデータクラスは次のようになる。

    /// <summary>
    /// 個人データ
    /// </summary>
    class Person
    {
        public int Number { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string TEL { get; set; }

        public Person()
        {
            Number = 0;
            FirstName = LastName = Address = TEL = "";
        }

        public Person(int number,string fname, string lname, string addr, string tel)
        {
            Number = number;
            FirstName = fname;
            LastName = lname;
            Address = addr;
            TEL = tel;
        }
    }

    /// <summary>
    /// Personクラスの配列を保持
    /// </summary>
    class Persons
    {
        public List<Person> persons { get; set; }
        
        public Persons()
        {
            persons = new List<Person>();
        }
    }

    /// <summary>
    /// ROOTノードクラス
    /// ※XML形式用にTop階層用に必要
    /// このクラスは1つのプロパティ要素しか持たない
    /// </summary>
    class Manage
    {
        public Persons manage { get; set; }

        public Manage()
        {
            manage = new Persons();
        }
    }

ManageクラスはXMLで表すところのroot(TOP階層)になるので、XML化では必須。ちなみに、JSONのみ扱う場合は必要ない。

データを用意する
テストデータとして、次のようなデータを用意した。


        Manage _manage = new Manage();

        /// <summary>
        /// 初期値展開用
        /// </summary>
        void DataSet()
        {
            _manage.manage.persons.Add(new Person(0,"YOSHIKO", "AOKI", "TOKYO", "1234578"));
            _manage.manage.persons.Add(new Person(1,"MAMI", "MANAKA", "TOKYO", "9999999"));
            _manage.manage.persons.Add(new Person(2,"SHIGEAKI", "ITOI", "OSAKA", "33333333"));
            _manage.manage.persons.Add(new Person(3,"AI", "YOMOGI", "OKIANAWA", "444444444"));
            _manage.manage.persons.Add(new Person(4,"KEN", "AOSHIMA", "NAGANO", "000000000"));
        }

ManageクラスをJSON形式に変換して保存する
拡張メソッド(ExtensionsClass)を使用してManageクラスのデータ(_manage)をJSON形式にシリアライズしてファイルに保存してみる。JSONはstringになるので、扱いはとっても楽。

System.IO.File.WriteAllText("persons.json", _manage.Object2Json());

ManageクラスをXML形式に変換して保存する
XMLでの保存も、拡張メソッド(JSON経由だけど^^;)を使用してXDocumentクラスに変換することで、保存が非常に楽にできる。

_manage.Object2XDocument().Save("persons.xml");

JSON形式をManageクラスに変換する
今度は逆にファイルから読み取ったデータをデシリアライズしてデータクラスに変換する。これもJSONライブラリで一発。うーんなんて便利なんでしょう。

// JSON形式をデシリアライザしてManageクラスにキャストして読み込み
_manage = (Manage)System.IO.File.ReadAllText(ofd.FileName).Json2Object<Manage>(); 

XML形式をManageクラスに変換する
XMLからの読み取りも拡張メソッドを組み合わせてManageクラスに変換する。

// XML形式をデシリアライザしてManageクラスにキャストして読み込み
_manage = (Manage)((XDocument.Load(ofd.FileName).XDocument2Object<Manage>()));

C#ではデータクラスはとっても意義がある気がする
このように、objectとJSONとXMLへの変換はこうしてライブラリによって平和に解決することができる。JSONとXMLは似ていて、Json.Netとかも内部的にはXMLのようなデータ構造をもっていると思う(たぶん)。また、クラスのプロパティへのバインドも動的なものだし、正直、速度的なパフォーマンスは期待できない。よって、軽量なデータなどには向いているけど、大量のデータを扱うにはそれなりに設計が必要かも。

LINQtoObjectではデータしかもたないクラスへの操作はとっても便利。objectからJSONとかXMLとか、汎用的なフォーマットに簡単に変換できるのってのはとっても意義がある気がする。汎用的なフォーマットへの変換はC#だけではなく、他の言語とかでも使用出来るので、ネットワーク越しのフォーマットにも使用出来るし。例えばクライアントはC#,VBとかでサーバサイドはPythonやRubyとかで。

今回作成したプロジェクトはこちら(自己責任で)
DataIroiro.zip