如何创建包含 AND 和 OR 运算符的 JSONPath 过滤器表达式?
How can I create a JSONPath filter expression containing both AND and OR operators?
我有一个要求,我试图通过过滤 JSON 中对象的多个属性的存在 and/or 值来 select 字符串中的对象 JSON ]数组。
这是我的例子 JSON:
{'Fields':[{
"Sub_Status": "Pending",
"Status": "Pending",
"Patient_Gender": "M"
}]}
我想使用这样的查询来检查这个 json 字符串(下面的查询是一个 SQL 查询)
string query = TRIM(UPPER(Status)) IN ('PENDING', 'DISPENSED','SHIPMENT') AND TRIM(Patient_Gender) IS NOT NULL
string json_string = {'Fields':[{
"Sub_Status": "Pending",
"Status": "Pending",
"Patient_Gender": "M"
}]};
var test = json_string.Where(query).toString() /// a return of bool = true or false
我尝试使用 JSONPath 和 system.linq.dynamic,但没有成功。
更新
我需要 c# 中的响应。截至目前。我尝试使用 NewtonSoft.Json SelectToken 来 select 使用 JSON 路径查询的令牌。
我查询的第一部分是:
JToken test = s.SelectToken("$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]");
我查询的第二部分是:
JToken test = s.SelectToken("$.Fields[?(@.Patient_Gender != '')]");
问题出在 "and" 运算符上——我不知道如何将它们合并到一个 JSONPath 查询中。单独查询正在工作。我需要 "and" 运算符的语法。任何建议都会有所帮助。
实际上,您需要将 json 反序列化为一个或多个对象(如果有多个记录)并测试该对象。
转到您的解决方案资源管理器 > 右键单击 => 管理 Nuget 包 => 下载 Netwonsoft.Json,然后创建具有类似 json 结构的 class:
public class Case
{
public string Sub_Status { set; get; }
public string Status { set; get; }
public string Patient_Gender { set; get; }
}
然后在你的程序中:
static void Main(string[] args)
{
string json_string = @"{""Sub_Status"": ""Pending"",
""Status"": ""Pending"",
""Patient_Gender"": ""M""}";
Case caseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Case>(json_string);
List<string> acceptedStatuses = new List<string> { "PENDING", "DISPENSED", "SHIPMENT" };
bool test = statuses.Any(s => s.Equals(caseObj.Status, StringComparison.OrdinalIgnoreCase))
&& !string.IsNullOrWhiteSpace(caseObj.Patient_Gender);
}
Newtonsoft 的 JSONPath 实现确实支持 AND
运算符,如 QueryExpression.cs 的 源代码所示
。它使用 &&
语法。因此,如果您想要搜索具有 Status == 'Pending'
且具有 Patient_Gender
属性 的字段(具有任何值),您将执行:
var query = s.SelectTokens("$.Fields[?(@.Status == 'Pending' && @.Patient_Gender)]");
但是,您是 混合 &&
和 ||
运算符,不幸的是,这两个运算符的优先顺序没有记录。 JSONPath website says, uselessly, that ()
is a script expression, using the underlying script engine. And the Newtonsoft documentation 除了将 reader 引用到同一个 JSONPath 网站之外什么也没说!
您可能想 open a documentation issue with Newtonsoft 要求他们澄清 JSONPath 中 ||
和 &&
运算符的优先级。
因此,要获得您想要的查询,您有以下选择:
我从实验中发现,&&
和 ||
以相同的优先级从左到右关联。因此 A && B || C
表示 A && (B || C)
而 A || B && C
表示 A || (B && C)
你显然想要前者。 只要您愿意依赖未记录的行为,以下查询应该有效:
var filter = "$.Fields[?(@.Patient_Gender && @.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]";
var query = s.SelectTokens(filter);
var result = query.ToList();
可以使用Enumerable.Intersect()
合并查询结果:
var query1 = s.SelectTokens("$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]");
var query2 = s.SelectTokens("$.Fields[?(@.Patient_Gender)]");
var query = query1.Intersect(query2);
var result = query.ToList();
您可以使用 Enumerable.Where()
进行过滤,而只需使用 SelectTokens()
进行枚举:
var query = from t in s.SelectTokens("$.Fields[*]")
where (string)t["Patient_Gender"] != null
let status = (string)t["Status"]
where status == "Pending" || status == "PENDING" || status == "SHIPMENT" || status == "DISPENSED"
select t;
var result = query.ToList();
如果你只是想知道是否匹配,而不是匹配的标记列表,你可以使用 Any()
,例如
var result = query.Any();
顺便说一句,以下尝试没有奏效:
尝试将逻辑运算符括起来会引发 JsonException: Unexpected character while parsing path query: (
:
var filter = "$.Fields[?((@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED') && (@.Patient_Gender))]";
var query = s.SelectTokens(filter);
var result = query.ToList();
在 ||
之后放置 &&
错误地选择了匹配 ||
子句之一但不匹配 &&
子句的标记:
var filter = "$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED' && @.Patient_Gender)]";
var query = s.SelectTokens(filter);
var result = query.ToList();
这里是一个 fiddle 显示工作和非工作查询。
我有一个要求,我试图通过过滤 JSON 中对象的多个属性的存在 and/or 值来 select 字符串中的对象 JSON ]数组。
这是我的例子 JSON:
{'Fields':[{
"Sub_Status": "Pending",
"Status": "Pending",
"Patient_Gender": "M"
}]}
我想使用这样的查询来检查这个 json 字符串(下面的查询是一个 SQL 查询)
string query = TRIM(UPPER(Status)) IN ('PENDING', 'DISPENSED','SHIPMENT') AND TRIM(Patient_Gender) IS NOT NULL
string json_string = {'Fields':[{
"Sub_Status": "Pending",
"Status": "Pending",
"Patient_Gender": "M"
}]};
var test = json_string.Where(query).toString() /// a return of bool = true or false
我尝试使用 JSONPath 和 system.linq.dynamic,但没有成功。
更新
我需要 c# 中的响应。截至目前。我尝试使用 NewtonSoft.Json SelectToken 来 select 使用 JSON 路径查询的令牌。
我查询的第一部分是:
JToken test = s.SelectToken("$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]");
我查询的第二部分是:
JToken test = s.SelectToken("$.Fields[?(@.Patient_Gender != '')]");
问题出在 "and" 运算符上——我不知道如何将它们合并到一个 JSONPath 查询中。单独查询正在工作。我需要 "and" 运算符的语法。任何建议都会有所帮助。
实际上,您需要将 json 反序列化为一个或多个对象(如果有多个记录)并测试该对象。
转到您的解决方案资源管理器 > 右键单击 => 管理 Nuget 包 => 下载 Netwonsoft.Json,然后创建具有类似 json 结构的 class:
public class Case
{
public string Sub_Status { set; get; }
public string Status { set; get; }
public string Patient_Gender { set; get; }
}
然后在你的程序中:
static void Main(string[] args)
{
string json_string = @"{""Sub_Status"": ""Pending"",
""Status"": ""Pending"",
""Patient_Gender"": ""M""}";
Case caseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Case>(json_string);
List<string> acceptedStatuses = new List<string> { "PENDING", "DISPENSED", "SHIPMENT" };
bool test = statuses.Any(s => s.Equals(caseObj.Status, StringComparison.OrdinalIgnoreCase))
&& !string.IsNullOrWhiteSpace(caseObj.Patient_Gender);
}
Newtonsoft 的 JSONPath 实现确实支持 AND
运算符,如 QueryExpression.cs 的 源代码所示
。它使用 &&
语法。因此,如果您想要搜索具有 Status == 'Pending'
且具有 Patient_Gender
属性 的字段(具有任何值),您将执行:
var query = s.SelectTokens("$.Fields[?(@.Status == 'Pending' && @.Patient_Gender)]");
但是,您是 混合 &&
和 ||
运算符,不幸的是,这两个运算符的优先顺序没有记录。 JSONPath website says, uselessly, that ()
is a script expression, using the underlying script engine. And the Newtonsoft documentation 除了将 reader 引用到同一个 JSONPath 网站之外什么也没说!
您可能想 open a documentation issue with Newtonsoft 要求他们澄清 JSONPath 中 ||
和 &&
运算符的优先级。
因此,要获得您想要的查询,您有以下选择:
我从实验中发现,
&&
和||
以相同的优先级从左到右关联。因此A && B || C
表示A && (B || C)
而A || B && C
表示A || (B && C)
你显然想要前者。 只要您愿意依赖未记录的行为,以下查询应该有效:
var filter = "$.Fields[?(@.Patient_Gender && @.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]"; var query = s.SelectTokens(filter); var result = query.ToList();
可以使用
Enumerable.Intersect()
合并查询结果:var query1 = s.SelectTokens("$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED')]"); var query2 = s.SelectTokens("$.Fields[?(@.Patient_Gender)]"); var query = query1.Intersect(query2); var result = query.ToList();
您可以使用
Enumerable.Where()
进行过滤,而只需使用SelectTokens()
进行枚举:var query = from t in s.SelectTokens("$.Fields[*]") where (string)t["Patient_Gender"] != null let status = (string)t["Status"] where status == "Pending" || status == "PENDING" || status == "SHIPMENT" || status == "DISPENSED" select t; var result = query.ToList();
如果你只是想知道是否匹配,而不是匹配的标记列表,你可以使用 Any()
,例如
var result = query.Any();
顺便说一句,以下尝试没有奏效:
尝试将逻辑运算符括起来会引发
JsonException: Unexpected character while parsing path query: (
:var filter = "$.Fields[?((@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED') && (@.Patient_Gender))]"; var query = s.SelectTokens(filter); var result = query.ToList();
在
||
之后放置&&
错误地选择了匹配||
子句之一但不匹配&&
子句的标记:var filter = "$.Fields[?(@.Status == 'Pending' || @.Status == 'PENDING' || @.Status == 'SHIPMENT' || @.Status == 'DISPENSED' && @.Patient_Gender)]"; var query = s.SelectTokens(filter); var result = query.ToList();
这里是一个 fiddle 显示工作和非工作查询。