Як додати JToken до JObject?


84

Я намагаюся додати об'єкт JSON з деякого тексту до існуючого файлу JSON за допомогою JSON.Net. Наприклад, якщо у мене є дані 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 cannot have multiple values."

Я насправді пробував кілька різних способів, але, здається, нікуди не дістатися. У моєму прикладі я дійсно хочу додати новий пункт до "фрукти". Будь ласка, дайте мені знати, чи є кращий спосіб зробити це або простіша бібліотека для використання.

Відповіді:


139

Я думаю, ви заплутаєтесь у тому, що може вмістити що-небудь у JSON.Net.

  • A JToken- загальне представлення будь-якого значення JSON. Це може бути рядок, об’єкт, масив, властивість тощо.
  • A JProperty- це одне JTokenзначення в парі з іменем. Його можна додати лише до a JObject, а його значення не може бути іншим JProperty.
  • A JObject- це колекція JProperties. Він не може проводити будь-який інший вид JTokenбезпосередньо.

У своєму коді ви намагаєтеся додати JObject (той, що містить дані "банана") до JProperty("апельсина"), який уже має значення (a JObjectмістить {"colour":"orange","size":"large"}). Як ви бачили, це призведе до помилки.

Що ви дійсно хочете зробити, це додати так JPropertyзваний "банан" до того, JObjectякий містить інші фрукти JProperties. Ось переглянутий код:

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 - Якщо під "перезаписом" ви хочете повністю замінити JPropertyінший, тоді ви можете використовувати Replaceметод. Якщо ви просто хочете змінити значення JProperty, ви можете встановити для нього Valueвластивість; це можна записати. Див . Посилання на API LINQ-to-JSON .
Брайан Роджерс

35

TL; DR: Ви повинні додати JProperty до JObject. Простий. Індексний запит повертає значення JValue, тому з’ясуйте, як натомість отримати JProperty :)


Прийнята відповідь - це не відповідь на питання, як здається. Що робити, якщо я хочу спеціально додати JProperty після конкретного? По-перше, давайте почнемо з термінологій, які насправді розробили мою голову.

  • JToken = Мати всіх інших типів. Це може бути JValue, JProperty, JArray або JObject. Це передбачає модульну конструкцію механізму розбору.
  • JValue = будь-який тип значення Json (рядок, int, логічне значення).
  • JProperty = будь-який JValue або JContainer (див. Нижче) в парі з ім'ям (ідентифікатором) . Наприклад"name":"value" .
  • JContainer = Мати всіх типів, які містять інші типи (JObject, JValue).
  • JObject = тип JContainer, що містить колекцію JProperties
  • JArray = тип JContainer, що містить колекцію JValue або JContainer.

Тепер, коли ви запитуєте елемент Json за допомогою індексу [], ви отримуєте JToken без ідентифікатора, який може бути JContainer або JValue (вимагає кастингу), але після нього ви не можете нічого додати, оскільки це лише значення. Ви можете змінити її саму, запитати більш глибокі значення, але після цього, наприклад, нічого не можна додати.

Що ви насправді хочете отримати, це властивість у цілому, а потім додайте іншу властивість після неї за бажанням. Для цього ви використовуєте JOjbect.Property("name"), а потім створюєте іншу властивість JP за вашим бажанням, а потім додаєте її після цього за допомогою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) є базовим класом , з якого JArray, JObject, JPropertyі , в JValueкінцевому рахунку успадковує. JValueє примітивом JSON, який представляє рядок, число, логічне значення, дату або нульове значення; він не може представляти масив або об'єкт. Див . Посилання на API LINQ-to-JSON .
Брайан Роджерс

1
@BrianRogers Дякую, я виправив термінологію.
Ghasan

1
Це дуже гарне пояснення об’єктної моделі Newtonsoft, і тепер я можу набагато краще зрозуміти newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm . Дотепер мої зусилля щодо його використання заважали відсутністю детальних пояснень у документах. Це просто здається автоматично згенерованим посиланням із коментарів коду.
Том Вілсон,

2
Однак приклад коду мода не зовсім вірний: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "color" ":" "yellow" "," "size" ":" "medium" "}")); var fruitJObject = foodJsonObj ["їжа"] ["фрукт"] як JObject; fruitJObject.Property ("апельсин"). AddAfterSelf (новий JProperty ("банан", bananaJson)); `
Том Вілсон,

Я не можу протягом усього життя застосовувати розмітку коду до свого попереднього коментаря - AARRGHH! Я використовував зворотні галочки та відступив 4 пробіли - як це зробити?
Том Вілсон,

5

Просто додавши .Firstдо вашого, bananaTokenслід це зробити: в основному рухається повз, щоб зробити його замість a .
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken

@ Брайан Роджерс, дякую, я забув .Parent. Відредаговано

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.