2016-07-30 7 views
2

Ich nehme an, dies ist ein weiterer Eintrag in meiner Reihe von Fragen, aber ich bin wieder fest. Dieses Mal, ich habe Probleme, die Arbeit mit einem JArray von JObjects und für jedes Element den Property.Value Typs Bestimmung in den JArray ...Abfrage und Filterung von JObjects mit Linq

Mein Code ist hier: https://dotnetfiddle.net/bRcSAQ

Der Unterschied zwischen meinem vorherigen Fragen und diese Frage ist, dass meine äußere Linq Abfrage beide JObject und JArray Token erhält, ist also, warum ich eine if (jo is JObject) bei Zeile 40 und eine if (jo is JArray) bei Line 48.

Sobald ich weiß, ich habe eine JArray von <JObjects>, ich habe Code, der so aussieht (Zeilen 48-):

if (jo is JArray) 
    { 
     var items = jo.Children<JObject>();      
     // return a JObject object 
    } 

Wenn ich einen Debugger verwende und Objekte betrachte, sehe ich, dass es 3 JObject-Objekte enthält - eines für Item_3A1, Item_3A2 und Item3A3. Aber ich muss den JTokenType für jeden JProperty.Value wissen, da ich nur an Property-Werten vom Typ JTokenType.String interessiert bin.

Also habe ich versucht:

// doesn't work :(
var items = jo.Children<JObject>() 
       .Where(p => p.Value.Type == JTokenType.String); 

Der Compiler roten Linien die Value-Eigenschaft mit dem Fehler CS0119 'JToken.Value<T>(object)' is a method, which is not valid in the given context.

Ich stelle fest, dass "p" in der Linq ausdrücklich kein JProperty ist. Ich denke, es ist ein JObject. Und ich weiß nicht, wie man "p" ausgibt, damit ich den Typ des JProperty-Objekts, das es repräsentiert, untersuchen kann.

Letztendlich brauche ich den Code für die JArray-Verarbeitung (ab Zeile 48), um ein JObject zurückzugeben, das ein JSON-Array enthält, das nur aus JProperty-Objekten vom Typ JTokenType.String besteht. Dies bedeutet, dass die Probe JSON gegeben, es zuerst eine JObject hält diese JSON Eigenschaften zurückgeben sollte:

{ ""Item_3A1"": ""Desc_3A1"" }, 
{ ""Item_3A2"": ""Desc_3A2"" }, 
{ ""Item_3A3"": ""Desc_3A3"" } 

Auf der nächsten Iteration, sollte es eine JObject halten diese JSON Eigenschaften zurückkehren (Beachten Sie, dass die verschachtelten Array3B1 Eigenschaften wegen weggelassen Array3B1 ist kein JProperty mit einem Werttyp von JTokenType.String):

{ ""Item_3B1"": ""Desc_3B1"" }, 
{ ""Item_3B2"": ""Desc_3B2"" }, 

Die dritte Iteration enthalten würde:

{ ""Item_3B11"": ""Desc_3B11"" }, 
{ ""Item_3B12"": ""Desc_3B12"" }, 
{ ""Item_3B13"": ""Desc_3B13"" } 

Und die vierte (letzte) Iteration würde enthalten:

Dies könnte meine letzte Hürde in dieser "Serie" sein.

Ein herzliches Dankeschön an alle, die helfen können und werden - und ein besonderer Dank nochmal an die Benutzer "Brian Rogers" und "dbc" für ihr wirklich erstaunliches JSON.NET/Linq-Wissen.

+0

Haben Sie versucht, p.Value zu machen. GetType()? –

+1

Ja, aber das hat nicht geholfen. Der Schlüssel war, SelectMany() zu verwenden und ein Where() an das Ende dieses Resultsets anzuheften. – Jazimov

Antwort

2

Dies erzeugt die Ausgabe, die Sie benötigen:

var root = (JContainer)JToken.Parse(json); 
var query = root.Descendants() 
    .Where(jt => (jt.Type == JTokenType.Object) || (jt.Type == JTokenType.Array)) 
    .Select(jo => 
     { 
      if (jo is JObject) 
      { 
       if (jo.Parent != null && jo.Parent.Type == JTokenType.Array) 
        return null; 
       // No help needed in this section    
       // populate and return a JObject for the List<JObject> result 
       // next line appears for compilation purposes only--I actually want a populated JObject to be returned 
       return new JObject(); 
      } 

      if (jo is JArray) 
      { 
       var items = jo.Children<JObject>().SelectMany(o => o.Properties()).Where(p => p.Value.Type == JTokenType.String); 
       return new JObject(items); 
      } 
      return null; 
     }) 
    .Where(jo => jo != null) 
    .ToList(); 

Ich verwende hier SelectMany() die verschachtelte Aufzählung der Eigenschaften der Aufzählung der untergeordneten Objekte von jo auf eine einzelne Aufzählung aller Eigenschaften von untergeordneten Objekten zu glätten.o => o.Properties() ist eine lambda expression Zuordnung der JObject o zu seiner Sammlung von Eigenschaften, und p => p.Value.Type == JTokenType.String ist ein weiteres Lambda Mapping eine Eigenschaft p (generiert von der vorherigen -Klausel) zu einem wahren/false-Wert, der angibt, ob die Eigenschaft einen String-Wert hat. Sowohl o als auch p sind Lambda-Eingangsparameter, die implicitly typed sind.

Im Abschnitt // No help needed in this section werden Objekte, deren Eltern Arrays sind, übersprungen, da sie von der Klausel (jo is JArray) erfasst werden.

Beachten Sie, dass der JObject-Konstruktor eine doppelte Schlüsselausnahme auslösen kann, wenn verschiedene untergeordnete Elemente des Arrays jo identische Eigenschaftennamen haben.

Forked fiddle.

+0

Ehrfürchtig, dbc. Also ist es richtig zu sagen, dass das o bezieht sich auf ein JObject (von Children()) und das p bezieht sich auf eine JProperty (von o.Properties())? Wenn ja, das war meine "fehlende Linq". :) – Jazimov

+0

In Ihren gegabelten Geige Ergebnisse (nach dem Ausführen), sehe ich leere Abfrage Elemente. Wie kann ich sie überspringen? Würde ich dem Linq-Ausdruck einen any() -Modifikator hinzufügen? Wenn ja, wo? – Jazimov

+1

@Jazimov - OK, es sieht so aus, als ob Sie im Abschnitt "Keine Hilfe benötigt" Hilfe benötigen. Ich würde empfehlen, alle Objekte zu überspringen, deren Eltern Arrays sind, da sie in der nachfolgenden 'if (jo is JAArray) -Klausel gesammelt werden. – dbc