ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

『低代码平台』规则引擎、表达式解析

2022-05-15 20:01:09  阅读:241  来源: 互联网

标签:return string Parameters DateTime 引擎 new 解析 public 表达式


背景

低代码平台中的一个核心内容是规则引擎,规则引擎致力于解决灵活繁复的硬编码问题,以全新的思想和更高的灵活性解决复杂规则/表单流程规则等问题。
示例一、员工加班申请表单,当加班小时总数>36小时时,需要提示"加班小时总数已超过36H,不允许申请";


示例二、一套标准的生活费领取流程如下



...

功能介绍

  • 普通规则解析
  • 自定义规则解析(支持扩展函数)
  • 带数据的规则解析
  • 规则校验

灵活的表达式规则解析

1、不带数据的表达式解析

接口:/api/Rule/GetRuleResult/{ruleText}
用swagger模拟请求
普通计算:



比较值:



带自定义函数的计算(如Days为获取两个日期相隔的天数):

2、带数据的表达式解析

表达式中使用"{字段}"来获取数据字段值



对于比较常用的三元表达式,程序中内置了IIF函数(IIF(a,b,c) :如果表达式a为真,则取b,否则取c)。
老婆给我打电话:下班顺路买四个包子带回来,如果看到卖西瓜的,买一个。
当晚,我手捧一个包子进了家门……
老婆怒道:你怎么就买了一个包子?!
我答曰:因为看到了卖西瓜的。

完整的表达式规则校验

接口:/api/Rule/ValidateRule/{ruleText}
提供表达式校验的接口,校验表达式正确性。
表达式错误:




方法不存在错误:



方法格式错误:



方法参数错误:

代码


示例程序使用DDD架构,包含规则解析领域和组织机构领域

目录说明

└──LsqParserEngine.Application              应用层:调用领域对象
    ├── Organization               
    ├── RuleParser        									         
└──LsqParserEngine.Common										公共类
└──LsqParserEngine.Domain                   领域层:包含所有的业务规则
    ├── Organization      
      ├── Repositories										  组织机构仓储  
    ├── RuleParser 
└──LsqParserEngine.Entity                   实体层:数据实体、接口等
    ├── Organization    										组织机构实体           
    ├── RuleParser  												规则实体
      ├── Math
        ├── ExecutionItem										各种类型的解析器
        ├── Function												自定义函数
        ├── VariableTable                   数据集类型(暂时只加了字典类型)
└──LsqParserEngine.WebApi										接口层

规则解析类图

添加自定义函数

如何添加自定义函数,以Days(d2,d1)为例
1.添加函数类,继承Function (LsqParserEngine.Entity=>RuleParser=>Math=>Function)

/// <summary>
/// Days获取两个日期相隔的天数
/// </summary>
internal class DaysFunction : Function
{
    public const string Name = "Days";

    public DaysFunction(IOrganization organization) : base(organization)
    {
    }
    /// <summary>
    /// 描述的内容
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override string Describe(List<string> Parameters)
    {
       
    }
    /// <summary>
    /// 描述的html
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override string DescribeAsHtml(List<string> Parameters)
    {
       
    }
    
    /// <summary>
    /// 方法帮助:控制参数个数及参数类型
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override FunctionHelper GetHelper()
    {
       
    }
    /// <summary>
    /// 解析的实现
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override Variant Parse(FunctionExpression desc, IVariableTable variables)
    {
        
    }

    public override string FunctionName
    {
        get
        {
            return "Days";
        }
    }
}

方法说明:

  • Describe:函数描述,前台函数列表可取此内容
  • DescribeAsHtml:函数描述的html,前台函数列表可取此内容
  • GetHelper:函数帮助,包含函数名、描述、示例、入参约束(支持非必填属性)、出参约束
  • Parse:函数解析的实现

完整代码:
1.添加函数类,继承Function (LsqParserEngine.Entity=>RuleParser=>Math=>Function)

/// <summary>
/// Days获取两个日期相隔的天数
/// </summary>
internal class DaysFunction : Function
{
    public const string Name = "Days";

    public DaysFunction(IOrganization organization) : base(organization)
    {
        return string.Format("获取日期{1}与{0}相隔的天数", Parameters[0], Parameters[1]);
    }
    /// <summary>
    /// 描述的内容
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override string Describe(List<string> Parameters)
    {
        if (Parameters.Count > 1)
        {
            return string.Format("<a>{0}</a>(<a>{1}</a>,<a>{2}</a>,<a>{3}</a>)", this.FunctionName, Parameters[0], Parameters[1]);
        }
        return base.DescribeAsHtml(Parameters);
    }
    /// <summary>
    /// 描述的html
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override string DescribeAsHtml(List<string> Parameters)
    {
        if (Parameters.Count > 1)
        {
            return string.Format("<a>{0}</a>(<a>{1}</a>,<a>{2}</a>,<a>{3}</a>)", this.FunctionName, Parameters[0], Parameters[1]);
        }
        return base.DescribeAsHtml(Parameters);
    }
    
    /// <summary>
    /// 方法帮助:控制参数个数及参数类型
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override FunctionHelper GetHelper()
    {
       return new FunctionHelper(this.FunctionName,
           "获取两个日期相隔的天数",
           this.FunctionName + "({EndData},{StartData})",
           new Parameter[] {
               //Parameter重载中提供参数是否必填设置
               new Parameter("EndData", "结束日期", new DataLogicType[] { DataLogicType.DateTime }),
               new Parameter("StartData", "开始日期", new DataLogicType[] { DataLogicType.DateTime })
           },
           new Parameter("Return", "天数", new DataLogicType[] { DataLogicType.Int }));
    }
    /// <summary>
    /// 解析的实现
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    public override Variant Parse(FunctionExpression desc, IVariableTable variables)
    {
        if (desc == null || desc.Count < 1 || desc.Count > 2)
        {
            throw new CalcException("The function \"" + this.FunctionName + "\" must have two parameter.");
        }

        Variant variant = desc[0];
        Variant variant2 = desc[1];
        DateTime def1 = DateTime.Now;
        if (variant.Value == null || string.IsNullOrEmpty(variant.Value.ToString()) || !DateTime.TryParse(variant.Value.ToString(), out def1))
        {
            return new Variant(-1);
        }
        DateTime def2 = DateTime.Now;
        if (variant2.Value == null || string.IsNullOrEmpty(variant2.Value.ToString()) || !DateTime.TryParse(variant2.Value.ToString(), out def2))
        {
            return new Variant(0);
        }
        DateTime t1 = Convert.ToDateTime(def1.ToShortDateString());
        DateTime t2 = Convert.ToDateTime(def2.ToShortDateString());
        TimeSpan ts = t1.Subtract(t2);
        double diffInDays = ts.TotalDays;
        return new Variant(diffInDays);
    }

    public override string FunctionName
    {
        get
        {
            return "Days";
        }
    }
}

2.方法工厂中注入该方法

 public static Function[] Create(IOrganization organization)
 {
     return new Function[] {
         //...
         new DaysFunction(organization),
     };
 }

规则表达式中便可以使用Days()函数了。

git地址LsqParserEngine

标签:return,string,Parameters,DateTime,引擎,new,解析,public,表达式
来源: https://www.cnblogs.com/liaoshiqi/p/16274187.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有