【问题标题】:Select part of json with System.text.json使用 System.text.json 选择部分 json
【发布时间】:2021-07-21 19:37:04
【问题描述】:

我开始使用 c# 并反序列化 Json。在我的培训中,我学习了 Newtonsoft,但我想对 system.text.json 做同样的事情

有了这个json,我想选择

  • 搜索产品 > 特色产品 和
  • 搜索过的产品 > 产品详情

制作一个对象列表。

https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=fr-fr&category=GPU&gpu=RTX%203090,RTX%203080%20Ti,RTX%203080,RTX%203070%20Ti,RTX%203070,RTX%203060%20Ti,RTX%203060&gpu_filter=RTX%203090~12,RTX%203080%20Ti~7,RTX%203080~16,RTX%203070%20Ti~3,RTX%203070~18,RTX%203060%20Ti~8,RTX%203060~2,RTX%202080%20SUPER~1,RTX%202080~0,RTX%202070%20SUPER~0,RTX%202070~0,RTX%202060~6,GTX%201660%20Ti~0,GTX%201660%20SUPER~9,GTX%201660~8,GTX%201650%20Ti~0,GTX%201650%20SUPER~3,GTX%201650~17

public class CarteGraphique
{
    public string displayName { get; set; }
    public string prdStatus { get; set; }
    public List<Retailer> retailers { get; set; }
}

使用 Newtonsoft,我执行以下操作:

牛顿软件

JObject jsonParse = JObject.Parse(json);

IList<CarteGraphique> products = new List<CarteGraphique>();

IList<JToken> productDetailsParse = jsonParse["searchedProducts"]["productDetails"]
    .Children()
    .Where(n => n["isFounderEdition"].Value<bool>() == true)
    .ToList();
var featuredProductParse = jsonParse["searchedProducts"]["featuredProduct"];


foreach (JToken item in productDetailsParse)
{
    CarteGraphique result = item.ToObject<CarteGraphique>();
    products.Add(result);
}
var featuredProduct = featuredProductParse.ToObject<CarteGraphique>();

products.Add(featuredProduct);



foreach (var item in products)
{
    Console.WriteLine(item.DisplayName);
}

我想用 System.Text.Json 做到这一点...但我不知道如何选择 json 部分“productDetails”以将其添加到对象列表中。

System.text.json

var listGpu = new List<CarteGraphique>();

var jsonParse = JsonDocument.Parse(json);

var jsonFilter = jsonParse.RootElement
    .GetProperty("searchedProducts")
    .GetProperty("featuredProduct")
    .GetRawText();

var jsonObj = JsonSerializer.Deserialize<CarteGraphique>(jsonFilter);

listGpu.Add(jsonObj);


foreach (var item in listGpu)
{
    Console.WriteLine(item.displayName);
}

你能帮帮我吗? 对于我这个初学者来说,文档不清楚。

【问题讨论】:

  • System.Text.Json 区分大小写,因此您需要使用new JsonSerializerOptions { PropertyNameCaseInsensitive = true },请参阅dotnetfiddle.net/nMaXSh。和JsonSerializer.Deserialize fails。这就是为什么CarteGraphique.PrdStatus 没有成功反序列化的原因。那是你唯一的问题吗?从您的问题来看,尚不清楚您的问题到底出在哪里。
  • 感谢您的回答,抱歉粘贴错误,我正在编辑我的课程。不,不是那样,我只想获取“productDetails”并反序列化以添加到列表中,就像我使用 Newtonsoft 的示例

标签: c# json system.text.json


【解决方案1】:

您可以按如下方式模拟 Json.NET 逻辑:

using var jsonParse = JsonDocument.Parse(json); // Be sure to dispose the JsonDocument!

var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };

var products = jsonParse.RootElement
    .GetProperty("searchedProducts") // Get the searchedProducts value
    .GetProperty("productDetails")   // Get the productDetails value
    .EnumerateArray()                // Enumerate its items
    .Where(n => n.GetProperty("isFounderEdition").GetBoolean()) // Filter on those for which isFounderEdition == true
    .Select(n => n.ToObject<CarteGraphique>(options)) // Deserialize to a CarteGraphique
    .ToList();
    
// Add the searchedProducts.featuredProduct item to the list.
var featuredProduct = jsonParse.RootElement
    .GetProperty("searchedProducts")
    .GetProperty("featuredProduct")
    .ToObject<CarteGraphique>(options);

products.Add(featuredProduct);
        

其中ToObject&lt;T&gt;(this JsonElement element, JsonSerializerOptions options = null)是从this answerSystem.Text.Json.JsonElement ToObject workaround的扩展方法

public static partial class JsonExtensions
{
    public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
    {
        var bufferWriter = new System.Buffers.ArrayBufferWriter<byte>();
        using (var writer = new Utf8JsonWriter(bufferWriter))
            element.WriteTo(writer);
        return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
    }

    public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
    {
        if (document == null)
            throw new ArgumentNullException(nameof(document));
        return document.RootElement.ToObject<T>(options);
    }       
}

注意事项:

演示小提琴here.

【讨论】:

  • 谢谢,对我帮助很大,很好解释。只是一个问题,为什么在你的演示中使用“使用”解析和网络客户端?
  • @Castiel - 因为两者都是一次性的。 JsonDocument 需要按照我的回答“注释”中的说明进行处理。旧的WebClient(我在小提琴中使用它是因为它是同步的)也应该被处理掉。但是,较新的HttpClient 应该被缓存和重用,而不是丢弃,请参阅Do HttpClient and HttpClientHandler have to be disposed between requests?
【解决方案2】:

在迁移到 JsonDocument 时,我也遇到了同样的问题。所以我开发了一个小型库来重新创建 JObject 的相同行为。它允许使用类似索引器的语法导航域对象模型。它叫做JsonEasyNavigation,你可以在github找到它或者从nuget.org获取。

在您的情况下,解决方案可能如下:

List<CarteGraphique> products = new List<CarteGraphique>();

using var jsonDocument = JsonDocument.Parse(json);
var nav = jsonDocument.ToNavigation();

var productDetails = nav["searchedProducts"]["productDetails"].Values
    .Where(x => x["isFounderEdition"].GetBooleanOrDefault())
    .Select(x => x.Map<CarteGraphique>())
    .ToArray();

var featuredProduct = nav["searchedProducts"]["featuredProduct"].Map<CarteGraphique>();

products.AddRange(productDetails);
products.Add(featuredProduct);

JsonDocument 必须使用 ToNavigation() 方法转换为 JsonNavigationElement。我希望你会发现它有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-21
    • 2023-04-02
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多