C# LINQ到JSON-对象或数组的查询
我正在尝试获取SEDOL和ADP值的列表。以下是我的json文本:C# LINQ到JSON-对象或数组的查询,c#,linq,json.net,linq-to-json,C#,Linq,Json.net,Linq To Json,我正在尝试获取SEDOL和ADP值的列表。以下是我的json文本: { "DataFeed" : { "@FeedName" : "AdminData", "Issuer" : [{ "id" : "1528", "name" : "ZYZ.A a Test Company", "clientCode" : "ZYZ.A", "s
{
"DataFeed" : {
"@FeedName" : "AdminData",
"Issuer" : [{
"id" : "1528",
"name" : "ZYZ.A a Test Company",
"clientCode" : "ZYZ.A",
"securities" : {
"Security" : {
"id" : "1537",
"sedol" : "SEDOL111",
"coverage" : {
"Coverage" : [{
"analyst" : {
"@id" : "164",
"@clientCode" : "SJ",
"@firstName" : "Steve",
"@lastName" : "Jobs",
"@rank" : "1"
}
}, {
"analyst" : {
"@id" : "261",
"@clientCode" : "BG",
"@firstName" : "Bill",
"@lastName" : "Gates",
"@rank" : "2"
}
}
]
},
"customFields" : {
"customField" : [{
"@name" : "ADP Security Code",
"@type" : "Textbox",
"values" : {
"value" : "ADPSC1111"
}
}, {
"@name" : "Top 10 - Select one or many",
"@type" : "Dropdown, multiple choice",
"values" : {
"value" : ["Large Cap", "Cdn Small Cap", "Income"]
}
}
]
}
}
}
}, {
"id" : "1519",
"name" : "ZVV Test",
"clientCode" : "ZVV=US",
"securities" : {
"Security" : [{
"id" : "1522",
"sedol" : "SEDOL112",
"coverage" : {
"Coverage" : {
"analyst" : {
"@id" : "79",
"@clientCode" : "MJ",
"@firstName" : "Michael",
"@lastName" : "Jordan",
"@rank" : "1"
}
}
},
"customFields" : {
"customField" : [{
"@name" : "ADP Security Code",
"@type" : "Textbox",
"values" : {
"value" : "ADPS1133"
}
}, {
"@name" : "Top 10 - Select one or many",
"@type" : "Dropdown, multiple choice",
"values" : {
"value" : ["Large Cap", "Cdn Small Cap", "Income"]
}
}
]
}
}, {
"id" : "1542",
"sedol" : "SEDOL112",
"customFields" : {
"customField" : [{
"@name" : "ADP Security Code",
"@type" : "Textbox",
"values" : {
"value" : "ADPS1133"
}
}, {
"@name" : "Top 10 - Select one or many",
"@type" : "Dropdown, multiple choice",
"values" : {
"value" : ["Large Cap", "Cdn Small Cap", "Income"]
}
}
]
}
}
]
}
}
]
}
}
以下是我目前掌握的代码:
var compInfo = feed["DataFeed"]["Issuer"]
.Select(p => new {
Id = p["id"],
CompName = p["name"],
SEDOL = p["securities"]["Security"].OfType<JArray>() ?
p["securities"]["Security"][0]["sedol"] :
p["securities"]["Security"]["sedol"]
ADP = p["securities"]["Security"].OfType<JArray>() ?
p["securities"]["Security"][0]["customFields"]["customField"][0]["values"]["value"] :
p["securities"]["Security"]["customFields"]["customField"][0]["values"]["value"]
});
但是我现在得到的错误是,“ExpandoObject”不包含“DataFeed”的定义,并且找不到接受“ExpandoObject”类型的第一个参数的扩展方法“DataFeed”
。注意:我知道这个json文本格式不正确。一个实例有一个数组,另一个是一个对象。我希望代码足够灵活,能够处理这两个实例
[UPDATE2]感谢@dbc迄今为止对我的代码的帮助。我已经更新了上面的json文本,使其与我当前的环境非常匹配。我现在可以得到SEDOLs和ADP代码了。然而,当我试图获得第一个分析员时,我的代码只对对象有效,并为作为数组一部分的分析员生成空值。以下是我当前的代码:
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
where security != null
select new
{
Id = (string)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => (string)o.SelectToken("values.value"))
.FirstOrDefault(),
Analyst = security["coverage"]
.DescendantsAndSelf()
.OfType<JObject>()
.Select(jo => (string)jo.SelectToken("Coverage.analyst.@lastName"))
.FirstOrDefault(),
};
var compInfo=来自提要中的发卡机构。选择令牌(“DataFeed.issuer”)。选择多个(i=>i.ObjectsOrSelf())
让security=issuer.SelectTokens(“securities.security”).SelectMany(s=>s.ObjectsOrSelf()).FirstOrDefault()
哪里有保安!=无效的
选择新的
{
Id=(字符串)颁发者[“Id”],//如果Id不一定是数字,则更改为(字符串)颁发者[“Id”]。
CompName=(字符串)颁发者[“名称”],
SEDOL=(字符串)安全性[“SEDOL”],
ADP=安全性[“自定义字段”]
.后代和自我()
第()类
。其中(o=>(字符串)o[“@name”]==“ADP安全代码”)
.Select(o=>(字符串)o.SelectToken(“values.value”))
.FirstOrDefault(),
分析师=安全[“覆盖范围”]
.后代和自我()
第()类
.Select(jo=>(string)jo.SelectToken(“Coverage.analyst@lastName”))
.FirstOrDefault(),
};
要始终选择第一位分析师,我需要做哪些更改?使用newtonsoft.json
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json);
还要注意,您的JSON格式不正确
创建的代理类无法确定安全性的类型,因为在一个实例中它是一个数组,而在另一个实例中它是一个简单的对象
原始答复:
我曾经帮助我获得一些类,现在我可以使用以下类型:
var obj = JsonConvert.DeserializeObject<RootObject>(json);
var result = from a in obj.DataFeed.Issuer
select new
{
Sedol = a.securities.Security.sedol,
Name = a.name
};
var obj=JsonConvert.DeserializeObject(json);
var结果=来自obj.DataFeed.Issuer中的
选择新的
{
Sedol=a.securities.Security.Sedol,
Name=a.Name
};
课程:
public class Values
{
public object value { get; set; }
}
public class CustomField
{
public string name { get; set; }
public string type { get; set; }
public Values values { get; set; }
}
public class CustomFields
{
public List<CustomField> customField { get; set; }
}
public class Security
{
public string id { get; set; }
public string sedol { get; set; }
public CustomFields customFields { get; set; }
}
public class Securities
{
public Security Security { get; set; }
}
public class Issuer
{
public string id { get; set; }
public string name { get; set; }
public string clientCode { get; set; }
public Securities securities { get; set; }
}
public class DataFeed
{
public string FeedName { get; set; }
public List<Issuer> Issuer { get; set; }
}
public class RootObject
{
public DataFeed DataFeed { get; set; }
}
公共类值
{
公共对象值{get;set;}
}
公共类自定义字段
{
公共字符串名称{get;set;}
公共字符串类型{get;set;}
公共值值{get;set;}
}
公共类自定义字段
{
公共列表自定义字段{get;set;}
}
公共安全
{
公共字符串id{get;set;}
公共字符串sedol{get;set;}
公共自定义字段自定义字段{get;set;}
}
公共类证券
{
公共安全{get;set;}
}
公共类发行人
{
公共字符串id{get;set;}
公共字符串名称{get;set;}
公共字符串clientCode{get;set;}
公共证券{get;set;}
}
公共类数据源
{
公共字符串FeedName{get;set;}
公共列表颁发者{get;set;}
}
公共类根对象
{
公共数据源数据源{get;set;}
}
如果您希望所有SEDOL&ADP值都具有相关的发卡机构Id和CompName,您可以执行以下操作:
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
from security in issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf())
select new
{
Id = (long)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => (string)o.SelectToken("values.value"))
.FirstOrDefault(),
};
产生:
然而,在您目前编写的查询中,您似乎试图只返回每个发行人的第一个SEDOL&ADP。如果这是您真正想要的,请执行以下操作:
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
where security != null
select new
{
Id = (long)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => (string)o.SelectToken("values.value"))
.FirstOrDefault(),
};
另一方面,由于JSON是多态的(属性有时是对象数组,有时只是对象),我不认为反序列化到类层次结构或ExpandoObject
会更容易
更新
给定已更新的JSON,您可以使用查找第一个分析人员的姓氏,其中递归搜索运算符处理分析人员可能包含在数组中,也可能不包含在数组中的事实:
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
where security != null
select new
{
Id = (string)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = (string)security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => o.SelectToken("values.value"))
.FirstOrDefault(),
Analyst = (string)security.SelectTokens("coverage.Coverage..analyst.@lastName").FirstOrDefault(),
};
var compInfo=来自提要中的发卡机构。选择令牌(“DataFeed.issuer”)。选择多个(i=>i.ObjectsOrSelf())
让security=issuer.SelectTokens(“securities.security”).SelectMany(s=>s.ObjectsOrSelf()).FirstOrDefault()
哪里有保安!=无效的
选择新的
{
Id=(字符串)颁发者[“Id”],//如果Id不一定是数字,则更改为(字符串)颁发者[“Id”]。
CompName=(字符串)颁发者[“名称”],
SEDOL=(字符串)安全性[“SEDOL”],
ADP=(字符串)安全性[“自定义字段”]
.后代和自我()
第()类
。其中(o=>(字符串)o[“@name”]==“ADP安全代码”)
.Select(o=>o.SelectToken(“values.value”))
.FirstOrDefault(),
Analyst=(字符串)security.SelectTokens(“coverage.coverage..Analyst@lastName”).FirstOrDefault(),
};
我会将json反序列化为一个动态ExpandooObject(为简洁起见,或者定义一个类型),然后使用linq。您能否提供一些代码,说明如何使用动态ExpandooObject实现这一点?同样,在这里,您需要调试代码。在foreach循环内设置断点,并检查/展开元素变量。它有什么价值观?该对象内部是否有DataFeed元素?使用调试器,观察整个ExpandooObject的内容。我使用LINQPAD作为IDE。我看到元素>键“DataFeed”,值“ExpandoObject”。这个
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;
}
}
Console.WriteLine(JsonConvert.SerializeObject(compInfo, Formatting.Indented));
[
{
"Id": 1528,
"CompName": "ZYZ.A a Test Company",
"SEDOL": "SEDOL111",
"ADP": "ADPSC1111"
},
{
"Id": 1519,
"CompName": "ZVV Test",
"SEDOL": "SEDOL112",
"ADP": "ADPS1133"
},
{
"Id": 1519,
"CompName": "ZVV Test",
"SEDOL": "SEDOL112",
"ADP": "ADPS1133"
}
]
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
where security != null
select new
{
Id = (long)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => (string)o.SelectToken("values.value"))
.FirstOrDefault(),
};
[
{
"Id": 1528,
"CompName": "ZYZ.A a Test Company",
"SEDOL": "SEDOL111",
"ADP": "ADPSC1111"
},
{
"Id": 1519,
"CompName": "ZVV Test",
"SEDOL": "SEDOL112",
"ADP": "ADPS1133"
}
]
var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
where security != null
select new
{
Id = (string)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
CompName = (string)issuer["name"],
SEDOL = (string)security["sedol"],
ADP = (string)security["customFields"]
.DescendantsAndSelf()
.OfType<JObject>()
.Where(o => (string)o["@name"] == "ADP Security Code")
.Select(o => o.SelectToken("values.value"))
.FirstOrDefault(),
Analyst = (string)security.SelectTokens("coverage.Coverage..analyst.@lastName").FirstOrDefault(),
};