C# 使用 System.Text.Json 動態取得內容(清單, 指定屬性, 不區分大小寫)

一般在處理 Json 內容時通常都是已經知道 Json 的格式,所以大部分都會先建立一個 class ,然後直接將 Json 內容反序列化為物件,簡單快速。 不過有些時候不會建立對應格式的類別,會想要直接動態的取得 Json 的某些屬性內容,那該怎麼做呢?

動態取得 Json 內容

原始 Json:
    
[
  {
    "id": 1,
    "name": "小明"
  },
  {
    "id": 2,
    "name": "大頭"
  }
]
    

    
string json = "[{\"id\": 1, \"name\": \"小明\"}, {\"id\": 2, \"name\": \"大頭\"}]";

using JsonDocument document = JsonDocument.Parse(json);
JsonElement root = document.RootElement;

// 取得清單中的每一項
foreach (JsonElement jsonElement in root.EnumerateArray())
{
    Console.WriteLine();
    Console.WriteLine($"Value: {jsonElement}, Value Type: {jsonElement.ValueKind}");
    
    // 取得物件中的所有屬性
    foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject())
    {
        Console.WriteLine($"Name: {jsonProperty.Name}, Value: {jsonProperty.Value}, Value Type: {jsonProperty.Value.ValueKind}");
    }
}


/*
Value: {"id": 1, "name": "小明"}, Value Type: Object
Name: id, Value: 1, Value Type: Number
Name: name, Value: 小明, Value Type: String

Value: {"id": 2, "name": "大頭"}, Value Type: Object
Name: id, Value: 2, Value Type: Number
Name: name, Value: 大頭, Value Type: String
*/
    

取得指定屬性內容

我們已經可以動態取得所有內容了,那我們先簡化一點,假設只有一個 Json Object,該如何動態取得指定的 Json 屬性內容呢?

原始 Json 資料:
    
{
  "id": 1,
  "name": "小明"
}
    

    
string json = "{\"id\": 1, \"name\": \"小明\"}";

using JsonDocument document = JsonDocument.Parse(json);
JsonElement root = document.RootElement;

if (root.TryGetProperty("name", out JsonElement nameProperty))
{
    string name = nameProperty.GetString() ?? string.Empty;
    Console.WriteLine($"name: {name}");
}
else
{
    Console.WriteLine("'name' property not found");
}

/*
name: 小明
*/
    

註:如果有多個內容屬性相同,則會回傳最後一個。

取得指定屬性內容且不區分大小寫

在上面的範例中 name 是小寫,如果使用 Name 或是 NAME 等只要大小寫不完全相同,就會取不到內容。 翻了一下文件,發現目前應該沒有內建的解決方式,筆者目前想到的是最笨的方法,就是一一比對屬性,然後比對時使用 StringComparison.OrdinalIgnoreCase 忽略大小寫。 為了方便複用,所以寫了一個擴充方法:
    
public static class JsonElementExtensions
{
    public static bool TryGetPropertyIgnoreCase(this JsonElement element, string propertyName, out JsonElement value)
    {
        foreach (JsonProperty property in element.EnumerateObject())
        {
            if (property.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
            {
                value = property.Value;
                return true;
            }
        }

        value = default;
        return false;
    }
}
    

用起來也很簡單,只要把剛剛的 TryGetProperty 改為 TryGetPropertyIgnoreCase 即可
    
string json = "{\"id\": 1, \"name\": \"小明\"}";

using JsonDocument document = JsonDocument.Parse(json);
JsonElement root = document.RootElement;

// if (root.TryGetProperty("name", out JsonElement nameProperty))
if (root.TryGetPropertyIgnoreCase("Name", out JsonElement nameProperty))
{
    string name = nameProperty.GetString() ?? string.Empty;
    Console.WriteLine($"name: {name}");
}
else
{
    Console.WriteLine("'name' property not found");
}

/*
name: 小明
*/
    



參考資料:
Microsoft.Learn - JsonDocument Class
Microsoft.Learn - JsonElement.TryGetProperty Method

留言