- 追加された行はこの色です。
- 削除された行はこの色です。
[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]
* 目次 [#pe665aa8]
#contents
*概要 [#o65cd171]
とある案件の要件で、
>非構造化データを粘土細工のように~
ゴリゴリと処理したいが、そういったことは、可能なのだろうか?
ということを調査した。
結論としては、[[コチラ>#ud85b2ed]]のLINQ to JSON
を使用することで可能。~
LINQ to JSONといっても、単純にインデクサで処理できる模様。
結論としては、[[コチラ>#ud85b2ed]]のLINQ to JSONを使用することで可能。
*基本 [#b1965670]
基本的には、[[ここ>JSONを送受信するRESTサービスを作成する方法#e10b9cbb]]に記載されたルールに従って、parseする。
*JSON.NET [#tf2395f2]
ココが参考になる。
-C#でJSONを扱うライブラリ「Json.NET」を使ってみました - Qiita~
http://qiita.com/ta-yamaoka/items/a7ff1d9651310ade4e76
**基本(Bean, POCO) [#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型にデシリアライズされる。
AAA aaa = JsonConvert.DeserializeObject<AAA>(json);
--型を指定せずにデシリアライズ
---コード~
JObject型にデシリアライズされる。
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はシリアライズできる。
-[[型が特定できない構造のJSON>#ud85b2ed]]は、シリアライズは可能だが、~
デシリアライズ結果は(インデクサが使用可能な)JObjectに格納されるので、~
これをそのまま使用するか、手動で任意の型にデシリアライズする必要がある。
ということが解った。
以下は、型が特定できる構造のJSONをparseする例。
***階層構造を持ったBean, POCOを使用する [#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型にデシリアライズされる)。
[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, POCOを使用するため(フィールド名・フィールド型の組み合わせが)自由な構造を組めない。
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の構造が一定ではない。
***object型を使用せざるを得ないケース [#ea76ada5]
-子要素JSONの構造が一定ではない(Fieldにobject型を使用する)
-配列内のJSONの構造が一定ではない(object[], Hashtableを使用する)
-object型が使用される例
--子要素JSONの構造が一定ではない(Fieldにobject型を使用する)
--配列内のJSONの構造が一定ではない(object[], Hashtableを使用する)
***LINQ to JSONで手動のデシリアライズ [#vd7fdcd8]
型が特定できない構造のJSONをデシリアライズするとJSONデータはJObject型に格納される。
***型が特定できない構造の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
この場合、LINQ to JSONでJObject型の手動のデシリアライズを行う。
LINQ to JSONといっても、単純にインデクサで処理できる模様。
-C# + LINQ でJSONのパースをする - Qiita~
http://qiita.com/numa08/items/475ab3e8aa9e10441a26
-Json.NET (Newtonsoft.Json) の基本的な使い方 | ITメモ~
https://netweblog.wordpress.com/2016/10/24/json-net-newtonsoft-json-usage/
-LINQ to JSON~
http://www.newtonsoft.com/json/help/html/LINQtoJSON.htm
--Querying JSON with LINQ~
http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
***型が特定できない構造の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
*DataContractJsonSerializer [#t365ab51]