Newtonsoft Json.NET でJSONを作成
概要・あらすじ
C#のデスクトップアプリにて、サーバーへJSONをPOSTする処理を組みたかったので Newtonsoft.Json のライブラリを使っていた。
で、「コレでJSONってどうやって作んねん?」となったので、 使い方というか理解を深める為?に書いたメモの延長線上的記事となります。
ちなみに 同ライブラリにおけるJSONのパース方法に関しては、別記事を過去にこさえています
Newtonsoft Json.NET を雰囲気で使う ← 読みづらい記事ですみません... 書き直すの面倒
公式ドキュメント
「このへんかな~」ってページへのリンクをちょろっと貼っておきますね
LINQ to JSON - Create JSON manually
LINQ to JSON - Create JSON using Collection Initializers
基本性質
※ 自己解釈
JObject 型 | { } | オブジェクトの"ガワ"部分 |
JArray 型 | [ ] | 配列の"ガワ"部分 |
JProperty 型 | "key":"value" | key:valueのペア・概念 |
JToken 型 | value(?) | value部分。ただしあやふやな状態。 これ以上細分化できるかもしれないし出来ないかもしれない |
JValue 型 | value | value部分。これ以上細分化出来ない、末端・単体の値相当。 数値/文字列/bool とか多分その辺 |
キャストしたり型の確認を癖に
プロパティには当然 .Value
概念がある。
key : value の対関係で、ひとつの「プロパティ」なのだから当然。
ただ、.Value
の「値」は Jvalue 型 ではなく、まず JToken 型 で扱われる。
なぜなら、.Value
の皮を被っていても 実態は JObject {} だったり JArray [] だったりする可能性 があるから。
勿論、これ以上細分化できない純粋な値 ( 1 とか "hoge" とか。つまり JValue 型) の可能性も勿論ある。
JSON作成例
例 1
下記オブジェクトを作成
{
{
"k1":"value1" ,
"k2": 234 ,
}
}
//( ↓ 感覚的にはこっちかも)
{
"k1":"value1" ,
"k2": 234 ,
}
↓ 処理内容
JObject obj = new JObject(); // { { } }
JProperty propA = new JProperty("k1", "value1"); // { "k1" , "value1" }
JProperty propB = new JProperty("k2", 234 ); // { "k2" , 234 }
obj.Add(propA);
obj.Add(propB);
例 2
下記オブジェクトを作成
{
{
"k1ArrVal" : [ ],
"k2ArrVals" : [ 1 , 2 , "hoge" ],
}
}
↓ 処理内容
// 作成パターン 1
{
JObject obj = new JObject(); // { { } }
JProperty propA = new JProperty("k1ArrVal"); // { "k1ArrVal" , [](的な状態) }
JProperty propB = new JProperty("k2ArrVals"); // { "k2ArrVals" , [](的な状態) }
// propBのvalue である [] 部分を JArray にキャストした([]として扱う事を確定させた)うえで、
// .Add() で値(JValue) を配列要素として放り込む
((JArray)(propB.Value)).Add(new JValue(1)); // { "k2ArrVals" , [ 1 ] }
((JArray)(propB.Value)).Add(new JValue(2)); // { "k2ArrVals" , [ 1 , 2 ] }
((JArray)(propB.Value)).Add(new JValue("hoge")); // { "k2ArrVals" , [ 1 , 2 , "hoge" ] }
obj.Add(propA);
obj.Add(propB);
}
// 作成パターン 2
{
JObject obj = new JObject(); // { { } }
JProperty propA = new JProperty("k1ArrVal"); // { "k1ArrVal" , [](的な状態) }
JProperty propB = new JProperty("k2ArrVals"); // { "k2ArrVals" , [](的な状態) }
// 一度 JArray で取り出して、そっちを追加処理に使うのもアリかも?
// 変にキャストするよりは可読性あるかもしれない
JArray _tempArr = (JArray)(propB.Value);
_tempArr.Add(1);
_tempArr.Add(2);
_tempArr.Add("hoge");
obj.Add(propA);
obj.Add(propB);
}
例 3
下記オブジェクトを作成
{
{
"Prop_1" : {
"keyA" : 1 ,
"key2" : 10
} ,
"Prop_2" : {
"hoge" : "foo" ,
"huga" : "bar"
}
}
}
↓ 処理内容
JObject obj = new JObject(); // { { } }
JProperty prop_1 = new JProperty("Prop_1", new JObject()); // { "Prop_1" , { } }
JProperty prop_2 = new JProperty("Prop_2", new JObject()); // { "Prop_2" , { } }
JProperty child1P1 = new JProperty("keyA", 1); // { "keyA" , 1 }
JProperty child1P2 = new JProperty("key2", 10); // { "key2" , 10 }
JProperty child2P1 = new JProperty("hoge", "foo"); // { "hoge" , "foo" }
JProperty child2P2 = new JProperty("huga", "bar"); // { "huga" , "bar" }
// "Prop_*" の対となる Value を JObject(つまり{})に見立てて(キャストして) .Add()で追加を図る
((JObject)(prop_1.Value)).Add(child1P1);
((JObject)(prop_1.Value)).Add(child1P2);
((JObject)(prop_2.Value)).Add(child2P1);
((JObject)(prop_2.Value)).Add(child2P2);
obj.Add(prop_1);
obj.Add(prop_2);
JValue 型だと .Add()
が用意されていないので、
JObject 型として扱う事で .Add()
を使えるようにする ( そしてオブジェクトの中に放り込む )
..といった感じ。
キャストを含めて、型をうまく扱うのが要なんやな~って気がします。
JProperty JValue 作成
基本形
// 同じものが出来上がる { "content" , "aa" }
JProperty _propB1 = new JProperty("content" , "aa");
JProperty _propB2 = new JProperty("content" , new JValue("aa") );
// 同じものが出来上がる { "content" , 10 }
JProperty _propB3 = new JProperty("content", 10 );
JProperty _propB4 = new JProperty("content", new JValue(10) );
作成例
空のJObjectに、プロパティを2つ突っ込む
// { { } } の "ガワ"を作成
JObject _jobjA = new JObject();
// プロパティ(key:value) を2つ作成
JProperty _propA = new JProperty("propA" , "aa"); // { "propA" , "aa" }
JProperty _propB = new JProperty("propB" , "bb"); // { "propB" , "aa" }
// 作成した2プロパティを "ガワ" に放り込む
_jobjA.Add(_propA);
_jobjA.Add(_propB);
/** できあがり
* {
* "propA" , "aa" ,
* "propB" , "aa" ,
* }
*/
他の例外など
以下はプロパティのキー名が重複するので例外発生 💦
JObject _jobjA = new JObject(); // { { } }
JProperty _propA = new JProperty("propA" , "aa"); // { "propA" , "aa" }
JProperty _propB = new JProperty("propA" , 1234 ); // { "propA" , 1234 }
_jobjA.Add(_propA);
_jobjA.Add(_propB);
// System.ArgumentException: 'Can not add property propA to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.'
/**
* ※ キー名が同じ。実現不可
* {
* "propA" , "aa" ,
* "propA" , 1234 ,
* }
*/
例外発生ケースその2
プロパティのvalue相当に対して 値を挿入・割り当てる場合、JObject 型だと怒られる。
{
// 同じものが出来上がる
// { "content" , "aa" }
JProperty _propB1 = new JProperty("content" , "aa");
JProperty _propB2 = new JProperty("content" , new JValue("aa") );
}
{
// 同じものが出来上がる
// { "content" , 10 }
JProperty _propB3 = new JProperty("content", 10 );
JProperty _propB4 = new JProperty("content", new JValue(10));
// JValue を入れなきゃいけない場所に JObject は突っ込めないと怒られる
// { "content" , 10 ← × 追加失敗 }
JProperty _propB5 = new JProperty("content", new JObject(10));
// (例外発生) System.ArgumentException:
// 'Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.'
}
ちなみに、JProperty 作成時、第2引数を省略すると value 側が配列(JArray)になる模様? Json.NET Documentation - JProperty Constructor
JProperty _propA = new JProperty("content"); // { "content" , [] }
上記ケースは JValue 側が配列なので .Add()
でValue側の配列に要素を突っ込めると思いきや、出来ない
JProperty _propA = new JProperty("content"); // { "content" , [] }
JProperty _elmA = new JProperty("key1", 1 ); // { "key1" , 1 }
_propA.Add(_elmA);
// { "content" , [ { "key1" , 1 } ← × 追加失敗] }
// Newtonsoft.Json.JsonException: 'Newtonsoft.Json.Linq.JProperty cannot have multiple values.'
JProperty は(1つの)プロパティなので、.Add()
で多数のプロパティを持てない
1台のゲーム機の中に、ソフトカセットは1つ挿せるが、ゲーム機1台を挿せるわけがないのと一緒
おまけ:JavaScriptなら...
型がユルいってのもあってか、このくらいカジュアルに放り込めるのですが。
{
const Arr = [];
Arr.push(1);
Arr.push("あいうえお");
Arr.push( { "key1" : "value1" } );
console.log(Arr);
}
.js
畑の人間だと自分では思っているので、C#
でこのライブラリ弄っているとき、
「元の濁りの田沼恋しき」 フレーズをつい思い浮かべてしまいましたね...