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。
我正在尝试用 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。