Laden...

Vom JArray zur .NET-Collection

Letzter Beitrag vor 10 Jahren 10 Posts 2.970 Views
Vom JArray zur .NET-Collection

Hallo,

ich habe eine JSON-Datei, die so aussieht:

{
  "Buch": [
    {
      "AutorName": "Sayers, Dorothy L.",
      "Titel": "Clouds of witness",
      "BuchID": 1,
      "Inhalt": "Diamantkatze, Parker begegnet Lady Mary"
    },
...
	{
      "AutorName": "Tremayne, Peter",
      "Titel": "Valley of the shadow",
      "BuchID": 32,
      "Inhalt": "33 tote junge M\u00e4nner, Ritualmord?"
    }
  ],
  "Autor": [
    {
      "Stamm": "Peter Wimsey, Charles Parker, Harriet Vane, Mervyn Bunter",
      "AutorName": "Sayers, Dorothy L.",
      "AutorID": 1
    },
...
	{
      "Stamm": "Fidelma von Cashel, Eadulf von Seaxmund's Ham",
      "AutorName": "Tremayne, Peter",
      "AutorID": 6
    }
  ]
}

Klassen für diese Daten habe ich auch. Um die Datei auszuwerten, benutze ich Newtonsoft.Json.NET, und da bin ich an einer Stelle nicht absolut zufrieden mit dem, was ich der Json.NET-Dokumentation bisher entnommen habe.

Was ich suche: ich möchte einen JArray in einem Stück in eine .NET-Collection überführen, ohne den Umweg über einen String zu gehen. Und dafür finde ich nichts in der Dokumentation.

Der Code, den ich bisher habe, sieht so aus:


static void KrimisAuswerten(string jsonname)
{
	JObject alles;
	using (StreamReader rdr = new StreamReader(jsonname))
	{
		JsonTextReader jsonrdr = new JsonTextReader(rdr);
		alles = (JObject)JToken.ReadFrom(jsonrdr);
	}

	// Die nächste Zeile missfällt mir, Kommentar s. unten
	string autext = alles.SelectToken("Autor").ToString();
	ICollection<Autor> autoren = JsonConvert.DeserializeObject<ICollection<Autor>>(autext);
	
	JArray buecher = (JArray)alles.SelectToken("Buch");
	List<Buch> AlleBuecher = new List<Buch>();
	foreach (dynamic buch in buecher)
	{
		Autor au = autoren.Single(a => a.AutorName == buch.AutorName.ToString());
		Buch neu = new Buch
		{
			BuchID = buch.BuchID,
			Titel = buch.Titel,
			Inhalt = buch.Inhalt,
			AutorID = au.AutorID,
			Autor = au
		};
		AlleBuecher.Add(neu);
	}
	foreach (Buch b in AlleBuecher)
	{
		Console.WriteLine(b.MitAutorToString());
	}
}

Was mir daran nicht gefällt: entweder ich muss meine Autorenliste, die ja schon Teil eines JObjects ist, in einen String zurückverwandeln, um sie dann mit DeserializeObject<ICollection<Autor>> als Ganzes in eine .NET-Collection umzuwandeln. Oder aber ich interpretiere sie gleich als JArray, wie ich es weiter unten mit der Bücherliste mache. Aber dann müsste ich jeden Satz einzeln in ein Autor-Objekt umwandeln und in meine Collection schreiben. Das ist bei der Bücherliste unproblematisch, weil ich da sowieso jeden Satz anfassen muss, um die AutorID zu ermitteln. Bei der Autorenliste wäre es unnötig.

Bin ich bloß nicht imstande, der Dokumentation ein besseres Vorgehen zu entnehmen, gibt es mehr Material zu Json.NET, das ich nicht gefunden habe, oder geht das nicht, was ich möchte?

Wieso willst Du ein JArray statt es ordentlich über eine C# Klasse zu machen, wenn die Struktur eh fest ist?
Was erhoffst Du Dir dabei? So musst Du ja alles doppelt machen.

Ich versuche die Frage umzuformulieren, vielleicht wird es dann klarer: So, wie die Funktion augenblicklich ist, wandle ich zwar mit "DeserializeObject" den String mit den Autoren-Daten in einem Rutsch in die Liste um, die ich brauche, aber vorher habe ich die kompletten Daten in das JObject "alles" eingelesen,
daraus mit "SelectToken" den Teil mit den Autorendaten herausgeholt und in ein JToken gepackt, das namenlos bleibt,
dieses JToken in den String "autext" umgewandelt.

