Как добавить JToken в JObject?

86

Я пытаюсь добавить объект 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."

Я на самом деле пробовал несколько разных способов, но, похоже, ничего не добился. В моем примере я действительно хочу добавить новый элемент в "fruit". Пожалуйста, дайте мне знать, есть ли лучший способ сделать это или более простую библиотеку для использования.

Джим
источник

Ответы:

143

Я думаю, вы не понимаете, что может содержать то, что находится в JSON.Net.

  • A JToken- это общее представление любого значения JSON. Это может быть строка, объект, массив, свойство и т. Д.
  • A JProperty- это одно JTokenзначение в паре с именем. Его можно только добавить к a JObject, и его значение не может быть другим JProperty.
  • A JObject- это набор файлов JProperties. Он не может JTokenнапрямую удерживать какой-либо другой вид .

В вашем коде вы пытаетесь добавить JObject(тот, который содержит данные "банан") к JProperty("апельсину"), который уже имеет значение ( 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 .
Брайан Роджерс
37

TL; DR: вы должны добавить JProperty к JObject. Просто. Индексный запрос возвращает JValue, поэтому выясните, как вместо этого получить JProperty :)


Принятый ответ не отвечает на вопрос, как кажется. Что, если я хочу добавить свойство JProperty после определенного? Во-первых, давайте начнем с терминологии, которая действительно заставила меня задуматься.

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

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

На самом деле вы хотите получить все свойство целиком, а затем при желании добавить после него еще одно свойство. Для этого вы используете JOjbect.Property("name"), а затем создаете другое свойство JP по вашему желанию, а затем добавляете его после этого AddAfterSelfметода using . Тогда все готово.

Для получения дополнительной информации: 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, представляющим строку, число, логическое значение, дату или значение NULL; он не может представлять массив или объект. См. Справочник по API LINQ-to-JSON .
Брайан Роджерс
1
@BrianRogers Спасибо, я исправил терминологию.
Гасан,
1
Это очень хорошее объяснение объектной модели Newtonsoft, и теперь я могу лучше понять newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm . До сих пор мои попытки использовать его затруднялись из-за отсутствия подробных объяснений в документации. Это просто похоже на автоматически созданную ссылку из комментариев кода.
Tom Wilson
2
Однако мод в примере кода не совсем правильный: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "цвет" ":" "желтый" "," "размер" ":" "средний" "}"); var fruitJObject = foodJsonObj ["еда"] ["фрукты"] как JObject; fruitJObject.Property («апельсин»). AddAfterSelf (новый JProperty («банан», bananaJson)); `
Том Уилсон
Я не могу, хоть убей, применить разметку кода к моему предыдущему комментарию - AARRGHH! Я использовал обратные галочки и отступил 4 пробела - как мне это сделать?
Том Уилсон
5

Просто добавив .Firstк вашемуbananaToken должно сделать это: в основном проходит мимо, чтобы сделать его вместо .
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken

@ Брайан Роджерс, спасибо, я забыл .Parent. Отредактировано

RepDbg
источник