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

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

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

Ответ 1

Я думаю, вы сбиты с толку о том, что можно сохранить в JSON.Net.

  • A JToken - это общее представление значения JSON любого типа. Это может быть строка, объект, массив, свойство и т.д.
  • A JProperty - это одно значение JToken в паре с именем. Он может быть добавлен только в 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""}"));

Ответ 2

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 с помощью индекса [], вы получаете 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);
    }
  }
}

Ответ 3

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

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