首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在OData $filter中解析C#

如何在OData $filter中解析C#
EN

Stack Overflow用户
提问于 2018-07-04 12:09:19
回答 2查看 5.2K关注 0票数 10

操作odata滤波器

如何在后端操作筛选器,并希望筛选查询参数的键值对?

表达式如下

?$filter=((命名为eq 'John‘或名称eq 'Grace Paul')和(部门eq’财务和会计‘)

因为有两个过滤器连接在一起&我如何获得以下值

代码语言:javascript
复制
Filter 1:
    Key: Name
    Operator: eq
    Value: Name

Operator: or

Filter 2:
    Key: Name
    Operator: eq
    Value: Grace Paul

Operator: and

Filter 3:
    Key: Department
    Operator: eq
    Value: Finance and Accounting

我试过

  • ODataUriParser,,但它似乎不支持ASP.NET核心2.1WebAPI。
  • 正则表达式--使用此堆栈溢出问题,它在我的示例中似乎不起作用,因为我的第三个筛选器在值中包含&因此正则表达式失败。
  • 方法中的ODataQueryOptions,但它给出的原始文本不能被提取到上述的键值对。

我使用ASP.NET Core2.1WebAPI和OData v4集成

有什么办法可以做到这一点吗?

EN

回答 2

Stack Overflow用户

发布于 2020-02-12 12:46:21

您可能需要考虑定义自己的解析器,然后遍历天冬氨酸以获得所需的值。有很多工具可以做到这一点(参见flex )。但是在.net世界中,反讽可能是一个可行的选择:它在.net standard 2.0中是可用的,我在.net core 2.1控制台测试项目中没有问题。

首先,通常需要定义语法。幸运的是,微软一直对向我们提供EBNF参考资料很好,所以我们所要做的就是让它适应讽刺。最后,我实现了上面语法的一个子集,它似乎满足了您的示例语句的需要(稍微超出了一点,可以随意地减少它)。

代码语言:javascript
复制
using Irony.Parsing;

namespace irony_playground
{
    [Language("OData", "1.0", "OData Filter")]
    public class OData: Grammar
    {
        public OData()
        {
            // first we define some terms
            var identifier = new RegexBasedTerminal("identifier", "[a-zA-Z_][a-zA-Z_0-9]*");
            var string_literal = new StringLiteral("string_literal", "'");
            var integer_literal = new NumberLiteral("integer_literal", NumberOptions.IntOnly);
            var float_literal = new NumberLiteral("float_literal", NumberOptions.AllowSign|NumberOptions.AllowSign) 
                                        | new RegexBasedTerminal("float_literal", "(NaN)|-?(INF)");
            var boolean_literal = new RegexBasedTerminal("boolean_literal", "(true)|(false)");

            var filter_expression = new NonTerminal("filter_expression");
            var boolean_expression = new NonTerminal("boolean_expression");
            var collection_filter_expression = new NonTerminal("collection_filter_expression");
            var logical_expression = new NonTerminal("logical_expression");
            var comparison_expression = new NonTerminal("comparison_expression");
            var variable = new NonTerminal("variable");
            var field_path = new NonTerminal("field_path");
            var lambda_expression = new NonTerminal("lambda_expression");
            var comparison_operator = new NonTerminal("comparison_operator");
            var constant = new NonTerminal("constant");

            Root = filter_expression; // this is where our entry point will be. 

            // and from here on we expand on all terms and their relationships
            filter_expression.Rule = boolean_expression;

            boolean_expression.Rule = collection_filter_expression
                                      | logical_expression
                                      | comparison_expression
                                      | boolean_literal
                                      | "(" + boolean_expression + ")"
                                      | variable;
            variable.Rule = identifier | field_path;

            field_path.Rule = MakeStarRule(field_path, ToTerm("/"), identifier);

            collection_filter_expression.Rule =
                field_path + "/all(" + lambda_expression + ")"
                | field_path + "/any(" + lambda_expression + ")"
                | field_path + "/any()";

            lambda_expression.Rule = identifier + ":" + boolean_expression;

            logical_expression.Rule =
                boolean_expression + (ToTerm("and", "and") | ToTerm("or", "or")) + boolean_expression
                | ToTerm("not", "not") + boolean_expression;

            comparison_expression.Rule =
                variable + comparison_operator + constant |
                constant + comparison_operator + variable;

            constant.Rule =
                string_literal
                | integer_literal
                | float_literal
                | boolean_literal
                | ToTerm("null");

            comparison_operator.Rule = ToTerm("gt") | "lt" | "ge" | "le" | "eq" | "ne";

            RegisterBracePair("(", ")");
        }
    }
}

一点提示:带有讽刺意味的语法资源管理器工具允许您加载语法dll并使用它们进行调试,因此我建议您将类放在自己的项目中。然后,您就可以更容易地将您的头围绕在这些概念上:

在您满意语法之后,您需要从您的项目中引用它并解析输入字符串:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        var g = new OData();
        var l = new LanguageData(g);
        var r = new Parser(l);
        var p = r.Parse("((Name eq 'John' or Name eq 'Grace Paul') and (Department eq 'Finance and Accounting'))"); // here's your tree
        // this is where you walk it and extract whatever data you desire 
    }
}

然后,您所要做的就是遍历生成的树,并根据sytax类型应用您的自定义逻辑。在这就是答案中可以找到一个如何做到这一点的例子。

根据您的需求,您可能会发现这对您的目的来说是完全过度的,或者实际上可能会发现它所提供的控制级别是完全正确的。

票数 3
EN

Stack Overflow用户

发布于 2019-02-07 08:04:04

我知道这不是解决办法,但与你分享,以防万一以后对你有帮助。这将匹配“:”右侧的所有值。

代码语言:javascript
复制
/(?<=: )[\w ]+/gm
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51173380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档