JSON 形式の文字列 {"name":"value"} から name を指定して value を取得する C# のプログラムのサンプルを書きます。
先の記事「Json.NET の JToken をパース」と「System.Text.Json の JsonElement をパース」で、Json.NET (Newtonsoft.Json) と System.Text.Json を使って JSON 文字列をパースするサンプルを書きました。
先の記事のサンプルの使い道はなさそうですが、その応用でいろいろできそうということで、まず JSON 文字列を JToken (Json.NET) または JsonElement (System.Text.Json) にデシリアライズしたオブジェクトから、name を指定して再帰的に value 値を取得するコードを書いてみました。
それが何の役に立つかというと、例えば JSON 文字列構造が不定なので特定のクラスにデシリアライズできないが、必要な情報のある name は事前に分かっているのでそれに該当する value を取得できれば目的は果たせるというようなケースです。
レアケースかもしれませんけど、ASP.NET Forum でそういう話があったので考えてみました。
JToken (Json.NET) および JsonElement (System.Text.Json) の両方の場合のサンプルコードを以下にアップしておきます。
(1) JToken (Json.NET)
Json.NET (Newtonsoft.Json) の DeserializeObject メソッドで JSON 文字列を JToken クラスのオブジェクトにデシリアライズし、その中から name が "ObjectArray" の value 値を FindJTokenByName メソッドで取得しています。
その結果を Visual Studio 2019 のデバッガで見たのが上の画像です。元になる JSON 文字列はこの記事の下の方に書いてありますのでそちらを見てください。
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
namespace NewtonsoftJson
{
class Program
{
static void Main(string[] args)
{
string path = @"C:\Users\...\NewtonsoftJson\";
string file = "TextFile5.txt";
string jsonText = "";
using (StreamReader sr = File.OpenText(path + file))
{
jsonText = sr.ReadToEnd();
}
JToken jtoken = JsonConvert.DeserializeObject<JToken>(jsonText);
Parse(0, jtoken);
JToken token = FindJTokenByName(jtoken, "ObjectArray");
}
private static void Parse(int padding, JToken jtoken)
{
// ・・・略・・・
}
private static JToken FindJTokenByName(JToken jtoken, string name)
{
if (jtoken is JObject)
{
foreach (KeyValuePair<string, JToken> kvp in (JObject)jtoken)
{
if (kvp.Key == name)
{
return kvp.Value;
}
else
{
JToken retVal = FindJTokenByName(kvp.Value, name);
if (retVal != null)
{
return retVal;
}
}
}
}
else if (jtoken is JArray)
{
foreach (JToken jtokenInArray in (JArray)jtoken)
{
JToken retVal = FindJTokenByName(jtokenInArray, name);
if (retVal != null)
{
return retVal;
}
}
}
else
{
return null;
}
return null;
}
}
}
(2) JsonElement (System.Text.Json)
System.Text.Json の Deserialize メソッドで JSON 文字列を JsonElement 構造体のオブジェクトにデシリアライズし、その中から name が "ObjectArray" の value 値を FindElementByName メソッドで取得しています。
using System;
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using System.IO;
namespace ConsoleAppJson
{
class Program
{
static void Main(string[] args)
{
string path = @"C:\Users\surfe...\ConsoleAppJson\";
string file = "TextFile5.txt";
string jsonText = "";
using (StreamReader sr = File.OpenText(path + file))
{
jsonText = sr.ReadToEnd();
}
JsonElement jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonText);
Parse(0, jsonElement);
var jelem = FindElementByName(jsonElement, "ObjectArray");
}
private static void Parse(int padding, JsonElement jelem)
{
// ・・・略・・・
}
// JsonElement は構造体。見つからないと null が返ってくるので
// 戻り値は JsonElement? として null 許容にした
private static JsonElement? FindElementByName(JsonElement jelem, string name)
{
if (jelem.ValueKind == JsonValueKind.Object)
{
foreach (JsonProperty jprop in jelem.EnumerateObject())
{
if (jprop.Name == name)
{
return jprop.Value;
}
else
{
JsonElement? retVal = FindElementByName(jprop.Value, name);
if (retVal != null)
{
return retVal;
}
}
}
}
else if (jelem.ValueKind == JsonValueKind.Array)
{
foreach (JsonElement jelemInArray in jelem.EnumerateArray())
{
JsonElement? retVal = FindElementByName(jelemInArray, name);
if (retVal != null)
{
return retVal;
}
}
}
else
{
return null;
}
return null;
}
}
}
上のコードで使った TextFile5.txt の JSON 文字列は以下の通りです。
{
"Title": "This is my title",
"Response": {
"Version": 1,
"StatusCode": "OK",
"Result": {
"Profile": {
"UserName": "SampleUser",
"IsMobileNumberVerified": false,
"MobilePhoneNumber": null
},
"ObjectArray" : [
{"Code": 2000,"Description": "Fail"},
{"Code": 3000,"Description": "Success"}
],
"lstEnrollment": "2021-2-5"
},
"Message": {
"Code": 1000,
"Description": "OK"
}
},
"StringArray" : ["abc", "def", "ghi"]
}