Làm thế nào để bạn thêm một JToken vào một JObject?


84

Tôi đang cố gắng thêm đối tượng JSON từ một số văn bản vào tệp JSON hiện có bằng JSON.Net. Ví dụ: nếu tôi có dữ liệu JSON như bên dưới:

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

Tôi đã cố gắng làm điều này như thế này:

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);

Nhưng điều này gây ra lỗi: "Newtonsoft.Json.Linq.JProperty cannot have multiple values."

Tôi thực sự đã thử một vài cách khác nhau nhưng dường như không đi đến đâu. Trong ví dụ của tôi, điều tôi thực sự muốn làm là thêm mục mới vào "trái cây". Vui lòng cho tôi biết nếu có cách nào tốt hơn hoặc sử dụng một thư viện đơn giản hơn.

Câu trả lời:


139

Tôi nghĩ rằng bạn đang bối rối về những gì có thể chứa những gì trong JSON.Net.

  • A JTokenlà đại diện chung của giá trị JSON thuộc bất kỳ loại nào. Nó có thể là một chuỗi, đối tượng, mảng, thuộc tính, v.v.
  • A JPropertylà một JTokengiá trị duy nhất được ghép nối với một tên. Nó chỉ có thể được thêm vào a JObjectvà giá trị của nó không thể là giá trị khác JProperty.
  • A JObjectlà một tập hợp của JProperties. Nó không thể chứa bất kỳ loại JTokentrực tiếp nào khác .

Trong mã của bạn, bạn đang cố gắng thêm a JObject(một chứa dữ liệu "chuối") vào một JProperty("cam") đã có một giá trị (a JObjectchứa {"colour":"orange","size":"large"}). Như bạn đã thấy, điều này sẽ dẫn đến một lỗi.

Những gì bạn thực sự muốn làm là thêm một quả JPropertyđược gọi là "chuối" vào quả JObjectcó chứa quả kia JProperties. Đây là mã sửa đổi:

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

7
Lưu ý: Sử dụng 'JToken.Parse' (hoặc 'JToken.FromObject') thay vì JObject.Parse, ở dòng cuối cùng. Vì điều này cũng hoạt động đối với các đối tượng đơn giản như chuỗi.
— ctrl-alt-delor

phải làm gì nếu tôi muốn ghi đè một Jproperty.
— Daniel

@Daniel - Nếu bằng cách "ghi đè" bạn muốn thay thế hoàn toàn JPropertybằng một cái khác, thì bạn có thể sử dụng Replacephương pháp này. Nếu bạn chỉ muốn thay đổi giá trị của JProperty, bạn có thể đặt thuộc Valuetính trên đó; nó có thể ghi được. Xem tham chiếu API LINQ-to-JSON .
— Brian Rogers

35

TL; DR: Bạn nên thêm JProperty vào JObject. Đơn giản. Truy vấn chỉ mục trả về một JValue, vì vậy hãy tìm cách lấy JProperty thay thế :)


Câu trả lời được chấp nhận không phải là trả lời câu hỏi như nó có vẻ. Điều gì sẽ xảy ra nếu tôi muốn thêm một JProperty cụ thể vào sau một cái cụ thể? Đầu tiên, chúng ta hãy bắt đầu với các thuật ngữ thực sự khiến tôi phải đau đầu.

  • JToken = Mẹ của tất cả các loại khác. Nó có thể là A JValue, JProperty, JArray hoặc JObject. Điều này là để cung cấp một thiết kế mô-đun cho cơ chế phân tích cú pháp.
  • JValue = bất kỳ kiểu giá trị Json nào (string, int, boolean).
  • JProperty = bất kỳ JValue hoặc JContainer nào (xem bên dưới) được ghép nối với một tên (định danh) . Ví dụ "name":"value".
  • JContainer = Mẹ của tất cả các kiểu chứa các kiểu khác (JObject, JValue).
  • JObject = một kiểu JContainer chứa một tập hợp các JProperties
  • JArray = một kiểu JContainer chứa một tập hợp JValue hoặc JContainer.

Bây giờ, khi bạn truy vấn mục Json bằng chỉ mục [], bạn đang nhận được JToken mà không có mã định danh, có thể là JContainer hoặc JValue (yêu cầu ép kiểu), nhưng bạn không thể thêm bất kỳ thứ gì vào sau nó, vì nó chỉ là một giá trị. Bạn có thể tự thay đổi nó, truy vấn các giá trị sâu hơn, nhưng bạn không thể thêm bất cứ thứ gì vào sau nó chẳng hạn.

Những gì bạn thực sự muốn nhận được là toàn bộ thuộc tính, và sau đó thêm một thuộc tính khác sau nó như mong muốn. Đối với điều này, bạn sử dụng JOjbect.Property("name"), và sau đó tạo một JProperty khác mà bạn mong muốn và sau đó thêm nó vào sau khi sử dụngAddAfterSelf phương pháp này. Bạn đã hoàn thành sau đó.

Để biết thêm thông tin: http://www.newtonsoft.com/json/help/html/ModifyJson.htm

Đây là mã tôi đã sửa đổi.

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
Bạn đã sai thuật ngữ của mình. JToken(không JValue) là lớp cơ sở mà từ đó JArray, JObject, JPropertyvà JValuecuối cùng là kế thừa. JValuelà một nguyên thủy JSON đại diện cho một chuỗi, số, boolean, ngày tháng hoặc giá trị null; nó không thể đại diện cho một mảng hoặc đối tượng. Xem Tham chiếu API LINQ-to-JSON .
— Brian Rogers

1
@BrianRogers Cảm ơn, tôi đã sửa thuật ngữ.
— Ghasan

1
Đây là một lời giải thích rất hay về mô hình đối tượng Newtonsoft và bây giờ tôi có thể hiểu newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm tốt hơn nhiều. Cho đến nay, nỗ lực của tôi để sử dụng nó đã bị cản trở do thiếu phần giải thích chi tiết trong tài liệu. Nó chỉ có vẻ là một tham chiếu được tạo tự động từ các bình luận mã.
— Tom Wilson,

2
Tuy nhiên, mã ví dụ mod không hoàn toàn đúng: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "color" ":" "yellow" "," "size" ":" "medium" "}"); var fruitJObject = foodJsonObj ["food"] ["fruit"] as JObject; fruitJObject.Property ("cam"). AddAfterSelf (JProperty mới ("chuối", bananaJson)); '
— Tom Wilson

Cả đời này tôi không thể áp dụng đánh dấu mã cho nhận xét trước đây của mình - AARRGHH! Tôi đã sử dụng dấu tích lùi và thụt vào 4 khoảng trắng - làm cách nào để thực hiện?
— Tom Wilson,

5

Chỉ cần thêm .Firstvào bananaTokennên làm của bạn: về cơ bản di chuyển qua để biến nó thành a thay vì a .
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken

@Brian Rogers, Cảm ơn tôi đã quên .Parent. Đã chỉnh sửa

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.