「マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。
とある案件の要件で、
非構造化データを粘土細工のように
ゴリゴリと処理したいが、そういったことは、可能なのだろうか?
ということを調査した。
結論としては、コチラのLINQ to JSONを使用することで可能。
まず、どのようなフォーマットの JSON を出力したいのかを確認する。
次に、出力したい JSON に合わせて、クラスを定義する。
基本的には、以下のルールに従って、クラス・プロパティを定義する。
基本的に、以下のようにJSON出力を想定し、クラスを定義する。
| # | 出力したいJSON | 定義するクラス・プロパティ |
| 1 | { "key1" : "value1", "key2" : "value2" } | public class Sample { string key1 { get; set; } string key2 { get; set; } } 若しくは、 Dictionary<string, string> dic; |
| 2 | [ "1", "2", "3" ] | List<string> listData { get; set; } |
| 3 | { "key1" : [ "1", "2", "3" ] } | public class Sample { List<string> key1 { get; set; } } |
| 4 | { "key" : { "key1" : "value1", "key2" : "value2" } } | public class Sample { string key1 { get; set; } string key2 { get; set; } } public class Sample2 { Sample key { get; set; } } 若しくは、 Dictionary<string, Sample> dic; 若しくは、 Dictionary<string, Dictionary<string, string>> dic; |
| 5 | [ { "key1" : "value1", "key2" : "value2" }, { "key1" : "value3", "key2" : "value4" } ] | public class Sample { string key1 { get; set; } string key2 { get; set; } } List<Sample> list; |
JsonConvert.SerializeObject(new
{
date = DateTime.Now,
command = SqlExecuteType.Reader,
text = this.ClearText(this._commandText),
param = this._commandParameters,
ms = this._stopwatch.ElapsedMilliseconds
}, Formatting.None));Visual Studio の拡張機能である、Web Essentials を使うと、JSON からクラスを自動生成できる。
Web Essentials は、Visual Studio のメニューから、[ツール] - [拡張機能と更新プログラム] で追加できる。

JSON 文字列をコピーし、Visual Studio のエディターで、右クリックまたは [編集] メニューから、
[形式を選択して貼り付け] - [JSON をクラスとして貼り付ける] を選択すると、
その JSON フォーマットに合ったクラスが生成される。
ココが参考になる。
[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 = JsonConvert.DeserializeObject<AAA>(json);
JObject jobj = (JObject)JsonConvert.DeserializeObject(json);
[JsonObject("aaa")]
public class AAA
{
[JsonProperty("prop1")]
public int Property1 { get; set; }
[JsonProperty("prop2")]
[DefaultValue("hogehoge")]
public string Property2 { get; set; }
}| # | 設定値 | 動作 |
| 1 | Include | シリアライズ時に既定値の項目をJSONに含める(既定)。 |
| 2 | Ignore | シリアライズ時に既定値の項目をJSONに含めない。 |
| 3 | Populate | デシリアライズ時にJSON文字列中に要素が存在しない場合でも既定値を設定。 |
| 4 | 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 });様々な属性がある。
上記のリンク先の記事に
「階層構造を持ったJSONでも問題なくデシリアライズ可能。
JSON配列もListなどにパースしてくれる。」
とあるが、何処までやってくれるか?
・・・検証の結果、
ということが解った。
以下は、型が特定できる構造のJSONをparseする例。
[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);[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);
JObject jobj= (JObject)JsonConvert.DeserializeObject(json);配列(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);
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);
[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);
シリアライズの対象にobject型を使用しており、
シリアライズの際、
以下の様な構造が一定ではないケースでは、
シリアライズの対象にobject型を使用せざるを得ない。
型が特定できない構造の(object型をシリアライズした)JSONを
デシリアライズするとJSONデータはJObject型に格納される。
この場合、LINQ to JSONでJObject型の手動のデシリアライズを行う。
LINQ to JSONといっても、単純にインデクサで処理できる模様。
WCFの既定のシリアライザ。
流行ってないので基本スルーだが、
使う場合は、以下の点に注意する。
.NETのDataContractJsonSerializer?はJavaやJSON.NETと、シリアライザの挙動が違う。
そのため、同じ形式の POJO または POCO であっても、シリアライズ後の JSON フォーマットが異なる。
特に、以下のように Dictionaryの JSON シリアライズ結果が異なる。
| # | 技術 | POJO / POCO サンプル | シリアライズされた JSON |
| 1 | Java, JSON.NET | public class Sample { public String _key1; public String _key2; public void setKey1(String key1) { this._key1 = key1; } public String getKey1() { return this._key1; } public void setKey2(String key2) { this._key2 = key2; } public String getKey2() { return this._key2; } } | { "key1" : "value1", "key2" : "value2" } |
| 2 | public class Sample { public HashMap?<String, String> _key; public void setKey(HashMap?<String, String> key) { this._key = key; } public void getKey() { return this._key; } } | ||
| 3 | .NETのDataContractJsonSerializer? | public class Sample { public string key1 { get; set; } public string key2 { get; set; } } | |
| 4 | public class Sample { public Dictionary<string, string> key { get; set; } } | [ { "Key": "Prop1", "Value": "Value1" }, { "Key": "Prop2", "Value": "Value2" } ] 同じ形式のジェネリック型であっても、 使用するSerializer次第でシリアライズ結果が異なる |
この違いは、以下の機能のサポート状況によるものらしい。
JavaScriptでは、JSON.stringify(シリアライズ)、JSON.parse(デシリアライズ)が使用できる。
JSON 文字列を解析して JavaScript のオブジェクトに変換する。
JavaScript の値を JSON 文字列に変換する。
順番保証がされないので、
{ "key1" : "value1", "key2" : "value2" }[ [ "key1", "value1" ], [ "key2", "value2" ] ]
Tags: :.NET開発, :.NET Core, :.NET Standard, :ASP.NET, :ASP.NET Web API