使用Newtonsoft.Json来处理json字符串,反序列化后形成JObject对象(不使用自定义实体的情况下),大多数情况下我们需要逻辑处理后返给前端。这就需要对JObject中的值进行筛选,简单的获取我们通过JObject的索引器语法即可获得,比如
jb["aaa"].ToString()
。
但我遇到了更复杂的情况,json数据看下图:
我需要查找QueryActiveLimit的成员LimitCommodityInfoList中CommodityID等于cid的NumLimit值(CommodityID是唯一的,即根据cid有且只能够找到一条记录),但是看上图应该可以清晰地明白数据结构:
常规的操作是逐层遍历,直到找到符合条件的CommodityID后break,代码如下:
#region 获取cid=106221的父节点NumLimit
//是否找到
var isFind = false;
//获取QueryActiveLimit的集合
var allAct = jb["ActiveLimitResponseList"][0]["QueryActiveLimit"].Children();
//盛放查询结果
JToken belongAct = null;
foreach (var actInfo in allAct)
{
if (!isFind)
{
var goodsList = actInfo["LimitCommodityInfoList"].Children();
foreach (var goods in goodsList)
{
if (goods["CommodityID"].ToString() == "106221")
{
isFind = true;
//如果最后一条记录符合条件
if (actInfo.Next == null)
{
belongAct = actInfo;
}
break;
}
}
}
else
{
//因为遍历到下条才中断,所以符合条件的实际是上一条记录
belongAct = actInfo.Previous;
break;
}
}
if (belongAct != null)
{
int.TryParse(belongAct["NumLimit"].ToString(), out limitNum);
}
else
{
limitNum = 0;
}
#endregion
belongAct即为最终查询结果。代码比较冗长,于是改用linq去实现。
以下即是linq实现代码,大大减少了代码行数:
#region 获取cid=106221的父节点NumLimit
var belongAct = jb["ActiveLimitResponseList"][0]["QueryActiveLimit"].Children()
.Where(a => (a["LimitCommodityInfoList"].Children().Select(c => c["CommodityID"].ToString().Contains("106221")).First()))
.FirstOrDefault();
if (belongAct != null)//查询成功
{
int.TryParse(belongAct["NumLimit"].ToString(), out limitNum);
}
else
{
limitNum = 0;
return true;
}
#endregion
备注:Where和需要查找的数据平级,处于同一层,Where中的lamda可依据上一层逐层Select下去,Select返回泛型可枚举布尔类型,只需要取First即可,因为有且仅有一条数据符合条件。
其实只是工作中代码优化的一个技巧,供自己以后参靠学习反思。