【问题标题】:Extract values from json or jarray elements从 json 或 jarray 元素中提取值
【发布时间】:2019-07-04 19:24:33
【问题描述】:

我有 JSON 数组,例如:

[
    {
        "type": "type1",
        "id": "id1",
        "properties": 
        {
            "sales": 
            [
                {
                    "name": "name1",
                    "requested_date": "2019-06-28"
                }
            ]
        }
    },
    {
        "type": "type1",
        "id": "id2",
        "properties": 
        {
            "sales": 
            [
                {
                    "name": "name2",
                    "requested_date": "2019-06-28"
                }
            ]
        }
    },
    {
        "type": "type1",
        "id": "id3",
        "properties": 
        {
            "sales": 
            [
                {
                    "name": "name3",
                    "requested_date": "2019-06-29"
                }
            ]
        }
    }
]

我想先通读它以提取请求日期的所有唯一值,所以在这种情况下,我会得到“2019-06-28”、“2019-06-29”。

其次,我需要能够选择与指定请求日期的选定值有关的所有条目。我已经有一个用于销售的 POCO,一个用于整个条目,但属性只是对象字典,因为它可以是任何东西,就像在这种情况下它是一个销售。

我的 JSON 在 JArray 中:

var stringCachedAddresses = JsonConvert.SerializeObject(cachedAddresses);
var parsedObject = JArray.Parse(stringCachedAddresses);

我只是不知道如何导航到每个条目的 requested_date,将值添加到列表中(如果不存在),也许是某种我无法弄清楚的 LINQ。

我可以获得所有销售的清单:

var parsedProperties = (from f in parsedObject
                        select f["properties"]["sales"]).ToList();

如何从parsedProperties 读取或直接获取requested_date 的值?

【问题讨论】:

  • 到目前为止你尝试过什么代码?您是否遇到了特定的错误或问题?如果您还没有这样做,请查看this 帮助文章,了解如何提出好的问题。
  • 这里有数百篇关于 JSON 序列化和解析的帖子。
  • 是的,但至少没有找到像这样的多层级,大部分时间是非常简单的 Json,很少像我正在寻找的那样从中选择值。
  • 其次,我需要能够选择与指定请求日期的选定值有关的所有条目。我已经有一个用于销售的 POCO... 堆栈溢出问题的首选格式是 one question per post,所以您能否将其分解为单独的帖子并显示 Sales POCO。
  • 对于第一部分,如果您只想在 JSON 层次结构中查找所有出现的 "requested_date",请参阅 Find a value of all occurrences from the json string in c#How do I get a deeply-nested property from JSON string?,例如变量query = parsedObject.SelectTokens("..requested_date")..Select(t => t.ToObject<DateTime>()).Distinct();: dotnetfiddle.net/BkAEaP

标签: c# json json.net


【解决方案1】:

假设您的 POCO for sale 如下所示:

public class Sales
{
    public string name { get; set; }
    public string requested_date { get; set; }
}

然后,您可以在层次结构中找到具有指定 requested_date 的所有 "sales" 对象,并通过将 查询与对 JToken.ToObject<Sales> 的调用相结合来反序列化每个选定项目:

// Your requested date
var requested_date = "2019-06-28";

// Construct a JSONPath query
var pathTemplate = "[*].properties.sales[?(@.requested_date == '{0}')]";
var path = string.Format(pathTemplate, requested_date);

// Query for and deserialize all sales from the specified requested date
var query = parsedObject.SelectTokens(path)
    .Select(t => t.ToObject<Sales>());

// Materialize the query as a list.
var list = query.ToList();

同样,您可以找到所有不同的requested_date 值,如下所示:

// Query for all values of requested_date, convert them to strings, and take all distinct values:
var query = parsedObject.SelectTokens("[*].properties.sales[*].requested_date")
    .Select(t => t.ToString()) 
    .Distinct();

// Materialize the query as a list.
var list = query.ToList();

注意事项:

  1. * 通配符运算符选择所有数组元素。

  2. ?(&lt;expression&gt;) 过滤器运算符应用过滤器表达式(使用 Json.NET 的 filter syntax)来选择指定的数组元素——这里是那些具有指定请求日期的元素。

  3. 有关 JSONPath 语法的概述,请参阅JSONPath - XPath for JSON

  4. 如果属性名称"sales"不固定,可以使用通配符作为属性名称,例如:

    "[*].properties.*[?(@.requested_date == '{0}')]";
    

    "[*].properties.*[*].requested_date"
    

演示小提琴here.

【讨论】:

  • 我看到了前面的 JSonPath 示例,但我无法让它为我工作,缺少通配符的使用。比我使用 from select 更好的解决方案。
  • select 是否可以像在 SQL 中一样工作,并且能够为每个 requested_date 添加一个计数值?
  • 我是这样做的:var querySales = parsedObject.SelectTokens("[*].properties.sales[*] .requested_date").Select(t => t.ToString())。 GroupBy(t => t).Select(x => new { requested_date = x.Key, count = x.Count() });
  • 我刚刚发现虽然从特定请求日期返回所有销售额非常有效,但我想要从请求日期返回的具有类型、id、属性的整个条目,而不仅仅是销售对象
  • @KaptainJ - 这里的首选格式是one question per post,因此您可能应该提出一个新问题,参考这个问题并使用minimal reproducible example 显示您的JSON 和数据模型。从您的评论中我无法真正弄清楚您的要求。
【解决方案2】:

我设法获得了不同的请求日期,尽管它看起来并不复杂:

var parsedObject = JArray.Parse(stringCachedAddresses);
var parsedProperties = (from f in parsedObject
                        select f["properties"]["sales"]);
var parsedForSales = (from s in parsedProperties.Children()["requested_date"]
                      select s).Distinct().ToList();

我的主要问题仍然是如何根据所需的请求日期提取 JSon 条目?

【讨论】:

  • 听起来你可能需要.ToLookup 之类的东西(它类似于每个键有多个值的字典)。每个日期您需要什么值?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多