QMacros 做为一个模板替换库,拥有良好的属性。结合合适的策略,可以很好的完成复杂的功能。
我们下面的这个例子,试图基于 QMacros 模板生成一个SQL批量插入脚本,首先我们来看下模板定义:
insert into mytable(Id,Name,Age,Sex,Scale,Comment) values ([Id.Quoted],[Name.Quoted],[Age],[Sex],[Scale],[Comment.Quoted]);
这个是我们生成一个简单 SQL 的模板定义,模板中宏以 ‘[‘ 开始,以 ‘]’ 结束,如果一个字段加入 .Quoted 代表这个字段的值要被替换为用单引号引起来的字符串。
好了,我们先看一下这个执行宏替换的效果:
嗯,看起来效果不错,可是只有一次记录,如果我们要批量生成所有记录的SQL语句我们怎么办?我们在 QMacro 的一个演示程序中,利用了 OnMissedMacro 事件来做了一个动态的宏处理。这里我们的测试环境是 XE7,使用了它的匿名函数版本,先直接上代码:
procedure TForm1.Button1Click(Sender: TObject); var AMacros: TQMacroManager; begin AMacros := TQMacroManager.Create; AMacros.BooleanAsInt := True; FDataSet.DisableControls; Memo1.Lines.BeginUpdate; try Memo1.Lines.Clear; AMacros.Push(FDataSet, ''); AMacros.SetOnMacroMiss( procedure(ASender: TQMacroManager; AName: QStringW; const AQuoter: QCharW; var AHandled: Boolean) begin AHandled := StartWithW(PQCharW(AName), 'Repeat:', True); if AHandled then ASender.Push(AName, procedure(AMacro: TQMacroItem; const AQuoter: QCharW) var AReplace: TQMacroComplied; AHelper: TQStringCatHelperW; begin AReplace := AMacros.Complie(DequotedStrW(Copy(AMacro.Name, 8, MaxInt), '"'), '[', ']'); if Assigned(AReplace) then begin AHelper := TQStringCatHelperW.Create; try FDataSet.First; while not FDataSet.Eof do begin AHelper.Cat(AReplace.Replace).Cat(SLineBreak); FDataSet.Next; end; AMacro.Value.Value := AHelper.Value; finally FreeAndNil(AHelper); FreeAndNil(AReplace); end; end; end); end); Memo1.Lines.Text := AMacros.Replace(edtExp.Text, '[', ']'); finally Memo1.Lines.EndUpdate; FreeAndNil(AMacros); FDataSet.EnableControls; end; end;
首先,我们约定了一个格式,如果宏以 “Repeat:” 打头,则认为是重复数据集中的所有记录,这个宏后面实际替换的模板以双引号包起来,以避免直接每一次解析时就被解析到,下面是上面的改良的模板:
[Repeat:"insert into mytable(Id,Name,Age,Sex,Scale,Comment) values ([Id.Quoted],[Name.Quoted],[Age],[Sex],[Scale],[Comment.Quoted]);"]
好了,我们下面回过来看上面贴的代码:
- AMacros.SetOnMacroMiss 在处理函数中检查未找到的宏是否以 “Repeat:” 打头
- 如果不是,则直接返回,程序会报告无法找到指定的宏定义;
- 反过来,如果找到了,则Push这个宏对应的解析函数,而这个解析函数我们为了直观一些,也直接做成了匿名函数
- 以 Repeat 打头的宏的解析函数做以一系列处理:
- 将 Repeat 宏名称中,引用中的内容去除引号,得到的原始内容进行编译;
- 循环数据集,对每一条记录执行一次替换并将替换结果拼接到一起,做为这个宏的值返回;
经过上面的处理,这个宏就完成了循环处理,生成了整个SQL脚本,我们看实际执行的效果: