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脚本,我们看实际执行的效果:

