2013-03-14 28 views
53

Sto cercando di aggiungere un oggetto JSON da un testo a un file JSON esistente utilizzando JSON.Net. Per esempio, se ho i dati JSON, come di seguito:Come si aggiunge un JToken a un JObject?

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

ho cercato di 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."

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

risposta

100

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

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

Nel codice, si sta tentando di aggiungere un JObject (quello che contiene i dati "banana") ad un JProperty ("arancione"), che ha già un valore (un JObject contenente {"colour":"orange","size":"large"}). Come hai visto, questo si tradurrà in un errore.

Quello che si vuole veramente fare è aggiungere uno JProperty chiamato "banana" al JObject che 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: Usa 'JToken.Parse' (o 'JToken.FromObject') al posto di 'JObject.Parse', in ultima riga. Come questo funziona anche per oggetti semplici come la stringa. –

+0

cosa fare se voglio sovrascrivere una Jproperty. – Daniel

+0

@Daniel - Se per "sovrascrivere" si intende sostituire completamente 'JProperty' con uno diverso, è possibile utilizzare il metodo' Sostituisci'. Se si desidera solo modificare il valore di 'JProperty', è possibile impostare la proprietà' Value' su di esso; è scrivibile. Consulta il [riferimento API LINQ-to-JSON] (https://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm). –

3

Solo l'aggiunta di .First al bananaToken dovrebbe farlo:
foodJsonObj["food"]["fruit"]["orange"].Parent.AddAfterSelf(bananaToken.First);
.First muove fondamentalmente oltre il { per renderlo un JProperty anziché JToken.

@Brian Rogers, Grazie Ho dimenticato il .Parent. Modificato

+0

Siamo spiacenti, questo non funziona. Vedi https://dotnetfiddle.net/qJDISd. Per farlo funzionare come hai suggerito, dovresti usare '.Parent' prima di' .AddAfterSelf() '. –

24

TL; DR: È necessario aggiungere una JProperty a un JObject. Semplice. La query restituisce un indice di JValue, in modo da capire come ottenere il JProperty invece :)


La risposta accettata non risponde alla domanda come sembra. Cosa succede se voglio aggiungere specificamente una JProperty dopo una specifica? Innanzitutto, iniziamo con terminologie che hanno davvero funzionato.

  • 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 (string, int, booleano).
  • JProperty = qualsiasi JValue o JContainer (vedere di seguito) 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 esegue una query oggetto JSON utilizzando l'indice [], si stanno ottenendo il JToken, senza l'identificatore, che potrebbe essere un JContainer o un JValue (richiede casting), ma non si può aggiungere nulla dopo che, a causa è solo un valore. Puoi cambiarlo da solo, interrogare più valori profondi, ma non puoi aggiungere nulla dopo di esso, ad esempio.

Ciò che in realtà si desidera ottenere è la proprietà come intera, quindi aggiungere un'altra proprietà dopo di essa come desiderato. Per questo, si utilizza JOjbect.Property("name"), quindi si crea un altro JProperty del proprio desiderio e quindi lo si aggiunge dopo aver utilizzato il metodo AddAfterSelf. Allora hai finito.

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

Questo è il codice 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); 
    } 
    } 
} 
+3

Hai sbagliato la terminologia. 'JToken' (non' JValue') è la classe base da cui 'JArray',' JObject', 'JProperty' e' JValue' in definitiva ereditano. 'JValue' è una primitiva JSON che rappresenta una stringa, un numero, un valore booleano, una data o un valore nullo; non può rappresentare una matrice o un oggetto. Consulta il [Riferimento API LINQ-to-JSON] (http://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm). –

+1

@BrianRogers Grazie, ho risolto la terminologia. –

+0

Questa è un'ottima spiegazione del modello di oggetti Newtonsoft e ora sono in grado di capire molto meglio http://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Linq.htm. Fino ad ora i miei sforzi per usarlo sono stati ostacolati dalla mancanza di una spiegazione dettagliata nei documenti. Sembra solo essere un riferimento generato automaticamente dai commenti del codice. –

Problemi correlati