[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]] * 目次 [#pe665aa8] #contents *概要 [#o65cd171] とある案件の要件で、 非構造化データを粘土細工のように~ ゴリゴリと処理したいが、そういったことは、可能なのだろうか? ということを調査した。 *DataContractJsonSerializer [#t365ab51] *JSON.NET [#tf2395f2] ココが参考になる。 -C#でJSONを扱うライブラリ「Json.NET」を使ってみました - Qiita~ http://qiita.com/ta-yamaoka/items/a7ff1d9651310ade4e76 **基本 [#tf0108ab] ***シリアライズ・デシリアライズ [#df8d3cd2] [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] public string Property2 { get; set; } } -シリアライズ ---コード AAA aaa = new AAA(); aaa.Property1 = 100; aaa.Property2 = "xxx"; string json = JsonConvert.SerializeObject(aaa); ---文字列 {"prop1":100,"prop2":"xxx"} -デシリアライズ --型を指定してデシリアライズ ---コード~ AAA型にparseされる。 AAA aaa = JsonConvert.DeserializeObject<AAA>(json); --型を指定せずにデシリアライズ ---コード~ JObject型にparseされる。 object obj = JsonConvert.DeserializeObject(json); -参考 --JsonConvert.SerializeObject Method~ http://www.newtonsoft.com/json/help/html/Overload_Newtonsoft_Json_JsonConvert_SerializeObject.htm --JsonConvert.DeserializeObject Method~ http://www.newtonsoft.com/json/help/html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm ***既定値 [#adf4b3f4] -プロパティの既定値の設定~ プロパティの属性にSystem.ComponentModel.DefaultValue属性を指定する。 [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] [DefaultValue("hogehoge")] public string Property2 { get; set; } } -シリアライズ(デシリアライズ時)の既定値の取り扱い~ DefaultValueHandling 列挙体でシリアライズ(デシリアライズ時)の既定値の取り扱い方法を制御できる。 --DefaultValueHandling |設定値|動作|h |Include|シリアライズ時に既定値の項目をJSONに含める(既定)。| |Ignore|シリアライズ時に既定値の項目をJSONに含めない。| |Populate|デシリアライズ時にJSON文字列中に要素が存在しない場合でも既定値を設定。| |IgnoreAndPopulate|IgnoreとPopulateの同時指定。| --指定方法 ---プロパティの属性として指定 [JsonProperty("prop2", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] [DefaultValue("hogehoge")] public string Property2 { get; set; } ---シリアライズ時に指定 string json = JsonConvert.SerializeObject(aaa, Formatting.Indented, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate }); --デシリアライズ時に指定 AAA aaa = JsonConvert.DeserializeObject<UserModel>(jsonstring, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate }); **応用 [#j19bc906] 上記のリンク先の記事に >「階層構造を持ったJSONでも問題なくデシリアライズ可能。~ JSON配列もListなどにパースしてくれる。」 とあるが、何処までやってくれるか? ・・・検証の結果、 -型が特定できる構造のJSONはparseできる。 -[[型が特定できない構造のJSON>#ud85b2ed]]は、~ JObjectを使用して手動で匿名型にparseする。 ということが解った。 以下は、型が特定できる構造のJSONをparseする例。 ***階層構造を持ったBeanを使用する [#q9cc3f69] -型を明示 [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] public string Property2 { get; set; } [JsonProperty("prop3")] public AAA Property3 { get; set; } } static void Main(string[] args) { AAA aaa = new AAA(); aaa.Property1 = 100; aaa.Property2 = "xxx"; aaa.Property3 = new AAA(); aaa.Property3.Property1 = 200; aaa.Property3.Property2 = "yyy"; string json = JsonConvert.SerializeObject(aaa); Console.WriteLine(json); aaa = JsonConvert.DeserializeObject<AAA>(json); -型を明示しない~ オブジェクト型を使用する(JObject型にparseされる)。 [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] public string Property2 { get; set; } [JsonProperty("prop3")] public object Property3 { get; set; } } static void Main(string[] args) { AAA aaa1 = new AAA(); AAA aaa2 = new AAA(); aaa1.Property1 = 100; aaa1.Property2 = "xxx"; aaa2.Property1 = 200; aaa2.Property2 = "yyy"; aaa1.Property3 = aaa2; string json = JsonConvert.SerializeObject(aaa1); Console.WriteLine(json); aaa1 = JsonConvert.DeserializeObject<AAA>(json); ***配列(List<AAA>)を使用する [#c749f4e3] 配列(Generic)も問題なく処理できる。 [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] public string Property2 { get; set; } [JsonProperty("prop3")] public AAA Property3 { get; set; } } static void Main(string[] args) { AAA aaa1 = new AAA(); AAA aaa2 = new AAA(); aaa1.Property1 = 100; aaa1.Property2 = "xxx"; aaa2.Property1 = 200; aaa2.Property2 = "yyy"; aaa1.Property3 = aaa2; List<AAA> lstaaa = new List<AAA>(); lstaaa.Add(aaa1); lstaaa.Add(aaa2); string json = JsonConvert.SerializeObject(lstaaa); Console.WriteLine(json); lstaaa = JsonConvert.DeserializeObject<List<AAA>>(json); ***Primitive型とGeneric型を使用する [#p067db84] -Primitive型とGeneric型の範囲であれば、JSONの型が特定できるので、parseできる。 -このため、Primitive型とGeneric型の範囲で自由な構造を組むことができる。 -しかし、Genericでは、Beanのような(フィールド名・フィールド型の組み合わせが自由な)構造を組めない。 static void Main(string[] args) { List<Dictionary<string, string>> parent = new List<Dictionary<string, string>>(); Dictionary<string, string> child; child = new Dictionary<string, string>(); child["aaa"] = "AAA"; child["bbb"] = "BBB"; child["ccc"] = "CCC"; parent.Add(child); child = new Dictionary<string, string>(); child["xxx"] = "XXX"; child["yyy"] = "YYY"; child["zzz"] = "ZZZ"; parent.Add(child); string json = JsonConvert.SerializeObject(parent); Console.WriteLine(json); parent = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(json); ***継承を使用する [#q73512eb] 派生型をシリアライズできるが、問題は派生型にデシリアライズできないこと。 [JsonObject("aaa")] public class AAA { [JsonProperty("prop1")] public int Property1 { get; set; } [JsonProperty("prop2")] public string Property2 { get; set; } [JsonProperty("prop3")] public AAA Property3 { get; set; } } [JsonObject("bbb")] public class BBB : AAA { [JsonProperty("prop4")] public int Property4 { get; set; } } [JsonObject("ccc")] public class CCC : AAA { [JsonProperty("prop4")] public string Property4 { get; set; } } static void Main(string[] args) { AAA aaa1 = new AAA(); AAA aaa2 = new AAA(); aaa1.Property1 = 100; aaa1.Property2 = "xxx"; aaa1.Property3 = new BBB(); // AAAの派生のBBB aaa2.Property1 = 200; aaa2.Property2 = "yyy"; aaa2.Property3 = new CCC(); // AAAの派生のCCC List<AAA> lstaaa = new List<AAA>(); lstaaa.Add(aaa1); lstaaa.Add(aaa2); string json = JsonConvert.SerializeObject(lstaaa); Console.WriteLine(json); // BBBとCCCがAAA型のProperty3フィールドにデシリアライズされない。 lstaaa = JsonConvert.DeserializeObject<List<AAA>>(json); **型が特定できない構造のJSON [#ud85b2ed] ***型が特定できない構造のJSONの例 [#sdf7fbe0] -object型を使用しており、シリアライズの際、 --任意の型がシリアライズされる。 --出力されるされるJSONの構造が一定ではない。 -object型が使用される例 --子要素JSONの構造が一定ではない(Fieldにobject型を使用する) --配列内のJSONの構造が一定ではない(object[], Hashtableを使用する) ***型が特定できない構造のJSONをparseする例 [#eadea96f] -memo: C#でJSON配列のパースに苦労した話~ https://kazyx.blogspot.com/2013/09/cjson.html -JSON.NETで変なJSONを読み込む方法 - かずきのBlog@hatena~ http://blog.okazuki.jp/entry/2014/04/19/235806 **参考 [#w963879c] -Json.NET - Newtonsoft~ http://www.newtonsoft.com/json