关于模板中的动态取值 ---反射与javascript脚本编译
在项目中经常遇到一个问题,打印word或者打印excel的时候,我们经常使用一对一的赋值或者批量替换的方式来对模板进行修改。
但是现在遇到两种场景:
1、取值是通过自定以方法进行取值的。
如:一个销售单据,会涉及到很多种费用,并且这些费用是由后台配置的,非常灵活。但是我们在制作打印模板时取值各项费用我们该如何去定义他呢,如何给他赋值呢?我们如果针对这一个场景下的模板进行一个特殊定义后,在打印另一份单据或者遇到同样的取值非常灵活的数据,是不是也需要进行特殊处理呢。
2、取值是通过自行定义进行取值的。
如:还是一个销售单据,我们打印的可能是销售价格,成本、毛利,但是如果我们打印的时候涉及到提成配比,提成配比可能是根据销售价格算的,可能根据毛利算的,可能根据效益来算的,那么是不是我们在做这个模板的时候定义:提成(按成本)、提成(按毛利)、提成...。
在这中情况下,我的解决方案是采用反射与javascript进行处理:
这里大致讲述一下我的解决思路,各位过路大神,各位奋战一线的程序猿们,看过笑过,不喜勿喷~
第一步:建立两种Eval方法,来解析表达式
C#Eval反射式:(此种方式主要应对在程序中自定义的方法,根据参数及方法来模拟程序中的计算,并将结果返回过去,这种方法必须制定处理他的主体Object)
- /// <summary>
- /// CShrapEval 的摘要说明
- /// </summary>
- public class CShrapEval
- {
- /// <summary>
- /// 计算结果,如果表达式出错则抛出异常
- /// </summary>
- public static object Eval(string action,Type type,object obj,object[] parm)
- {
- return type.InvokeMember(
- action,
- BindingFlags.InvokeMethod,
- null,
- obj,
- parm
- );
- }
- public static object Eval(string Cstring, Type type, object obj)
- {
- string action = Cstring.Split('|')[0];
- object[] parm = Cstring.Split('|')[1].Split(',');
- return type.InvokeMember(
- action,
- BindingFlags.InvokeMethod,
- null,
- obj,
- parm
- );
- }
- }
JavaScript脚本编译方式:模拟javascript工作方式去处理一个表示式,可以使用一个javascript常用函数(如getdate() length等),灵活方便
- /**/
- /// <summary>
- /// 动态求值
- /// </summary>
- public class JavaEval
- {
- /**/
- /// <summary>
- /// 计算结果,如果表达式出错则抛出异常
- /// </summary>
- /// <param name="statement">表达式,如"1+2+3+4"</param>
- /// <returns>结果</returns>
- public static object Eval(string statement)
- {
- return _evaluatorType.InvokeMember(
- "Eval",
- BindingFlags.InvokeMethod,
- null,
- _evaluator,
- new object[] { statement }
- );
- }
- /**/
- /// <summary>
- ///
- /// </summary>
- static JavaEval()
- {
- //构造JScript的编译驱动代码
- CodeDomProvider provider = CodeDomProvider.CreateProvider("JScript");
- CompilerParameters parameters;
- parameters = new CompilerParameters();
- parameters.GenerateInMemory = true;
- CompilerResults results;
- results = provider.CompileAssemblyFromSource(parameters, _jscriptSource);
- Assembly assembly = results.CompiledAssembly;
- _evaluatorType = assembly.GetType("Evaluator");
- _evaluator = Activator.CreateInstance(_evaluatorType);
- }
- private static object _evaluator = null;
- private static Type _evaluatorType = null;
- /**/
- /// <summary>
- /// JScript代码
- /// </summary>
- private static readonly string _jscriptSource =
- @"class Evaluator
- {
- public function Eval(expr : String) : String
- {
- return eval(expr);
- }
- }";
- }
第二步、构建好两个eval之后我们就需要在程序中去识别那些是C#,那些是javascript代码断
这里我处理的办法是:<c ...代码 /> 和<J ...代码 />使用这两种方式分别标示是那种代码
然后在处理中我们只需要找出那些是C代码 那些是J代码,并且对代码断进行计算
- public void ExportDoc()
- {
- ExportReplace();
- foreach (NodeTemplate temp in DocTemplateList)
- {
- ExportDoc(temp);
- }
- if (ActionObject != null)
- {
- //动态取值
- ExportDymic();
- }
- }
- //定义C表达式
- System.Text.RegularExpressions.Regex RegexC = new System.Text.RegularExpressions.Regex(@"\<C\w*\|\w*[\,\w*]*\\\>");
- //定义J表达式
- System.Text.RegularExpressions.Regex RegexJ = new System.Text.RegularExpressions.Regex(@"\<J^\>*\\\>");
- //业务逻辑理论为先处理C在处理J,但是C与J由存在循环处理的过程
- public void ExportDymic()
- {
- var MatchesS = RegexC.Matches(doc.GetText());
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
- string result = CEval(Cstring);
- //CShrapEval.Eval(Cstring, this.GetType(), this).ToString();
- //A = A.Replace(MatchC.Value, result);
- doc.Range.Replace(MatchC.Value, result, false, false);
- }
- MatchesS = RegexJ.Matches(doc.GetText());
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
- string result = JavaEval.Eval(Jstring).ToString();
- doc.Range.Replace(MatchC.Value, result, false, false);
- }
- }
- public string CEval(string A)
- {
- var MatchesS = RegexC.Matches(A);
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
- string result = CEval(Cstring).ToString();
- A = A.Replace(MatchC.Value, result);
- }
- MatchesS = RegexJ.Matches(A);
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
- string result = JEval(Jstring).ToString();
- A = A.Replace(MatchC.Value, result);
- }
- return CShrapEval.Eval(A, ActionObject.GetType(), ActionObject).ToString();
- }
- public string JEval(string A)
- {
- var MatchesS = RegexC.Matches(A);
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
- string result = CEval(Cstring).ToString();
- A = A.Replace(MatchC.Value, result);
- }
- MatchesS = RegexJ.Matches(A);
- foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
- {
- string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
- string result = JEval(Jstring).ToString();
- A = A.Replace(MatchC.Value, result);
- }
- return JavaEval.Eval(A).ToString();
- }
这样就可以对表达进行精确的解析了,当然目前还有一些未考虑完全的地方 ,待各位看客老爷指点。
好的~今天就贴到这里, 后期看看被喷的程度来确定是否继续在博客园发一些日志
关于模板中的动态取值 ---反射与javascript脚本编译的更多相关文章
- mybatis中两种取值方式?谈谈Spring框架理解?
1.mybatis中两种取值方式? 回答:Mybatis中取值方式有几种?各自区别是什么? Mybatis取值方式就是说在Mapper文件中获取service传过来的值的方法,总共有两种方式,通过 $ ...
- Vue 列动态取值
在前端开发过程中,可能会遇到列动态取值的情况,即列表中某列的取值由两个或以上的字段的值决定. 用 Vue 实现的话可以用如下代码解决 <template slot-scope="sco ...
- C#中float的取值范围和精度
原文:C#中float的取值范围和精度 float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: floa ...
- JSP中EL表达式取值问题记录(已解决)
***************************2015-10-28 22:21************************* 问题描述如下: 在当前的jsp页面已经有了如下代码: < ...
- C语言中数据类型的取值范围
C语言中数据类型的取值范围如下:char -128 ~ +127 (1 Byte)short -32767 ~ + 32768 (2 Bytes)unsigned short 0 ~ 65536 (2 ...
- loadrunner 脚本优化-参数化之场景中的参数化取值
脚本优化-场景中的参数化取值 by:授客 QQ:1033553122 Action() { lr_eval_string("{NewParam}"); lr_eval_stri ...
- mysql中数据类型的取值范围
mysql整型bigint.int.mediumint.smallint 和 tinyint的语法介绍,如下: 1.bigint 从 -2^63 (-9223372036854775808) 到 2^ ...
- Struts2中EL表达式取值
http://blog.csdn.net/cuihaiyang/article/details/41950141 (写的不错,可以知道为什么struts2可以用El取属性值的问题.正常el从reque ...
- 基础学习:C#中float的取值范围和精度
float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中 ...
随机推荐
- 尼玛的,不学ORACLE RAC就不能叫高大上啊
刚才趁这段时间和机会,进去好好套弄一下. 我看不得会ORACLE人的嘴脸,于是,,,,我想试试~~~
- Spring: DispacherServlet和ContextLoaderListener中的WebApplicationContext的关系
在Web容器(比如Tomcat)中配置Spring时,你可能已经司空见惯于web.xml文件中的以下配置代码: <context-param> <param-name>cont ...
- iostat 使用说明
LINUX [oracle@perass back]$ iostat -m 1 10 Linux 2.6.18-194.el5 (perass) 03/01/2014 avg-cpu: %user % ...
- weblogic jsp 不生效解决方法
1. 检查weblogic.xml配置文件,其中如果有: <jsp-descriptor> <jsp-param> <param-name>pageCheckSec ...
- 【转】Android开发中adb启动失败adb连接异常的解决办法 offline
原文网址:http://www.cnblogs.com/yejiurui/p/4173521.html 一.情况描述: 我们在使用eclipse开发有时候会出现adb连接异常中,有时候控制台会打印出来 ...
- 自己做的网页页面导航浏览JS/JQuery_版本2(优化边缘)
版本2增加了宽宽的边界,边界内鼠标也可以导航.边界对应这HTML页面的边界.目前右下角有时会导致功能失效.版本1. 这次找了个更好的例子,实践中产生这个需求的真实例子,点我Demo. 需求: 版本1: ...
- java JDK安装
JDK安装包下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 图释安装 ...
- Selenium webdriver firefox 路径设置问题
问题: Cannot find firefox binary in PATH. Make sure firefox is installed. 原因:selenium找不到Firefox浏览器. 方法 ...
- Rules
我们之前处理异常的时候用到过Rules,当然还有很多其他规则.Rules允许弹性的添加或者重定义测试方法的行为.测试者可以重复使用或者扩展下面的某一个Rules,也可以写一个属于自己的规则. 这里先展 ...
- hdoj 1728 逃离迷宫
逃离迷宫 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...