Wie fügt man einem JObject ein JToken hinzu?

84

Ich versuche, mit JSON.Net ein JSON-Objekt aus einem Text zu einer vorhandenen JSON-Datei hinzuzufügen. Zum Beispiel, wenn ich die folgenden JSON-Daten habe:

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

Ich habe versucht, dies so zu machen:

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

Aber das gibt den Fehler: "Newtonsoft.Json.Linq.JProperty cannot have multiple values."

Ich habe tatsächlich ein paar verschiedene Wege ausprobiert, komme aber anscheinend nicht weiter. In meinem Beispiel möchte ich den neuen Artikel wirklich zu "Obst" hinzufügen. Bitte lassen Sie mich wissen, ob es einen besseren Weg gibt, dies zu tun, oder ob eine einfachere Bibliothek zu verwenden ist.

Jim
quelle

Antworten:

139

Ich denke, Sie werden verwirrt darüber, was was in JSON.Net halten kann.

  • A JTokenist eine generische Darstellung eines JSON-Werts jeglicher Art. Es kann sich um eine Zeichenfolge, ein Objekt, ein Array, eine Eigenschaft usw. handeln.
  • A JPropertyist ein einzelner JTokenWert, der mit einem Namen gepaart ist. Es kann nur zu a hinzugefügt werden JObject, und sein Wert kann kein anderer sein JProperty.
  • A JObjectist eine Sammlung von JProperties. Es kann keine andere Art von JTokendirekt halten.

In Ihrem Code versuchen Sie, ein JObject(das die "Bananen" -Daten enthält) einem JProperty("orange") hinzuzufügen, das bereits einen Wert (ein JObjectenthält {"colour":"orange","size":"large"}) hat. Wie Sie gesehen haben, führt dies zu einem Fehler.

Was Sie wirklich tun möchten, ist eine JPropertysogenannte "Banane" zu der hinzuzufügen , die JObjectdie anderen Früchte enthält JProperties. Hier ist der überarbeitete Code:

JObject foodJsonObj = JObject.Parse(jsonText);
JObject fruits = foodJsonObj["food"]["fruit"] as JObject;
fruits.Add("banana", JObject.Parse(@"{""colour"":""yellow"",""size"":""medium""}"));
Brian Rogers
quelle
7
Hinweis: Verwenden Sie 'JToken.Parse' (oder 'JToken.FromObject') anstelle von JObject.Parsein der letzten Zeile. Da dies auch für einfache Objekte wie String funktioniert.
Strg-Alt-Delor
Was tun, wenn ich eine Eigenschaft überschreiben möchte?
Daniel
@Daniel - Wenn Sie mit "überschreiben" das vollständig durch JPropertyein anderes ersetzen möchten , können Sie die ReplaceMethode verwenden. Wenn Sie nur den Wert von ändern möchten JProperty, können Sie die ValueEigenschaft darauf festlegen . es ist beschreibbar. Siehe die LINQ-to-JSON-API-Referenz .
Brian Rogers
35

TL; DR: Sie sollten einem JObject eine JProperty hinzufügen. Einfach. Die Indexabfrage gibt einen JValue zurück. Finden Sie also heraus, wie Sie stattdessen die JProperty erhalten können :)


Die akzeptierte Antwort beantwortet die Frage anscheinend nicht. Was ist, wenn ich eine JProperty nach einer bestimmten hinzufügen möchte? Beginnen wir zunächst mit Terminologien, die mir wirklich den Kopf verdreht haben.

  • JToken = Die Mutter aller anderen Typen. Dies kann A JValue, JProperty, JArray oder JObject sein. Dies dient dazu, dem Parsing-Mechanismus einen modularen Aufbau zu verleihen.
  • JValue = ein beliebiger Json-Werttyp (Zeichenfolge, Int, Boolescher Wert).
  • JProperty = jeder JValue oder JContainer (siehe unten), gepaart mit einem Namen (Bezeichner) . Zum Beispiel "name":"value".
  • JContainer = Die Mutter aller Typen, die andere Typen enthalten (JObject, JValue).
  • JObject = ein JContainer-Typ, der eine Sammlung von JProperties enthält
  • JArray = ein JContainer-Typ, der eine Sammlung JValue oder JContainer enthält.

Wenn Sie jetzt ein Json-Element mit dem Index [] abfragen, erhalten Sie das JToken ohne den Bezeichner, bei dem es sich möglicherweise um einen JContainer oder einen JValue handelt (erfordert Casting), aber Sie können danach nichts hinzufügen, da es sich nur um einen Wert handelt. Sie können es selbst ändern, tiefere Werte abfragen, aber Sie können beispielsweise nichts danach hinzufügen.

Was Sie tatsächlich erhalten möchten, ist die Eigenschaft als Ganzes, und fügen Sie danach nach Wunsch eine weitere Eigenschaft hinzu. Dazu verwenden Sie JOjbect.Property("name")eine weitere JProperty Ihres Wunsches, erstellen diese und fügen sie anschließend mit der AddAfterSelfMethode hinzu. Sie sind dann fertig.

Für weitere Informationen: http://www.newtonsoft.com/json/help/html/ModifyJson.htm

Dies ist der Code, den ich geändert habe.

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
quelle
4
Sie haben Ihre Terminologie falsch. JToken(nicht JValue) ist die Basisklasse , von der JArray, JObject, JPropertyund JValueschließlich erbt. JValueist ein JSON-Grundelement, das eine Zeichenfolge, eine Zahl, einen Booleschen Wert, ein Datum oder einen Nullwert darstellt. Es kann kein Array oder Objekt darstellen. Siehe die LINQ-zu-JSON-API-Referenz .
Brian Rogers
1
@BrianRogers Danke, ich habe die Terminologie korrigiert.
Ghasan
1
Dies ist eine sehr gute Erklärung des Newtonsoft-Objektmodells, und ich kann newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm jetzt viel besser verstehen . Bisher wurden meine Bemühungen, es zu verwenden, durch das Fehlen detaillierter Erklärungen in den Dokumenten behindert. Es scheint nur eine automatisch generierte Referenz aus Codekommentaren zu sein.
Tom Wilson
2
Codebeispiel mod ist jedoch nicht ganz richtig: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "Farbe" ":" "gelb" "," "Größe" ":" "mittel" "}"); var obstJObject = foodJsonObj ["Essen"] ["Frucht"] als JObject; ruitJObject.Property ("orange"). AddAfterSelf (neue JProperty ("banana", bananaJson)); `
Tom Wilson
Ich kann für mein ganzes Leben kein Code-Markup auf meinen vorherigen Kommentar anwenden - AARRGHH! Ich habe Back Ticks verwendet und 4 Leerzeichen eingerückt - wie mache ich das?
Tom Wilson
5

Nur das Hinzufügen .Firstzu Ihrem bananaTokensollte es tun: bewegt sich im Grunde an dem vorbei , um es zu einem statt zu einem zu machen .
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken

@ Brian Rogers, danke ich habe das vergessen .Parent. Bearbeitet

RepDbg
quelle