[[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();
 
   aaa2.Property1 = 200;
   aaa2.Property2 = "yyy";
   aaa2.Property3 = new CCC();
 
   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);

**型が特定できない構造の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

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS