API m multi - noradle/plsql-print GitHub Wiki

将 plsql array 或者 SQL query sys_refcursor 带入模板字符串快速生成模式相同数据不同的内容。

为了减少缩进 为了是标签输出代码连续,可以把需要批量和循环处理的数据放到数组或者游标中 对于重复处理的输出,采用批量数据绑定输出API后,有机会提高性能 包括 td,th,col; option,checkbox,radio.

NORADLE 建议在循环中输出的内容不在循环中调用基本的 tag API, 而都使用 multi print 输出,特别是预先解析模板的方式,以提高性能。

m is synonym for multi package.

array wrapper series

对每个成员带入模板"@"定位点,数据成员来自逗号分割字符串

substitute template with comma separated strings demo

m.w(template@text, comma_separated_value_list) 成员是逗号(",")分割的字符串

同时支持 procedure/function 版本, 适合针对静态的一组值进行 wrap。

example :

m.w('<col class="@"/>', 'col1,col2,col3');

produce

<col class="col1"/><col class="col2"/><col class="col3"/>

对每个成员带入模板"@"定位点,数据成员来自 st

wrap each item in st with template, substitution point is at "@"

m.w(template@text, st(v1, v2, ...)) 成员是 ST string table 类型

同时支持 procedure/function 版本, 因为需要对模板解析,即便只分析唯一的一个"@",终归有一点消耗, 如果在循环中使用,尽量采用后面的 before|after 模式的 wrapper。

substitute template with ST value demo

for i in (select rownum rid, a.object_name, a.object_type from user_objects a where rownum < 10) loop
  x.p('<tr>', m.w('<td>@</td>', st(ltrim(to_char(i.rid, '09')), i.object_name, i.object_type)));
end loop;

produce

<tr><td>01</td><td>ATTR_TAGP_DEMO_B</td><td>PACKAGE</td></tr>
<tr><td>02</td><td>ATTR_TAGP_DEMO_B</td><td>PACKAGE BODY</td></tr>
...

note: table head use comma separated m.w to produce all th elements.

直接对每个成员 wrapper (before/after)

wrap every value in ST string table with before and after text

适合对各个成员处理完全一样的情形,特别是对于表格一行的各个列,都使用 TD 包围。 这个是 multi 中最简单的使用情形。

API: m.w(before_text, st(v1, v2, ...), after_text)

注:即可作为 procedure 直接输出,也有 function 版本返回结果字符串。 因为不需要解析模板,适合放到循环中使用。 也因此,该 API 只支持 ST 参数,不支持逗号分割字符串参数版本。

for i in (select *
            from user_objects a
           where a.object_name not like 'BIN$%'
             and a.object_type not like '%PARTITION'
           order by a.object_type, a.object_name) loop
  x.p('<tr>', m.w('<td>', st(i.object_name, i.object_type), '</td>'));
end loop;

produce

<tr><td>PK_EMP</td><td>INDEX</td></tr>
<tr><td>PK_TERM</td><td>INDEX</td></tr>
...

m.w APIs 综合范例

  procedure w_table is
    v_total pls_integer := 0;
  begin
    x.o('<table rules=all,cellspacing=8>');
    x.p(' <thead>', x.p('<tr>', m.w('<th>@</th>', 'package,num of procedures')));
    x.o(' <tbody>');
    for i in (select a.object_name pack, count(a.procedure_name) pcnt
                from user_procedures a
               where a.object_type = 'PACKAGE'
                 and a.procedure_name is not null
               group by a.object_name) loop
      x.p('<tr>', m.w('<td>', st(i.pack, i.pcnt), '</td>'));
      v_total := v_total + i.pcnt;
    end loop;
    x.c(' </tbody>');
    x.p(' <tfoot>', x.p('<tr>', m.w('<th>@</th>', st('total', v_total))));
    x.c('</table>');
  end;

produce

<table rules="all" cellspacing="8">
<thead><tr><th>package</th><th>num of procedures</th></tr></thead>
<tbody>
<tr><td>UPLOAD_B</td><td>1</td></tr>
<tr><td>MEDIA_B</td><td>1</td></tr>
<tr><td>LIST_B</td><td>3</td></tr>
...
</tbody>
<tfoot><tr><th>total</th><th>178</th></tr></tfoot>
</table>

note

`m.w('before@after', 'v1,v2,...')` 一般不在循环中 用于静态数据,代码简单 如范例中的 thead 中 th 名称
`m.w('before@after', st(v1,v2,...))` 涉及模板解析,不适合放在循环中 用于动态数据,带入变量 如范例中的 tfoot 中存在 total 这个变量
`m.w('before', st(v1,v2,...), 'after')` 不用解析模板,适合放在循环中 用于动态数据,带入变量 如范例中的 tbody 各行中的 td

list 模板预解析一次,重复使用,提升性能

