マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

とある案件の要件で、

非構造化データを粘土細工のように
ゴリゴリと処理したいが、そういったことは、可能なのだろうか?

ということを調査した。

結論としては、コチラのLINQ to JSONを使用することで可能。

JSON フォーマットとクラスの定義

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;

Web Essentialsを使用

Visual Studio の拡張機能である、Web Essentials を使うと、JSON からクラスを自動生成できる。
Web Essentials は、Visual Studio のメニューから、[ツール] - [拡張機能と更新プログラム] で追加できる。

WebEssentials.png

JSON 文字列をコピーし、Visual Studio のエディターで、右クリックまたは [編集] メニューから、
[形式を選択して貼り付け] - [JSON をクラスとして貼り付ける] を選択すると、
その JSON フォーマットに合ったクラスが生成される。

JSON.NET

ココが参考になる。

基本(Bean, POCO)

シリアライズ・デシリアライズ

[JsonObject("aaa")]
public class AAA
{
  [JsonProperty("prop1")]
  public int Property1 { get; set; }
  [JsonProperty("prop2")]
  public string Property2  { get; set; }
}

既定値を制御する属性

その他、属性

様々な属性がある。

応用

上記のリンク先の記事に

「階層構造を持ったJSONでも問題なくデシリアライズ可能。
JSON配列もListなどにパースしてくれる。」

とあるが、何処までやってくれるか?

・・・検証の結果、

ということが解った。

以下は、型が特定できる構造のJSONをparseする例。

階層構造を持ったBean, POCOを使用する

配列(List<AAA>)を使用する

配列(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型を使用する

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);

型が特定できない構造のJSON

型が特定できない構造のJSONの例

シリアライズの対象にobject型を使用しており、

シリアライズの際、

object型を使用せざるを得ないケース

以下の様な構造が一定ではないケースでは、
シリアライズの対象にobject型を使用せざるを得ない。

JSON.NETのJObjectのLINQ to JSONで手動のデシリアライズ

型が特定できない構造の(object型をシリアライズした)JSONを
デシリアライズするとJSONデータはJObject型に格納される。

この場合、JSON.NETのJObjectのLINQ to JSONで型の手動のデシリアライズを行う。

参考

DataContractJsonSerializer?

WCFの既定のシリアライザ。

流行ってないので基本スルーだが、
使う場合は、以下の点に注意する。

JavaやJSON.NETのシリアライザとの違い。

.NETのDataContractJsonSerializer?はJavaやJSON.NETと、シリアライザの挙動が違う。
そのため、同じ形式の POJO または POCO であっても、シリアライズ後の JSON フォーマットが異なる。

Dictionaryのシリアライズ結果

特に、以下のように Dictionaryの JSON シリアライズ結果が異なる。

#技術POJO / POCO サンプルシリアライズされた JSON
1Java, JSON.NETpublic 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" }
2public 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; }
}
4public class Sample {
    public Dictionary<string, string> key { get; set; }
}
[
    {
        "Key": "Prop1",
        "Value": "Value1"
    },
    {
        "Key": "Prop2",
        "Value": "Value2"
    }
]

同じ形式のジェネリック型であっても、
使用するSerializer次第でシリアライズ結果が異なる

Efficient dictionary serialization, Nonsensical dictionary serialization

この違いは、以下の機能のサポート状況によるものらしい。

JSON.stringify、JSON.parse(JavaScript

JavaScriptでは、JSON.stringify(シリアライズ)、JSON.parse(デシリアライズ)が使用できる。

JSON.parse

JSON 文字列を解析して JavaScript のオブジェクトに変換する。

JSON.stringify

JavaScript の値を JSON 文字列に変換する。

参考

応用

JSONを送信するRESTサービスを作成する方法

JSONを受信するJSON-RPCサービスを作成する方法

コンボ生成でJSONを使用する際の注意事項(順番保証)。

順番保証がされないので、

JSON.NETのJObjectを使ってみる。

Deserialize

以下のようにデシリアライズできる。

JObject jObject = (JObject)JsonConvert.DeserializeObject(jsonResult);
if (jObject["Message"] != null)
{
    // 正常終了
    List<Dictionary<string, string>> list =
        JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jObject["Result"].ToString());
    this.lstRecords.ItemsSource = list;
    message = "正常終了しました";
}
else
{
    ・・・

Messageの戻りによって、Resultの方が変わる事例。

Serialize

上記のシナリオに合わせて、以下のようにシリアライズできる。

単にobject型を使用したり、匿名型を使用したりして、
シリアライズするobject階層構造を可変にすればイイ。

object ret = null;
if(・・・)
{
  ret = new { ErrorMSG = message };
}
else
{
  List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
  ・・・
  ret = new { Message = "", Result = list };
}
return Request.CreateResponse(HttpStatusCode.OK, ret);

参考

参考


Tags: :.NET開発, :.NET Core, :.NET Standard, :ASP.NET, :ASP.NET Web API


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