Come si aggiunge un JToken a un JObject?


86

Sto cercando di aggiungere un oggetto JSON da un testo a un file JSON esistente utilizzando JSON.Net. Ad esempio, se ho i dati JSON come di seguito:

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

Ho provato a farlo in questo modo:

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

Ma questo dà l'errore: "Newtonsoft.Json.Linq.JProperty cannot have multiple values."

In realtà ho provato diversi modi ma non riesco ad arrivare da nessuna parte. Nel mio esempio quello che voglio veramente fare è aggiungere il nuovo elemento a "frutta". Per favore fatemi sapere se c'è un modo migliore per farlo o una libreria più semplice da usare.

Risposte:


143

Penso che ti stia confondendo su cosa può contenere cosa in JSON.Net.

  • A JTokenè una rappresentazione generica di un valore JSON di qualsiasi tipo. Potrebbe essere una stringa, un oggetto, un array, una proprietà, ecc.
  • A JPropertyè un singolo JTokenvalore abbinato a un nome. Può essere aggiunto solo a JObjecte il suo valore non può essere un altro JProperty.
  • A JObjectè una raccolta di JProperties. Non può trattenere nessun altro tipo di JTokendirettamente.

Nel tuo codice, stai tentando di aggiungere un JObject(quello contenente i dati "banana") a un JProperty("arancione") che ha già un valore (un JObjectcontenente{"colour":"orange","size":"large"} ). Come hai visto, questo risulterà in un errore.

Quello che vuoi veramente fare è aggiungere una JPropertycosiddetta "banana" alla JObjectquale contiene l'altro frutto JProperties. Ecco il codice rivisto:

JObject foodJsonObj = JObject.Parse(jsonText);
JObject fruits = foodJsonObj["food"]["fruit"] as JObject;
fruits.Add("banana", JObject.Parse(@"{""colour"":""yellow"",""size"":""medium""}"));

7
Nota: utilizza "JToken.Parse" (o "JToken.FromObject") invece di JObject.Parse, sull'ultima riga. Poiché funziona anche per oggetti semplici come string.
ctrl-alt-delor

cosa fare se voglio sovrascrivere un file Jproperty.
Daniel

@Daniel - Se con "sovrascrivi" intendi sostituire completamente il JPropertycon uno diverso, puoi utilizzare il Replacemetodo. Se vuoi solo cambiare il valore di JProperty, puoi impostare la Valueproprietà su di esso; è scrivibile. Vedi il riferimento all'API LINQ-to-JSON .
Brian Rogers

37

TL; DR: dovresti aggiungere una JProperty a un JObject. Semplice. La query dell'indice restituisce un JValue, quindi scopri come ottenere invece JProperty :)


La risposta accettata non è rispondere alla domanda come sembra. E se volessi aggiungere in modo specifico una JProperty dopo una specifica? Innanzitutto, iniziamo con le terminologie che mi hanno davvero fatto girare la testa.

  • JToken = La madre di tutti gli altri tipi. Può essere A JValue, JProperty, JArray o JObject. Questo per fornire un design modulare al meccanismo di analisi.
  • JValue = qualsiasi tipo di valore Json (stringa, int, booleano).
  • JProperty = qualsiasi JValue o JContainer (vedi sotto) abbinato a un nome (identificatore) . Ad esempio "name":"value".
  • JContainer = La madre di tutti i tipi che contengono altri tipi (JObject, JValue).
  • JObject = un tipo JContainer che contiene una raccolta di JProperties
  • JArray = un tipo JContainer che contiene una raccolta JValue o JContainer.

Ora, quando si interroga l'elemento Json utilizzando l'indice [], si ottiene il JToken senza l'identificatore, che potrebbe essere un JContainer o un JValue (richiede il casting), ma non è possibile aggiungere nulla dopo di esso, perché è solo un valore. Puoi modificarlo da solo, interrogare valori più profondi, ma non puoi aggiungere nulla dopo di esso, ad esempio.

Ciò che si desidera effettivamente ottenere è la proprietà nel suo insieme, quindi aggiungere un'altra proprietà dopo di essa come desiderato. Per questo, usi JOjbect.Property("name")e quindi crei un'altra JProperty di tuo desiderio e poi aggiungila dopo questo utilizzoAddAfterSelf metodo . Allora hai finito.

Per maggiori informazioni: http://www.newtonsoft.com/json/help/html/ModifyJson.htm

Questo è il codice che ho modificato.

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
Hai sbagliato la tua terminologia. JToken(non JValue) è la classe base da cui JArray, JObject, JPropertye JValueereditano. JValueè una primitiva JSON che rappresenta una stringa, un numero, un valore booleano, una data o un valore nullo; non può rappresentare un array o un oggetto. Vedere il riferimento all'API LINQ-to-JSON .
Brian Rogers

1
@BrianRogers Grazie, ho corretto la terminologia.
Ghasan

1
Questa è un'ottima spiegazione del modello a oggetti di Newtonsoft e ora sono in grado di comprendere molto meglio newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm . Finora i miei sforzi per utilizzarlo sono stati ostacolati dalla mancanza di spiegazioni dettagliate nei documenti. Sembra solo essere un riferimento generato automaticamente dai commenti del codice.
Tom Wilson,

2
Tuttavia, il mod di esempio di codice non è corretto: `var foodJsonObj = JObject.Parse (jsonText); var bananaJson = JObject.Parse (@ "{" "color" ":" "yellow" "," "size" ":" "medium" "}"); var fruitJObject = foodJsonObj ["cibo"] ["frutto"] come JObject; fruitJObject.Property ("orange"). AddAfterSelf (new JProperty ("banana", bananaJson)); `
Tom Wilson,

Per tutta la vita non posso applicare il markup del codice al mio commento precedente - AARRGHH! Ho usato zecche indietro e 4 spazi rientrati, come posso farlo?
Tom Wilson,

5

Basta aggiungere .Firstal tuo bananaTokendovrebbe farlo: fondamentalmente si sposta oltre il per renderlo a invece di a
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken .First);
.First{JPropertyJToken .

@ Brian Rogers, grazie ho dimenticato il .Parent. Modificato

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.