2016-07-20 11 views
0

Ich habe eine polymorphe JSON-Zeichenfolge. Hier ist, wie es aussieht:LINQ zu JSON - Setup-Liste von verschiedenen Arrays

{ 
    "Product" : { 
     "Context" : { 
      "IssuerDetails" : { 
       "Issuer" : { 
        "@clientCode" : "BMTEST-CA", 
        "@companyName" : "zTest BM Company, Inc", 
        "@companyId" : "1", 
        "IssuerChanges" : [{ 
          "@type" : "Book Value", 
          "@previous" : "$9.06", 
          "@current" : "$55.34" 
         }, { 
          "@type" : "Price Target", 
          "@previous" : "$50.00", 
          "@current" : "$199.00" 
         }, { 
          "@type" : "EPS", 
          "@previous" : "2.10", 
          "@current" : "2.09", 
          "@period" : "5", 
          "@year" : "2017" 
         }, { 
          "@type" : "Income Tax", 
          "@previous" : "56", 
          "@current" : "55", 
          "@period" : "5", 
          "@year" : "2015" 
         } 
        ], 
        "SecurityDetails" : { 
         "Security" : { 
          "@primaryIndicator" : "Yes", 
          "Clusters" : [{ 
            "@name" : "Company Data", 
            "@rank" : "2", 
            "FinancialValue" : [{ 
              "@financialsType" : "Dividend", 
              "CurrentValue" : { 
               "@displayValue" : "$5.02", 
              } 
             }, { 
              "@financialsType" : "Book Value", 
              "CurrentValue" : { 
               "@displayValue" : "$55.34", 
              }, 
              "PreviousValue" : { 
               "@displayValue" : "$9.06", 
               "@type" : "INCREASE", 
              } 
             } 
            ] 
           }, { 
            "@rank" : "1", 
            "@name" : "AAPL & Market Data", 
            "FinancialValue" : [{ 
              "@financialsType" : "Rating", 
              "@shortCode" : "Mkt", 
              "CurrentValue" : { 
               "@displayValue" : "Market Perform", 
              } 
             }, { 
              "@financialsType" : "Rating Qualifier", 
              "CurrentValue" : { 
               "@displayValue" : "Speculative", 
              } 
             } 
            ] 
           } 
          ] 
         } 
        } 
       } 
      } 
     } 
    } 
} 

Ich verwende die folgende Erweiterung Klasse:

public static class JsonExtensions 
{ 
    public static IEnumerable<JObject> ObjectsOrSelf(this JToken root) 
    { 
     if (root is JObject) 
      yield return (JObject)root; 
     else if (root is JContainer) 
      foreach (var item in ((JContainer)root).Children()) 
       foreach (var child in item.ObjectsOrSelf()) 
        yield return child; 
     else 
      yield break; 
    } 
} 

Auf dieser Grundlage ist hier meine Frage:

JObject feed = JObject.Parse(jsonText); 

var compInfo = from issuer in feed.SelectTokens("Product.Context.IssuerDetails.Issuer").SelectMany(i => i.ObjectsOrSelf()) 
     let issuerChanges = issuer.SelectTokens("IssuerChanges").SelectMany(s => s.ObjectsOrSelf()) 
     where issuerChanges != null 
     let finValues = issuer.SelectTokens("SecurityDetails.Security.Clusters").SelectMany(s => s.ObjectsOrSelf()) 
     where finValues != null 
     select new 
     { 
      Id = (int)issuer["@companyId"], 
      BMOTicker = (string)issuer["@clientCode"], 
      CompName = (string)issuer["@companyName"], 
      ChngsType = issuerChanges.Select(c => (string)c["@type"]), 
      PrevChng = issuerChanges.Select(c => (string)c["@previous"]), 
      CurrChng = issuerChanges.Select(c => (string)c["@current"]), 
      Period = issuerChanges.Select(c => (string)c["@period"]), 
      Year = issuerChanges.Select(c => (string)c["@year"]), 
      FinValueName = finValues.Select(c => (string)c["@financialsType"]) 
    }; 

Wenn ich die Abfrage versucht, Ich erhalte keinen Fehler, bekomme aber Folgendes (von LinqPad): enter image description here

Das Endergebnis sollte so aussehen (simuliert in Excel): enter image description here

Irgendeine Idee, wie kann ich das Endergebnis bekommen?

+1

Bitte beachten Sie die Bild-Links beheben oder die tatsächliche und erwartete Ergebnis als Text schreiben –

+0

Das tut mir leid. Es war ein Formatierungsproblem, das das Anzeigen der Bilder verhinderte. –

+0

Wie ist die Beziehung zwischen den FinType/Value-Paaren und dem Rest der Daten in Ihrem gewünschten/simulierten Ergebnis?Ich verstehe nicht, warum der FinType "Dividend" mit dem ChgsType "Buchwert" und der FinType "BookValue" mit dem ChatsType "Kursziel" usw. einhergeht. –

Antwort

1

