0

我有一个多态的 json 字符串。这是它的样子:

{
    "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",
                                            }
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                }
            }
        }
    }
}

我正在使用以下扩展类:

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

基于此,这是我的查询:

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"])
    };

当我尝试查询时,我没有收到错误但得到以下信息(来自 LinqPad): 在此处输入图像描述

最终结果应如下所示(在 Excel 中模拟): 在此处输入图像描述

知道如何获得最终结果吗?

4

1 回答 1

1

首先,你要摆脱那些ChngsType,PrevChng等嵌套表中的compInfo. 您可以使用SelectMany()(流利的语法)或重复from的关键字(查询语法),如下例所示:

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

您可以看到compInfoTest1包含一个扁平的 Company-Type 表:

{ 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} }

请注意ObjectsOrSelf(),执行此操作不需要扩展方法。

其次, (object->array->object->array->objectObjectsOrSelf()的双嵌套结构失败SecurityDetails- 它在第二个对象级别停止,因此无法达到@financialsType)。为了解决这个问题,您需要对from每个下一个内部级别重复使用相同的展平技术:

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"] };

这是查询结果:

{ 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} }

第三,由于 FinType/Value 对与其余数据之间没有关系,因此您不能编写任何条件来匹配changeandfinVal集合中的项目。相反,您可以使用Enumerable.Zip()粘合“相应”项目。

所以最后的查询是:

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,
    };

它对您的样本数据产生以下结果:

{ 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" }
于 2016-07-21T09:41:39.450 回答