API:

  • m.p(tempate, tmp.stv)
  • m.r(tmp.stv, st(v1, v2, ...) 同时支持 function 版本

和前面的 m.w wrapper 比,本类 API 支持模板,里面可以有多个锚点,适用更广更复杂的情形。

m.p(arse) 先将模板字符串 parse 一次,将"@" 分割的各个部分保存到 tmp.stv 数组中。
(注:之所以不像x.t那样支持:n替换,是从简单性和性能考虑,为了更简单也更快的将 tmp.stv 和 value st 做交替链接,而不用考虑非自然顺序的开销)

m.r(ender) 使用 parse 到的 tmp.stv 替代原来 m.w 的模板,不用每轮循环都做模板解析,从而提升了性能。

如果使用 x.t 如下,会比较慢,在循环中,每次都要有定位和替换。

x.o('<fieldset>');
x.p(' <legend>', 'traditional x.t, support col order/format, but has <em>bad</em> preformance');
for i in (select rownum rid, a.object_name, a.object_type from user_objects a where rownum < 10) loop
  tmp.stv := st(to_char(i.rid, '09'), i.object_name, i.object_type);
  x.t(' :1 - <label><input name="a" type="checkbox" value=":3"/>:2</label><br/>', tmp.stv);
end loop;
x.c('</fieldset>');

produce

<fieldset>
<legend>m.tpl_cur support sys_refcursor, SQL itself do col order/format, high preformance</legend>
1- <label><input name="a" type="checkbox" value="ATTR_TAGP_DEMO_B"/>PACKAGE</label><br/>
2- <label><input name="a" type="checkbox" value="ATTR_TAGP_DEMO_B"/>PACKAGE BODY</label><br/>
...
</fieldset>

现在使用 m.p, m.r 提速

  procedure parse_render_table is
  begin
    src_b.header;
    x.o('<table rules=all,cellspacing=8>');
    x.p(' <caption>', 'm.parse once, m.render repeatly, high proformance');
    m.p(' <tr><th>@</th><td>@</td><td>@</td></tr>', tmp.stv);
    for i in (select rownum rid, a.object_name, a.object_type from user_objects a where rownum < = 3) loop
      m.r(tmp.stv, st(to_char(i.rid, '09'), i.object_type, i.object_name));
    end loop;
    x.c('</table>');
    src_b.footer;
  end;

produce

<table rules="all" cellspacing="8">
<caption>m.parse once, m.render repeatly, high proformance</caption>
<tr><th> 01</th><td>PACKAGE</td><td>ATTR_TAGP_DEMO_B</td></tr>
<tr><th> 02</th><td>PACKAGE BODY</td><td>ATTR_TAGP_DEMO_B</td></tr>
<tr><th> 03</th><td>PACKAGE</td><td>AUTH_B</td></tr>
</table>

m.prc 针对 sys_refcursor 带入 repeater

synopsis

m.prc('template@for@every@row', sys_refcursor);

  • sys_refcursor 中要为带入模版排好正确的字段的顺序,和模板的插入点"@"位置匹配
  • sys_refcursor 对输出字段进行正确的格式化,因为不想前面的 m.r 前还能在SQL外用PL/SQL对select出来的字段值进行加工再代入
  • 内部实现也是先 parse 模板,再在SQL结果集中的每一条带入 parse 过的模板,因此性能很好。
  • 和前面分开 parse/render 的方式相比,SQL和页面标签前后完全分离,代码标签结构清晰,页面生成代码的可读性很高。
  procedure cursor_render_table is
    cur sys_refcursor;
  begin
    src_b.header;
    open cur for
      select a.object_name, a.object_type from user_objects a where rownum <= 3;
    x.p('<p>', 'sys_refcursor to simple fill ul list');
    x.o('<ul>');
    m.prc('<li><b>@</b><small> - (@)</small></li>', cur);
    x.c('</ul>');
    src_b.footer;
  end;

produce

<p>sys_refcursor to simple fill ul list</p>
<ul>
<li><b>ATTR_TAGP_DEMO_B</b><small> - (PACKAGE)</small></li>
<li><b>ATTR_TAGP_DEMO_B</b><small> - (PACKAGE BODY)</small></li>
<li><b>AUTH_B</b><small> - (PACKAGE)</small></li>
</ul>

使用 m.p/m.r 组合和使用 m.prc 的比较

  • m.prc : html source is natural, more clear
  • m.p/m.r : sql fetch data only, give chance to do all conversion/filter/process in pl/sql before filling final data in ST

m.nv API

说明: 针对 option,checkbox,radio 等需要2组值,和设置是否选上的情形。

模板只带入 value, name 先后两个插入点, 模板中除了有"@"替换点意外,还有 "?string", 如果 value/name 字段值在 sv(select values) 之内, 则输出 "string", 否则空着不输出。

synopsis

open cur for select value, name from ...;
m.nv('<label><input ?checked type="checkbox",value="@"/>@</label>', cur, 'selected_value1,selected_value2,...');
m.nv('<label><input ?checked type="radio",value="@"/>@</label>', cur,'selected_value');
m.nv('<option ?selected value="@">@</option>'), cur,'selected_value(s)');

radios options example

procedure nv_form_radios is
  cur sys_refcursor;
  sv  varchar2(4000) := r.getc('sv', 'AUTH_B');
begin
  src_b.header;
  open cur for
    select a.object_id, a.object_name from user_objects a where rownum < 10;
  x.p('<h1>', 'radios / function edition');
  x.o('<fieldset>');
  x.p(' <legend>', 'radio groups');
  x.p(' <div>', m.nv('<label><input ?checked type="radio" name="single" value="@"/>@</label><br/>', cur, sv));
  x.c('</fieldset>');
end;

produce

<h1>radios / function edition</h1>
<fieldset>
<legend>radio groups</legend>
<div><label><input type="radio" name="single" value="93199"/>ATTR_TAGP_DEMO_B</label><br/>...</div>
</fieldset>

checkboxes example

http://localhost:8889/demo1/m_multi_b.nv_form_checkboxes

procedure nv_form_checkboxes is
  cur sys_refcursor;
  svs varchar2(4000) := r.getc('sv', 'AUTH_B,BASIC_IO_B');
begin
  src_b.header;
  open cur for
    select a.object_id, a.object_name from user_objects a where rownum < 10;
  x.p('<h1>', 'checkboxes / procedure edition');
  x.o('<fieldset>');
  x.p(' <legend>', 'checkbox groups');
  x.o(' <div>');
  m.nv(' <label><input ?checked type="checkbox" name="single" value="@"/>@</label><br/>', cur, svs);
  x.c(' </div>');
  x.c('</fieldset>');
end;

produce

<h1>checkboxes / procedure edition</h1>
<fieldset>
<legend>checkbox groups</legend>
<div>
<label><input type="checkbox" name="single" value="93199"/>ATTR_TAGP_DEMO_B</label><br/>
<label><input type="checkbox" name="single" value="93500"/>ATTR_TAGP_DEMO_B</label><br/>
<label><input checked type="checkbox" name="single" value="93253"/>AUTH_B</label><br/>
<label><input checked type="checkbox" name="single" value="93501"/>AUTH_B</label><br/>
<label><input type="checkbox" name="single" value="93252"/>AUTH_S</label><br/>
<label><input type="checkbox" name="single" value="93502"/>AUTH_S</label><br/>
<label><input checked type="checkbox" name="single" value="93251"/>BASIC_IO_B</label><br/>
<label><input checked type="checkbox" name="single" value="93503"/>BASIC_IO_B</label><br/>
<label><input type="checkbox" name="single" value="93366"/>BOM_B</label><br/>
</div>
</fieldset>

也可以用通用的标准的 m.p, m.r 替换

procedure parse_render_st_boolean is
  svs varchar2(4000) := r.getc('sv', 'AUTH_B,BASIC_IO_B');
begin
  src_b.header;
  x.p('<h1>', 'checkboxes / procedure edition');
  x.o('<fieldset>');
  x.p(' <legend>', 'checkbox groups');
  x.o(' <div>');
  m.p(' <label><input @ type="checkbox" name="single" value="@"/>@</label><br/>', tmp.stv);
  for i in (select a.object_id, a.object_name from user_objects a where rownum < 10) loop
    m.r(tmp.stv, st(t.tf(t.inlist(svs, i.object_name), 'checked'), i.object_id, i.object_name));
  end loop;
  x.c(' </div>');
  x.c('</fieldset>');
end;

produce

<h1>checkboxes / procedure edition</h1>
<fieldset>
<legend>checkbox groups</legend>
<div>
<label><input  type="checkbox" name="single" value="93199"/>ATTR_TAGP_DEMO_B</label><br/>
<label><input  type="checkbox" name="single" value="93500"/>ATTR_TAGP_DEMO_B</label><br/>
<label><input checked type="checkbox" name="single" value="93253"/>AUTH_B</label><br/>
<label><input checked type="checkbox" name="single" value="93501"/>AUTH_B</label><br/>
<label><input  type="checkbox" name="single" value="93252"/>AUTH_S</label><br/>
<label><input  type="checkbox" name="single" value="93502"/>AUTH_S</label><br/>
<label><input checked type="checkbox" name="single" value="93251"/>BASIC_IO_B</label><br/>
<label><input checked type="checkbox" name="single" value="93503"/>BASIC_IO_B</label><br/>
<label><input  type="checkbox" name="single" value="93366"/>BOM_B</label><br/>
</div>
</fieldset>
⚠️ **GitHub.com Fallback** ⚠️