找到最后一个实际报告的季度
Find the last actual reported quarter
我正在尝试查找最后一个实际报告的季度及其随附的显示值。条件是 @clientsDescription 或 @displayName 必须为 EPS。这是我的 JSON 字符串的样子:
{
"?xml": {
"@version": "1.0",
"@encoding": "UTF-8"
},
"DataFeed": {
"@FeedName": "issuerDetails",
"SecurityDetails": {
"Security": {
"@sequence": "850",
"TimesSeriesList": [{
"@description": "EPS",
"@clientsDescription": "EPS",
"FinancialValue": [{
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q1",
"@periodEnd": "2015-9-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].19"
}
}, {
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q2",
"@periodEnd": "2015-12-31T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].26"
}
}, {
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q3",
"@periodEnd": "2015-3-31T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].34"
}
}, {
"@displayRank": "850",
"@estimateActual": "Estimate",
"@period": "Q4",
"@periodEnd": "2015-6-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].32"
}
}, {
"@displayRank": "850",
"@estimateActual": "Estimate",
"@period": "Annual",
"@periodEnd": "2015-6-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": ".11"
}
}
]
}
]
}
}
}
}
这是 json 类 的样子:
public static class JsonExtensions
{
public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
{
if (node == null)
return Enumerable.Empty<JToken>();
var container = node as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new[] { node };
}
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;
}
public static IEnumerable<JToken> SingleOrMultiple(this JToken source)
{
if (source == null)
return Enumerable.Empty<JToken>();
IEnumerable<JToken> arr = source as JArray;
return arr ?? new[] { source };
}
}
既然有人要原版XML,这里是:
<DataFeed FeedName="issuerDetails">
<CompanyDetails></CompanyDetails>
<SecurityDetails minDisplayYear="2014" maxDisplayYear="2020">
<Security sequence="900" primaryIndicator="No">
<TimesSeriesList description="EPS" clientsDescription="EPS" id="1" qualifier="--" currencyName="CAD" currencySymbol="C$" fiscalId="1" fiscalCalendar="Fiscal" qualifierId="0">
<FinancialValue displayRank="900" estimateActual="Actual" period="Q1" periodEnd="2015-12-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].45">0.4502</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Actual" period="Q2" periodEnd="2015-3-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].43">0.43</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Actual" period="Q3" periodEnd="2015-6-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].64">0.64</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Q4" periodEnd="2015-9-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].52">0.52</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Annual" periodEnd="2015-9-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue=".03">2.0325</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Q1" periodEnd="2016-12-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].56">0.56</CurrentValue>
</FinancialValue>
</TimesSeriesList>
</Security>
</SecurityDetails>
</DataFeed>
下面是我的 JSON 提要代码:
from securityDetail in jsonFeed
.SelectTokens("DataFeed.SecurityDetails.Security.TimesSeriesList")
.SelectMany(i => i.ObjectsOrSelf())
let metric = securityDetail
.SelectToken("@clientDescription")
.SingleOrMultiple()
.Select(t => (string)t)
.ToArray()
where metric.Equals("EPS") && metric != null
let finValues = securityDetail.SelectTokens("FinancialValue")
.SelectMany(d => d.ObjectsOrSelf())
orderby finValues.SelectToken("@periodEnd") descending // <-- getting a error here
orderby finValues.SelectToken("@period") descending
select new
{
LastRptQtr = string.format("{0}{1}",
(string)(finValues
.SelectToken("@periodEnd").FirstOrDefault()).Substring(0, 4),
(string)finValues
.SelectToken("@period").FirstOrDefault()),
DispVal = finValues
.SelectToken("CurrentValue.@displayValue").FirstOrDefault()
}
最后,我需要:
LastRptQtr = "2015Q3"
DispVal = "[=14=].34"
我收到以下错误:
'IEnumerable<JObject>' does not contain a definition for 'SelectToken'
and no extension method 'SelectToken' accepting a first argument of
type 'IEnumerable<JObject>' could be found
我做错了什么?
我认为您可以使用 Json.Net 轻松完成此操作。
给定以下 json 字符串。
var json = @"
{
""?xml"": {
""@version"": ""1.0"",
""@encoding"": ""UTF-8""
},
""DataFeed"": {
""@FeedName"": ""issuerDetails"",
""SecurityDetails"": {
""Security"": {
""@sequence"": ""850"",
""TimesSeriesList"": [{
""@description"": ""EPS"",
""@clientsDescription"": ""EPS"",
""FinancialValue"": [{
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q1"",
""@periodEnd"": ""2015-9-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].19""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q2"",
""@periodEnd"": ""2015-12-31T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].26""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q3"",
""@periodEnd"": ""2015-3-31T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].34""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Estimate"",
""@period"": ""Q4"",
""@periodEnd"": ""2015-6-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].32""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Estimate"",
""@period"": ""Annual"",
""@periodEnd"": ""2015-6-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": "".11""
}
}
]
}
]
}
}
}
}";
以下内容似乎可以满足您的要求:
var obj = JObject.Parse(json);
obj["DataFeed"]["SecurityDetails"]["Security"]["TimesSeriesList"]
.Where(x =>
x.HasValues
&& x["@clientsDescription"].Value<string>() == "EPS")
.SelectMany(x => x["FinancialValue"].Children())
.Where(x => x["@estimateActual"].Value<string>() == "Actual")
.Select(x => new {
PeriodEnd = x["@periodEnd"].Value<DateTime>(),
Period = x["@period"].Value<string>(),
DisplayValue = x["CurrentValue"]["@displayValue"].Value<string>(),
LastReportQuarter = x["@periodEnd"].Value<DateTime>().Year.ToString() + x["@period"].Value<string>()})
.OrderByDescending(x => x.PeriodEnd.Year)
.ThenByDescending(x => x.Period)
.First()
.Dump();
PeriodEnd 3/31/2015 12:00:00 AM
Period Q3
DisplayValue [=12=].34
LastReportQuarter 2015Q3
方法ObjectsOrSelf
returnsIEnumerable
,
然后在 let a = data.SelectMany(t=>t.ObjectsOrSelf())
子句中,变量 a
具有 IEnumerable 类型,需要通过 from b in a
.
进行扩展
var result = from securityDetail in obj.SelectTokens("DataFeed.SecurityDetails.Security.TimesSeriesList").SelectMany(t => t.ObjectsOrSelf())
let metric = securityDetail.SelectToken("@clientsDescription")
where metric != null && metric.Value<String>() == "EPS"
let finValues = securityDetail.SelectTokens("FinancialValue").SelectMany(d => d.ObjectsOrSelf())
from v in finValues
orderby v.SelectToken("@periodEnd") descending
orderby v.SelectToken("@period") descending
select new
{
LastRptQtr = string.Format("{0}{1}",
((string) v.SelectToken("@periodEnd")).Substring(0, 4),
(string) v.SelectToken("@period")),
DispVal = v.SelectToken("CurrentValue.@displayValue").Value<String>()
};
手上只有锤子,看什么都是钉子。您不需要将原始 xml 转换为 json。使用原始 xml 会更简单。
使用 Linq2Xml + Xpath
var xDoc = XDocument.Parse(xmlstring);
var elements = xDoc.XPathSelectElements("//*[@periodEnd and (@clientsDescription='EPS' or @displayName='EPS')]")
.OrderBy(x => (DateTime)x.Attribute("periodEnd"))
.Select(x=>new {
PeriodEnd = (DateTime)x.Attribute("periodEnd"),
DispVal = (string)x.Element("CurrentValue").Attribute("displayValue")
})
.ToList();
我正在尝试查找最后一个实际报告的季度及其随附的显示值。条件是 @clientsDescription 或 @displayName 必须为 EPS。这是我的 JSON 字符串的样子:
{
"?xml": {
"@version": "1.0",
"@encoding": "UTF-8"
},
"DataFeed": {
"@FeedName": "issuerDetails",
"SecurityDetails": {
"Security": {
"@sequence": "850",
"TimesSeriesList": [{
"@description": "EPS",
"@clientsDescription": "EPS",
"FinancialValue": [{
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q1",
"@periodEnd": "2015-9-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].19"
}
}, {
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q2",
"@periodEnd": "2015-12-31T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].26"
}
}, {
"@displayRank": "850",
"@estimateActual": "Actual",
"@period": "Q3",
"@periodEnd": "2015-3-31T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].34"
}
}, {
"@displayRank": "850",
"@estimateActual": "Estimate",
"@period": "Q4",
"@periodEnd": "2015-6-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": "[=10=].32"
}
}, {
"@displayRank": "850",
"@estimateActual": "Estimate",
"@period": "Annual",
"@periodEnd": "2015-6-30T00:00:00.00",
"@displayName": "EPS",
"CurrentValue": {
"@displayValue": ".11"
}
}
]
}
]
}
}
}
}
这是 json 类 的样子:
public static class JsonExtensions
{
public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
{
if (node == null)
return Enumerable.Empty<JToken>();
var container = node as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new[] { node };
}
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;
}
public static IEnumerable<JToken> SingleOrMultiple(this JToken source)
{
if (source == null)
return Enumerable.Empty<JToken>();
IEnumerable<JToken> arr = source as JArray;
return arr ?? new[] { source };
}
}
既然有人要原版XML,这里是:
<DataFeed FeedName="issuerDetails">
<CompanyDetails></CompanyDetails>
<SecurityDetails minDisplayYear="2014" maxDisplayYear="2020">
<Security sequence="900" primaryIndicator="No">
<TimesSeriesList description="EPS" clientsDescription="EPS" id="1" qualifier="--" currencyName="CAD" currencySymbol="C$" fiscalId="1" fiscalCalendar="Fiscal" qualifierId="0">
<FinancialValue displayRank="900" estimateActual="Actual" period="Q1" periodEnd="2015-12-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].45">0.4502</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Actual" period="Q2" periodEnd="2015-3-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].43">0.43</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Actual" period="Q3" periodEnd="2015-6-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].64">0.64</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Q4" periodEnd="2015-9-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].52">0.52</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Annual" periodEnd="2015-9-30T00:00:00.00" displayName="EPS">
<CurrentValue displayValue=".03">2.0325</CurrentValue>
</FinancialValue>
<FinancialValue displayRank="900" estimateActual="Estimate" period="Q1" periodEnd="2016-12-31T00:00:00.00" displayName="EPS">
<CurrentValue displayValue="[=12=].56">0.56</CurrentValue>
</FinancialValue>
</TimesSeriesList>
</Security>
</SecurityDetails>
</DataFeed>
下面是我的 JSON 提要代码:
from securityDetail in jsonFeed
.SelectTokens("DataFeed.SecurityDetails.Security.TimesSeriesList")
.SelectMany(i => i.ObjectsOrSelf())
let metric = securityDetail
.SelectToken("@clientDescription")
.SingleOrMultiple()
.Select(t => (string)t)
.ToArray()
where metric.Equals("EPS") && metric != null
let finValues = securityDetail.SelectTokens("FinancialValue")
.SelectMany(d => d.ObjectsOrSelf())
orderby finValues.SelectToken("@periodEnd") descending // <-- getting a error here
orderby finValues.SelectToken("@period") descending
select new
{
LastRptQtr = string.format("{0}{1}",
(string)(finValues
.SelectToken("@periodEnd").FirstOrDefault()).Substring(0, 4),
(string)finValues
.SelectToken("@period").FirstOrDefault()),
DispVal = finValues
.SelectToken("CurrentValue.@displayValue").FirstOrDefault()
}
最后,我需要:
LastRptQtr = "2015Q3"
DispVal = "[=14=].34"
我收到以下错误:
'IEnumerable<JObject>' does not contain a definition for 'SelectToken'
and no extension method 'SelectToken' accepting a first argument of
type 'IEnumerable<JObject>' could be found
我做错了什么?
我认为您可以使用 Json.Net 轻松完成此操作。
给定以下 json 字符串。
var json = @"
{
""?xml"": {
""@version"": ""1.0"",
""@encoding"": ""UTF-8""
},
""DataFeed"": {
""@FeedName"": ""issuerDetails"",
""SecurityDetails"": {
""Security"": {
""@sequence"": ""850"",
""TimesSeriesList"": [{
""@description"": ""EPS"",
""@clientsDescription"": ""EPS"",
""FinancialValue"": [{
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q1"",
""@periodEnd"": ""2015-9-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].19""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q2"",
""@periodEnd"": ""2015-12-31T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].26""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Actual"",
""@period"": ""Q3"",
""@periodEnd"": ""2015-3-31T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].34""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Estimate"",
""@period"": ""Q4"",
""@periodEnd"": ""2015-6-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": ""[=10=].32""
}
}, {
""@displayRank"": ""850"",
""@estimateActual"": ""Estimate"",
""@period"": ""Annual"",
""@periodEnd"": ""2015-6-30T00:00:00.00"",
""@displayName"": ""EPS"",
""CurrentValue"": {
""@displayValue"": "".11""
}
}
]
}
]
}
}
}
}";
以下内容似乎可以满足您的要求:
var obj = JObject.Parse(json);
obj["DataFeed"]["SecurityDetails"]["Security"]["TimesSeriesList"]
.Where(x =>
x.HasValues
&& x["@clientsDescription"].Value<string>() == "EPS")
.SelectMany(x => x["FinancialValue"].Children())
.Where(x => x["@estimateActual"].Value<string>() == "Actual")
.Select(x => new {
PeriodEnd = x["@periodEnd"].Value<DateTime>(),
Period = x["@period"].Value<string>(),
DisplayValue = x["CurrentValue"]["@displayValue"].Value<string>(),
LastReportQuarter = x["@periodEnd"].Value<DateTime>().Year.ToString() + x["@period"].Value<string>()})
.OrderByDescending(x => x.PeriodEnd.Year)
.ThenByDescending(x => x.Period)
.First()
.Dump();
PeriodEnd 3/31/2015 12:00:00 AM
Period Q3
DisplayValue [=12=].34
LastReportQuarter 2015Q3
方法ObjectsOrSelf
returnsIEnumerable
,
然后在 let a = data.SelectMany(t=>t.ObjectsOrSelf())
子句中,变量 a
具有 IEnumerable 类型,需要通过 from b in a
.
var result = from securityDetail in obj.SelectTokens("DataFeed.SecurityDetails.Security.TimesSeriesList").SelectMany(t => t.ObjectsOrSelf())
let metric = securityDetail.SelectToken("@clientsDescription")
where metric != null && metric.Value<String>() == "EPS"
let finValues = securityDetail.SelectTokens("FinancialValue").SelectMany(d => d.ObjectsOrSelf())
from v in finValues
orderby v.SelectToken("@periodEnd") descending
orderby v.SelectToken("@period") descending
select new
{
LastRptQtr = string.Format("{0}{1}",
((string) v.SelectToken("@periodEnd")).Substring(0, 4),
(string) v.SelectToken("@period")),
DispVal = v.SelectToken("CurrentValue.@displayValue").Value<String>()
};
手上只有锤子,看什么都是钉子。您不需要将原始 xml 转换为 json。使用原始 xml 会更简单。
使用 Linq2Xml + Xpath
var xDoc = XDocument.Parse(xmlstring);
var elements = xDoc.XPathSelectElements("//*[@periodEnd and (@clientsDescription='EPS' or @displayName='EPS')]")
.OrderBy(x => (DateTime)x.Attribute("periodEnd"))
.Select(x=>new {
PeriodEnd = (DateTime)x.Attribute("periodEnd"),
DispVal = (string)x.Element("CurrentValue").Attribute("displayValue")
})
.ToList();