如何在 C# 中拆分 OData 多级展开查询字符串?
Posted
技术标签:
【中文标题】如何在 C# 中拆分 OData 多级展开查询字符串?【英文标题】:How to Split OData multi-level expand query string in C#? 【发布时间】:2021-08-28 03:50:06 【问题描述】:我有一个网址:Expand=User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List
我需要按以下格式拆分此字符串:
User($select=Firstname,Lastname)
Organisation
Contract($Expand=MyOrganisation($select=Name,Status),Organisation)
List
如何在 C# 中实现这个功能?
【问题讨论】:
您是否有任何理由使用单个参数而不是 4 个参数?比如user=User($select=Firstname,Lastname)&organisation=Organisation等 是的,需要进行 odata 转换。 OData 是这里的东西 "$select=Firstname,Lastname",它不需要把所有东西都放在一个字符串中 Odata 支持多级过滤和扩展功能 例如:***.com/questions/51525409/… 【参考方案1】:您不仅需要拆分字符串,还需要在拆分时跟踪括号。仅使用普通的旧正则表达式是不可能的。见this post。
但是,可以通过一些高级的 RegEx 来实现拆分; .NET 幸运地支持balancing groups,您可以使用它来跟踪括号。 This answer 对提出解决方案很有帮助。为了便于阅读,我将正则表达式拆分为多行并使用了RegexOptions.IgnorePatternWhitespace
:
string url = "User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List";
Regex rgx = new Regex(
@"(.+?)
(
(
\(
(?:
[^()]
|
(?'open'\()
|
(?'close-open'\))
)+
(?(open)(?!))
\)
)
,
|
,
|
\b$
)",
RegexOptions.IgnorePatternWhitespace);
foreach(var match in rgx.Matches(url))
Console.WriteLine($"match.Groups[1] match.Groups[3]");
该字段将以match.Groups[1]
的形式提供,参数(如果有)将以match.Groups[3]
的形式提供(如果没有参数,这将是一个空字符串)。您可以访问match.Groups[0]
获取整个群组。
正则表达式分解
Regex | Description |
---|---|
(.+?) |
Non-greedily match one or more characters |
\( and \)
|
Match an actual ( and )
|
[^()] |
Match any character that is not a ( or )
|
(?'open'\() |
Create a named group with the name "open" and match a ( character |
(?'close-open\)) |
Create a group "close" and assign the interval between "open" and "close" to "close" and delete group "open" |
(?(open)(?!)) |
Assert if the "open" group is not deleted |
(?:[^()]|(?'open'\()|(?'close-open'\)))+ |
Create a non-capturing group and match one or more characters that match one of the expressions between |
|
【讨论】:
列表将不是结果的一部分并且 match.Groups[2] 将崩溃 预期:字段:合同参数:$Expand=MyOrganisation($select=Name,Status),Organisation) @AmalK 在合同字符串拆分中没有预期请给我这个想法。 完美正则表达式解释:) @AmalK 和 Boris Sokolov 这很好。非常感谢您的支持。【参考方案2】:您更有可能必须使用带有内置URI Parser 的ODataLib
Uri requestUri = new Uri("Products?$select=ID&$expand=ProductDetail" +
"&$filter=Categories/any(d:d/ID%20gt%201)&$orderby=ID%20desc" +
"&$top=1&$count=true&$search=tom",
UriKind.Relative);
ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
SelectExpandClause expand = parser.ParseSelectAndExpand(); // parse $select, $expand
FilterClause filter = parser.ParseFilter(); // parse $filter
OrderByClause orderby = parser.ParseOrderBy(); // parse $orderby
SearchClause search = parser.ParseSearch(); // parse $search
long? top = parser.ParseTop(); // parse $top
long? skip = parser.ParseSkip(); // parse $skip
bool? count = parser.ParseCount(); // parse $count
添加 RegExp 选项(Amal 在下面提供的固定版本)
string url = "User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List";
Regex rgx = new Regex(@"(.+?)(?:(\(.*?\)),|,)");
foreach (var match in rgx.Matches($"url,"))
Console.WriteLine(match.ToString()[..^1]);
【讨论】:
我们没有使用动态或 Jobject 的模型。我试过没有模型就不行。 手动解析会有问题,因为您没有特定的分隔符(逗号用于多种用途)。因此,如果您确定有 ")," 语句,然后是 "," 和 ")," - 您可以使用 IndexOf() 和 substrigns 这是使用索引和范围的好方法。请注意,它们仅从 C# 8.0 开始受支持以上是关于如何在 C# 中拆分 OData 多级展开查询字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C# 为 OData 查询中指定的每个过滤器获取一组键/值对?
从表中仅选择几列以使用 C# Web API 上的 Odata Select 查询进行映射
如何在 C# 中使用 JSON 反序列化 oData V2?