C# 反序列化 JSON Schema.org 来自网络的食谱

C# Deserialize JSON Schema.org Recipe from web

我正在尝试用 C# 编写菜谱解析器。我尝试过同时使用 Newtonsoft 和 System.Text.Json。我使用过在线 json class 构建器和 VS2019 Paste as json classes。我有 Newtonsoft 示例代码 运行.

Schema.org 食谱 https://schema.org/Recipe

Class我在用。我真的只对这两个值感兴趣

public class Recipe
{
public string recipeIngredient { get; set; }
public string recipeInstructions { get; set; }
}

代码 - 此代码 运行 没有错误。

var document = File.ReadAllText(@"D:\recipeExample.json");
Recipe recipe = null;
try
{
    recipe = System.Text.Json.JsonSerializer.Deserialize<Recipe>(document);
}
    catch (System.Text.Json.JsonException ex)
{
    Console.WriteLine($"Error parsing : {ex}");
}

正在尝试读取值。没有错误或值。

Console.WriteLine(recipe.recipeIngredient);

我不确定我是否理解 schema.org 文档需要如何遍历。在生成的 classes 中,我可以看到 Graph 和 Context,我猜它们是根节点。但我的实验表明我不需要所有 classes - 只需要 recipeIngredient 和 recipeInstructions。 这只是一个食谱——我想解析一个食谱列表,我相信它们都有自己的 classes 所以我正在寻找最通用的方法来获取我的 2 个字段值求。

编辑

使用 tymtam 的 Json 文档示例我可以看到那里有一个对象

Console.WriteLine(recipes.Count);

但我无法使用

获取要显示的值
Console.WriteLine(recipes[0].Ingredients.ToString());
Console.WriteLine(recipes[0].Instructions.ToString());

我也试过用

打印配料
foreach (var recipe in recipes)
{
Console.WriteLine(recipes[0].Ingredients);
}

但这只打印对象名称而不打印元素

System.Linq.Enumerable+WhereSelectEnumerableIterator

编辑 2:已解决

foreach (var ingredient in recipes[0].Ingredients)
   Console.WriteLine(ingredient);

foreach (var instruction in recipes[0].Instructions)
   Console.WriteLine(instruction);

我认为您的问题是您正在一次读取整个文件。因此反序列化方法可能无法分配单个值,因为您试图从所有文本中解析一个变量

如果您正在使用 System.Text.Json 您应该能够在 class、

中设置 2 个属性
public string recipeIngredient {get; set;}
public string recipeInstructions {get; set;}
public override string ToString() => JsonSerializer.Serialize<Recipe>(this);

然后当你反序列化时你可以做这样的事情

public list<Recipe> getRecipe()
{
   using (var jsonFileReader = File.OpenText(filename))
   {
      return JsonSerializer.Deserialize<Recipe>(jsonFileReader.ReadToEnd());
   }
}

有了这个,您应该能够制作一个类型为您的食谱的列表 class。然后您应该能够引用该列表。 (编辑) 我忘了提到它,但你可能想称呼它,为此你会说 list<Recipe> recipeList = getRecipe(); 然后您只需遍历列表,每个对象都会有一个“.recipeIngredient”和“.recipeInstructions”,您可以使用它们来格式化输出

json的相关部分如下:

{
   "@context":"https://schema.org",
   "@graph":[
      (...)
      {
         "@type":"Recipe",
         "recipeIngredient":[
            "12 oz rice noodles",
            (...)
         ],
         "recipeInstructions":[
            {
               "@type":"HowToStep",
               "text":"Bring ...",
               "name":"Bring ...",
               "url":"https://..."
            },
            (...)
         ],
  (...)

System.Text.Json 与 JsonDocument

using (JsonDocument doc = JsonDocument.Parse(json))
{
    JsonElement root = doc.RootElement;
    JsonElement graph = root.GetProperty("@graph");

    var recipes = graph.EnumerateArray()
    .Where(g => g.GetProperty("@type").GetString() == "Recipe")
    .Select(r => new
    {
        Ingredients = r.GetProperty("recipeIngredient").EnumerateArray().Select(p => p.GetString()),
        Instructions = r.GetProperty("recipeInstructions").EnumerateArray().Select(p => new
        {
            @type = p.GetProperty("@type").GetString(),
            text = p.GetProperty("text").GetString(),
            name = p.GetProperty("name").GetString(),
            url = p.GetProperty("url").GetString(),
        })
    })
    .ToList();
}

System.Text.Json 与 类

class Root 
{
    [JsonPropertyName("@context")]
    public string Context {get; set;}
    
    [JsonPropertyName("@graph")]
    public List<Element> Graph {get; set;}
}


class Element {
    [JsonPropertyName("@type")]
    public string Type {get;set;}
    public List<string> RecipeIngredient {get; set;}

    public List<Instruction> RecipeInstructions {get; set;}
}

class Instruction {
    public string Text {get; set;}
}
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
};
var x = JsonSerializer.Deserialize<Root>(json, options);
var recipes = x.Graph.Where( o => o.Type == "Recipe");

Json.Net

请看官方Querying JSON with LINQ or Querying JSON with SelectToken.

这是一个带有查询和 类:

的混合搭配解决方案
using Newtonsoft.Json.Linq;

JObject o = JObject.Parse(json);
JToken t = o.SelectToken("$.@graph[?(@.@type == 'Recipe')]");
var recipe = t.ToObject<Recipe>();

(...)
class Recipe {
    public List<string> RecipeIngredient {get; set;}

    public List<Instruction> RecipeInstructions {get; set;}
}

class Instruction {
    public string Text {get; set;}
}

对于多个配方,使用 SelectTokens