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.
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"/>
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.
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>
...
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 |
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>
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.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
说明: 针对 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)');
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>
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>
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>