Jak dodać JToken do JObject?

84

Próbuję dodać obiekt JSON z jakiegoś tekstu do istniejącego pliku JSON przy użyciu JSON.Net. Na przykład, jeśli mam dane JSON jak poniżej:

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

Próbowałem to zrobić w ten sposób:

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

Ale to daje błąd: "Newtonsoft.Json.Linq.JProperty cannot have multiple values."

Właściwie wypróbowałem kilka różnych sposobów, ale nie wydaje mi się, żebym to osiągnął. W moim przykładzie to, co naprawdę chciałbym zrobić, to dodać nowy element do „owoców”. Daj mi znać, jeśli istnieje lepszy sposób na zrobienie tego lub prostsza biblioteka.

Jim
źródło

Odpowiedzi:

139

Myślę, że nie wiesz, co może przechowywać dane w JSON.Net.

  • A JTokento ogólna reprezentacja dowolnej wartości JSON. Może to być ciąg znaków, obiekt, tablica, właściwość itp.
  • A JPropertyto pojedyncza JTokenwartość sparowana z nazwą. Można go dodać tylko do a JObject, a jego wartość nie może być inna JProperty.
  • A JObjectto zbiór plików JProperties. Nie może zawierać żadnego innego rodzaju JTokenbezpośrednio.

W swoim kodzie próbujesz dodać JObject(ten zawierający dane „banana”) do JProperty(„orange”), który ma już wartość ( JObjectzawiera {"colour":"orange","size":"large"}). Jak widziałeś, spowoduje to błąd.

To, co naprawdę chcesz zrobić, to dodać JPropertyzwanego „banana” do tego, JObjectktóry zawiera drugi owoc JProperties. Oto poprawiony kod:

JObject foodJsonObj = JObject.Parse(jsonText);
JObject fruits = foodJsonObj["food"]["fruit"] as JObject;
fruits.Add("banana", JObject.Parse(@"{""colour"":""yellow"",""size"":""medium""}"));
Brian Rogers
źródło
7
Uwaga: użyj „JToken.Parse” (lub „JToken.FromObject”) zamiast JObject.Parsew ostatnim wierszu. Ponieważ działa to również w przypadku prostych obiektów, takich jak string.
ctrl-alt-delor
co zrobić, jeśli chcę nadpisać Jproperty.
Daniel
@Daniel - Jeśli przez "nadpisanie" masz na myśli całkowite zastąpienie JPropertyinnego, możesz użyć tej Replacemetody. Jeśli chcesz tylko zmienić wartość elementu JProperty, możesz ustawić na nim Valuewłaściwość; jest zapisywalny. Zobacz dokumentację interfejsu API LINQ-to-JSON .
Brian Rogers
35

TL; DR: Powinieneś dodać JProperty do JObject. Prosty. Zapytanie indeksujące zwraca JValue, więc dowiedz się, jak zamiast tego uzyskać JProperty :)


Przyjęta odpowiedź nie odpowiada na pytanie, jak się wydaje. A jeśli chcę konkretnie dodać JProperty po konkretnym? Po pierwsze, zacznijmy od terminologii, która naprawdę przykuła moją głowę.

  • JToken = matka wszystkich innych typów. Może to być JValue, JProperty, JArray lub JObject. Ma to na celu zapewnienie modułowej konstrukcji mechanizmu analizowania.
  • JValue = dowolny typ wartości Json (string, int, boolean).
  • JProperty = dowolna JValue lub JContainer (patrz poniżej) w połączeniu z nazwą (identyfikatorem) . Na przykład "name":"value".
  • JContainer = Matka wszystkich typów, które zawierają inne typy (JObject, JValue).
  • JObject = typ JContainer, który zawiera kolekcję JProperties
  • JArray = typ JContainer, który zawiera kolekcję JValue lub JContainer.

Teraz, gdy odpytujesz element Json za pomocą indeksu [], otrzymujesz JToken bez identyfikatora, którym może być JContainer lub JValue (wymaga rzutowania), ale nie możesz nic dodać po nim, ponieważ jest to tylko wartość. Możesz go zmienić samodzielnie, zapytać o głębsze wartości, ale nie możesz na przykład nic dodać po nim.

W rzeczywistości chcesz uzyskać właściwość jako całość, a następnie dodaj kolejną właściwość po niej zgodnie z potrzebami. W tym celu używasz JOjbect.Property("name"), a następnie tworzysz kolejną JProperty według własnego uznania, a następnie dodajesz ją po tej AddAfterSelfmetodzie. Jesteś skończony.

Więcej informacji: http://www.newtonsoft.com/json/help/html/ModifyJson.htm

To jest kod, który zmodyfikowałem.

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);
    }
  }
}
Ghasan
źródło
4
Masz błędną terminologię. JToken(nie JValue) jest klasą bazową, z której JArray, JObject, JPropertyi JValueostatecznie dziedziczy. JValuejest prymitywem JSON, który reprezentuje ciąg, liczbę, wartość logiczną, datę lub wartość null; nie może reprezentować tablicy ani obiektu. Zobacz dokumentację interfejsu API LINQ-to-JSON .
Brian Rogers
1
@BrianRogers Dzięki, poprawiłem terminologię.
Ghasan
1
To jest bardzo dobre wyjaśnienie modelu obiektów Newtonsoft i teraz jestem w stanie znacznie lepiej zrozumieć newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm . Do tej pory moje wysiłki, aby go użyć, były utrudnione przez brak szczegółowych wyjaśnień w dokumentacji. Po prostu wydaje się, że jest to automatycznie wygenerowane odniesienie z komentarzy do kodu.
Tom Wilson,
2
Jednak przykładowy mod nie jest całkiem poprawny: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "color" ":" "yellow" "," "size" ":" "medium" "}"); var fruitJObject = foodJsonObj ["food"] ["fruit"] jako JObject; fruitJObject.Property ("pomarańczowy"). AddAfterSelf (nowy JProperty ("banana", bananaJson)); `
Tom Wilson
Nie mogę przez całe życie zastosować znaczników kodu do mojego poprzedniego komentarza - AARRGHH! Użyłem tylnych znaczników i 4 wcięć - jak to zrobić?
Tom Wilson,
5

Po prostu dodanie .Firstdo swojego bananaTokenpowinno to zrobić: w zasadzie przesuwa się poza, aby zrobić to zamiast a .
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken

@Brian Rogers, Dzięki, zapomniałem .Parent. Edytowano

RepDbg
źródło