Und was ich gerne hätte: eine direkte Umwandlung des Ergebnisses von SelectToken in eine ICollection<Autor>, ohne ToString() zwischendrin. Dass dabei dieses Ergebnis als ein JArray interpretiert werden müsste, war eine Vermutung und ist nicht weiter wichtig.

Und wieso nicht so:

Buch myBook = JsonConvert.DeserializeObject< Book >( jsonString );

Dann hast Du das Json, das ein Buch repräsentiert, in einer POCO (Entität) Klasse in einem Rutsch und feritg.
Ich versteh nicht, wieso Du so einen Aufwand machen willst 🤔

Wenn das Json keine Entität darstellt, sondern nur Du diese erst zusammen bauen musst (zB wegen irgendwelchen ID-Referenzen), dann nimm mein Beispiel als DTO

BuchDTO myBookDTO = JsonConvert.DeserializeObject< BookDTO >( jsonString );

Und arbeite dann managed mit .NET Objekten weiter um die Entität Book zu erstellen.
Aber sich mit JArray und JObject rum zu schlagen: wär mir zu unsicher, da untypisiert bzw auf Deutsch: zu doof 😉

Du sollst nicht erzählen wie du das was du vor hast in java gelöst hättest, sondern du sollst sagen was du als ergebnis haben willst.

Dein Weg ist etwas, sagen wir es vorsichtig, typisch Java, over-architected.

Und wieso nicht so:

Buch myBook = JsonConvert.DeserializeObject< Book >( jsonString );  

Dann hast Du das Json, das ein Buch repräsentiert, in einer POCO (Entität) Klasse in einem Rutsch und feritg.
Ich versteh nicht, wieso Du so einen Aufwand machen willst 👶

Wenn das Json keine Entität darstellt, sondern nur Du diese erst zusammen bauen musst (zB wegen irgendwelchen ID-Referenzen), dann nimm mein Beispiel als DTO

BuchDTO myBookDTO = JsonConvert.DeserializeObject< BookDTO >( jsonString );  

Und arbeite dann managed mit .NET Objekten weiter um die Entität Book zu erstellen.
Aber sich mit JArray und JObject rum zu schlagen: wär mir zu unsicher, da untypisiert bzw auf Deutsch: zu doof 😉

Ich bin jetzt auf json2csharp gestoßen und habe das mal auf meinen Json-Text losgelassen. Da habe ich alle nötigen DTO-Klassen auf einen Sitz samt Root-Objekt, in das ich den kompletten Text deserialisieren kann. Das ist natürlich ganz nett, andererseits kriege ich auf diese Weise doppelt so viele Klassen wie ich eigentlich brauche, weil nur die Autor-Klasse direkt verwendet werden kann. Das muss man wohl je nach Anwendungsfall abwägen.

Du sollst nicht erzählen wie du das was du vor hast in java gelöst hättest, sondern du sollst sagen was du als ergebnis haben willst.

Dein Weg ist etwas, sagen wir es vorsichtig, typisch Java, over-architected.

Wenn ich das auch nur annähernd richtig verstehe, hast Du meinen zweiten Beitrag ganz falsch verstanden: das sollte eine Beschreibung dessen sein, was der Beispiel-Code im ersten Beitrag tut (von Java war hier im übrigen nie die Rede), bevor er mir einen String liefert, der in eine Autorenliste deserialisiert werden kann. Das war der Versuch, zu erklären, warum ich ihn als umständlich und ein Hin-und-Her empfinde. Und was ich gern hätte, habe ich im übrigen auch gesagt.

Wenn du dir deinen Beitrag nochmal durchliest, sagtst du genau wie du es machen willst, nicht was es ergeben soll.

Du willst doch eigentlich "nur" aus dem JSON die Liste der Autoren haben.

Ja, aber eben auf eine weniger umständliche Weise als mit dem Code, den ich bisher habe. Es geht also nicht um ein Ergebnis, das ich bekommen will und bisher nicht bekomme, sondern um eine bessere Methode, an eben dieses Ergebnis zu kommen.

Was ich beschrieben habe, ist nicht, wie ich es machen will, sondern wie ich es mache, weil mir nichts Besseres eingefallen ist.

Das problem ist doch, das man durch den ganzen Text ( der in eine Zeile gepasst hätte ) den einfachen Teil leicht übersieht.

Und weil du es so Blumig schreibst und auch diese vorgehensweise als erstes benutzt bin ich von einem Java Vorleben ausgegangen.

Aber wie du ja selber schon gemerkt hast, Klassen erstellen, deserialisieren und dann per LinQ ist deutlich "einfacher"