Erste, mögen Sie von diesen ChngsType, PrevChng usw. verschachtelten Tabellen in den compInfo loszuwerden. Sie können SelectMany() (fließend Syntax) oder rezidivierende from Schlüsselwörter (Abfragesyntax) wie in diesem Beispiel verwenden:

var compInfoTest1 = 
    from issuer in feed.SelectTokens("Product.Context.IssuerDetails.Issuer") 
    from change in issuer["IssuerChanges"] 
    select new { Company = issuer["@companyName"], Type = change["@type"] }; 

können Sie sehen die compInfoTest1 eine flache Firmen-Type-Tabelle enthält:

{ Company = {zTest BM Company, Inc}, Type = {Book Value} } 
{ Company = {zTest BM Company, Inc}, Type = {Price Target} } 
{ Company = {zTest BM Company, Inc}, Type = {EPS} } 
{ Company = {zTest BM Company, Inc}, Type = {Income Tax} } 

Bitte beachten Die Erweiterungsmethode ObjectsOrSelf() ist dazu nicht erforderlich.

Zweite, die ObjectsOrSelf() nicht auf der Doppel-verschachtelte Struktur von SecurityDetails (objekt-> Array-> object-> Array-> Objekt - es auf dem zweiten Objektebene stoppt somit versagt @financialsType zu erreichen). Um damit umzugehen, müssen Sie die gleiche Abflachung Technik verwenden from für die jeder nächst inneren Ebene zu wiederholen:

var compInfoTest2 = 
    from issuer in feed.SelectTokens("Product.Context.IssuerDetails.Issuer") 
    from cluster in issuer["SecurityDetails"]["Security"]["Clusters"] 
    from finVal in cluster["FinancialValue"] 
    select new { Company = issuer["@companyName"], FinType = finVal["@financialsType"] }; 

Hier ist das Abfrageergebnis:

{ Company = {zTest BM Company, Inc}, FinType = {Dividend} } 
{ Company = {zTest BM Company, Inc}, FinType = {Book Value} } 
{ Company = {zTest BM Company, Inc}, FinType = {Rating} } 
{ Company = {zTest BM Company, Inc}, FinType = {Rating Qualifier} } 

Dritte, da es keine Beziehung zwischen den FinType/Value-Paaren und den Rest der Daten, können Sie keine Bedingung schreiben, um Elemente in den change und Sets zu entsprechen. Stattdessen können Sie Enumerable.Zip() verwenden, um die "entsprechenden" Elemente zu kleben.

So ist die letzte Abfrage ist:

var compInfo = 
    from issuer in feed.SelectTokens("Product.Context.IssuerDetails.Issuer") 
    let finValues = (
     from cluster in issuer["SecurityDetails"]["Security"]["Clusters"] 
     from finVal in cluster["FinancialValue"] 
     select new { 
      FinValueName = (string)finVal["@financialsType"], 
      Value = (string)finVal["CurrentValue"]["@displayValue"], 
     } 
    ) 
    from changesAndFinValues in issuer["IssuerChanges"].Zip(finValues, (c,f) => new { 
      ChngsType = (string)c["@type"], 
      PrevChng = (string)c["@previous"], 
      CurrChng = (string)c["@current"], 
      Period = (string)c["@period"], 
      Year = (string)c["@year"], 
      f.FinValueName, 
      f.Value 
    }) 
    select new 
    { 
     Id = (int)issuer["@companyId"], 
     BMOTicker = (string)issuer["@clientCode"], 
     CompName = (string)issuer["@companyName"], 
     changesAndFinValues.ChngsType, 
     changesAndFinValues.PrevChng, 
     changesAndFinValues.CurrChng, 
     changesAndFinValues.Period, 
     changesAndFinValues.Year, 
     changesAndFinValues.FinValueName, 
     changesAndFinValues.Value, 
    }; 

Es erzeugt das folgende Ergebnis auf Ihre Beispieldaten:

{ Id = 1, BMOTicker = "BMTEST-CA", CompName = "zTest BM Company, Inc", ChngsType = "Book Value", PrevChng = "$9.06", CurrChng = "$55.34", Period = null, Year = null, FinValueName = "Dividend", Value = "$5.02" } 
{ Id = 1, BMOTicker = "BMTEST-CA", CompName = "zTest BM Company, Inc", ChngsType = "Price Target", PrevChng = "$50.00", CurrChng = "$199.00", Period = null, Year = null, FinValueName = "Book Value", Value = "$55.34" } 
{ Id = 1, BMOTicker = "BMTEST-CA", CompName = "zTest BM Company, Inc", ChngsType = "EPS", PrevChng = "2.10", CurrChng = "2.09", Period = "5", Year = "2017", FinValueName = "Rating", Value = "Market Perform" } 
{ Id = 1, BMOTicker = "BMTEST-CA", CompName = "zTest BM Company, Inc", ChngsType = "Income Tax", PrevChng = "56", CurrChng = "55", Period = "5", Year = "2015", FinValueName = "Rating Qualifier", Value = "Speculative" }