[QMacros] 使用迭代器来重复内容

QMacros 2017年9月18日提交的版本支持了迭代器,以重复替换某一部分内容。

迭代器的声明:

IQMacroIterator = interface
    ['{3DB5D84F-0539-4C10-9476-E6B71D3099DE}']
    // 开始替换
    procedure BeginReplace(AMacro: TQMacroItem);
    // 判断是否还有要处理的数据
    function HasNext: Boolean;
    // 执行一次替换
    function Replace: QStringW;
    // 结束替换
    procedure EndReplace;
    // 获取当前活动的迭代器序号
    function GetItemIndex: Integer;
  end;

好吧,这是一个接口,这就意味着,我们绑定某个宏到这个迭代器之前,需要先实现一个迭代器。我们可以继承自 TQMacroIterator 实现一个自带的迭代器绑定,从而实现自己的替换规则。要实现自己的迭代器,可以看一下默认的 TQMacroDataSetIterator 实现来参考一下。

QMacros 内置了数据集的迭代器,假设你的数据集的 Name 为 adsData,则 adsData.@Rows 宏对应的就是一个迭代器,这个宏包含三个参数:

  • 要替换的模板,一个字符串类型的参数,转义语法遵守 C/Java 语法;
  • 模板中宏的起始字符标志字符串
  • 模板中宏的结束字符标志字符串

我们来看一个示例:

procedure TForm1.Button1Click(Sender: TObject);
const
  STableTemplate: QStringW = '<html><head><title><%Title%></title></head>' + //
    '<body>这是一个表格<table border="1"  cellspacing="0" cellpadding="0" bordercolor="#000000" style="BORDER-COLLAPSE: collapse">'
    + //
    '<th><tr><td>记录号</td><td>序号</td><td>编号</td><td>姓名</td></tr></th>' + //
    '%adsData.@Rows("<tr><td>%adsData.@RecNo%</td><td>%adsData.@Rows.@Index%<td>%Id%</td><td>%Name%</td></tr>","%","%")%'
    + //
    '</table></body>';
var
  AMacros: TQMacroManager;
  AHtmlFile, AHtmlText, ATag: String;
begin
  AMacros := TQMacroManager.Create;
  try
    AMacros.Push(adsData, '');
    AMacros.Push('Title', 'QMacros HTML Tag 替换');
    AHtmlText := AMacros.Replace(STableTemplate, '%', '%', MRF_PARSE_PARAMS);
    AHtmlFile := ExtractFilePath(Application.ExeName) + 'index.html';
    SaveTextW(AHtmlFile, AHtmlText);
    WebBrowser1.Navigate('file:///' + StringReplaceW(AHtmlFile, '\', '/',
      [rfReplaceAll]));
    AMacros.Pop(adsData, '');
  finally
    FreeAndNil(AMacros);
  end;
end;

在这个示例中,STableTemplate 是一个简单的HTML模板,我们需要将数据集adsData的内容,输出为一个HTML的表格,那么核心就在

%adsData.@Rows(“<tr><td>%adsData.@RecNo%</td><td>%adsData.@Rows.@Index%<td>%Id%</td><td>%Name%</td></tr>”,”%”,”%”)%

这一行:adsData.@Rows 在我们调用 AMacros.Push(adsData,”) 时,被自动入栈为一个迭代器,当我们调用 AMacros.Replace 来执行替换时,它会从第一条记录循环到最后一条记录,按照第一个参数指定的模板循环输出内容,如果其中包含宏定义,则会替换成相应的宏定义。

我们来看一下这段代码的执行结果:

好吧,就说到这里。具体的代码请自行 SVN/GIT 检出。

分享到: