如何向 JObject 添加 JToken?

96

我正在尝试使用JSON.Net将一些文本中的JSON对象添加到现有的JSON文件中。例如,如果我有以下JSON数据:

  {
  "food": {
    "fruit": {
      "apple": {
        "colour": "red",
        "size": "small"
      },
      "orange": {
        "colour": "orange",
        "size": "large"
      }
    }
  }
}

我一直试图这样做:

var foodJsonObj = JObject.Parse(jsonText);
var bananaJson = JObject.Parse(@"{ ""banana"" : { ""colour"": ""yellow"", ""size"": ""medium""}}");
var bananaToken = bananaJson as JToken;
foodJsonObj["food"]["fruit"]["orange"].AddAfterSelf(bananaToken);

但是这会导致错误:"Newtonsoft.Json.Linq.JProperty不能有多个值。"

我实际上尝试了几种不同的方法,但似乎就是无法得到结果。在我的例子中,我真正想做的是将新项目添加到“fruit”中。如果有更好的方法或更简单的库可供使用,请告诉我。

3个回答

153

我觉得你对JSON.Net中可以容纳哪些内容有些混淆了。

  • JToken是任意类型的JSON值的通用表示。它可以是字符串、对象、数组、属性等。
  • JProperty是单个JToken值与名称配对的组合。它只能添加到JObject中,并且其值不能是另一个JProperty
  • JObject是一个JProperties集合。它不能直接包含任何其他类型的JToken

在你的代码中,你试图将一个JObject(包含“banana”数据的对象)添加到一个已经有值(包含{"colour":"orange","size":"large"}的JObject)的JProperty(“orange”)中。正如你所看到的,这将导致错误。

你真正想要的是将一个名为“banana”的JProperty添加到包含其他水果JPropertiesJObject中。以下是修改后的代码:

JObject foodJsonObj = JObject.Parse(jsonText);
JObject fruits = foodJsonObj["food"]["fruit"] as JObject;
fruits.Add("banana", JObject.Parse(@"{""colour"":""yellow"",""size"":""medium""}"));

7
请使用 JToken.Parse(或JToken.FromObject)而不是在最后一行使用JObject.Parse。这也适用于简单对象,如字符串。 - ctrl-alt-delor
如果我想覆盖Jproperty,该怎么办? - Daniel
1
@Daniel - 如果你所说的“覆盖”是指完全替换JProperty为另一个不同的对象,那么你可以使用Replace方法。如果你只想改变JProperty的值,你可以在它上面设置Value属性;它是可写的。请参阅LINQ-to-JSON API reference - Brian Rogers

44
TL;DR: 将 JProperty 添加到 JObject 中,可以使用 AddAfterSelf 方法在特定的 JProperty 后添加新的属性。
接受的答案似乎没有回答问题。如果我想要在特定的 JProperty 后面添加一个 JProperty 呢?首先,让我们从术语开始,这些术语真的让我头疼。
- JToken = 所有其他类型的母体。它可以是 JValue、JProperty、JArray 或 JObject。这是为了提供可扩展的解析机制。 - JValue = 任何 Json 值类型(字符串、整数、布尔值)。 - JProperty = 任何带有名称(标识符)的 JValue 或 JContainer(见下文)。例如,"name":"value"。 - JContainer = 包含其他类型(JObject、JValue)的所有类型的母体。 - JObject = 一种 JContainer 类型,保存了一组 JProperties。 - JArray = 一种 JContainer 类型,保存了一组 JValue 或 JContainer。
当使用索引[]查询Json条目时,您会得到没有标识符的JToken,它可能是JContainer或JValue(需要转换),但是您不能在其后添加任何内容,因为它只是一个值。您可以更改它本身,查询更深的值,但是例如您不能在其后添加任何内容。
实际上你需要获取整个属性,然后根据需要添加另一个属性。为此,您可以使用JOjbect.Property("name"),然后创建所需的另一个JProperty,并使用AddAfterSelf方法在它后面添加。这样就完成了。
更多信息请参见:http://www.newtonsoft.com/json/help/html/ModifyJson.htm 这是我修改的代码。
public class Program
{
  public static void Main()
  {
    try
    {
      string jsonText = @"
      {
        ""food"": {
          ""fruit"": {
            ""apple"": {
              ""colour"": ""red"",
              ""size"": ""small""
            },
            ""orange"": {
              ""colour"": ""orange"",
              ""size"": ""large""
            }
          }
        }
      }";

      var foodJsonObj = JObject.Parse(jsonText);
      var bananaJson = JObject.Parse(@"{ ""banana"" : { ""colour"": ""yellow"", ""size"": ""medium""}}");

      var fruitJObject = foodJsonObj["food"]["fruit"] as JObject;
      fruitJObject.Property("orange").AddAfterSelf(new JProperty("banana", fruitJObject));

      Console.WriteLine(foodJsonObj.ToString());
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
    }
  }
}

4
你的术语用词有误。JToken(而不是 JValue)是 JArrayJObjectJPropertyJValue 最终继承自的基类。JValue 是一个 JSON 原始类型,表示字符串、数字、布尔、日期或 null 值;它不能表示数组或对象。请参阅LINQ-to-JSON API 参考 - Brian Rogers
1
@BrianRogers 谢谢,我修正了术语。 - Ghasan غسان
1
这是一个非常好的Newtonsoft对象模型解释,现在我能够更好地理解http://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm。到目前为止,我的使用尝试一直受到文档中缺乏详细解释的阻碍。它似乎只是从代码注释自动生成的参考资料。 - Tom Wilson
5
然而,代码示例的修改还不完全正确: var foodJsonObj = JObject.Parse(jsonText); var bananaJson = JObject.Parse(@"{ ""colour"": ""yellow"", ""size"": ""medium""}"); var fruitJObject = foodJsonObj["food"]["fruit"] as JObject; fruitJObject.Property("orange").AddAfterSelf(new JProperty("banana", bananaJson)); - Tom Wilson
我真的无法将代码标记应用于我的先前评论 - AARRGHH!我已经使用了反引号和缩进4个空格 - 我该怎么做? - Tom Wilson

5
只需将.First添加到您的bananaToken中即可:
foodJsonObj ["food"] ["fruit"] ["orange"].Parent.AddAfterSelf(bananaToken .First);
.First基本上是跳过{,以使其成为JProperty而非JToken

@Brian Rogers,谢谢提醒我忘了.Parent。已编辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接