_____ _________ ________ ___ ___ _________ ________
/ __/ \_ ____/ \ ) | | | | \_ ____/ \ )
\__ \ | _)_ | __ _/ | | | | | _)_ | __ _/
___\ \ | \ | | \ \ \ \_/ / | \ | | \ \ solutions
\____/ /_____ / /_/ \ \ \ / /_____ / /_/ \ \
\/ \/ \_/ \/ \/
(c) Lada 'Ray' Lostak (c) Orcave (c) 2002-2005
Content:
Server Thin Client Library
History:
05/18/2002 Ray - initial version
12/18/2004 Ray - PHP part of STLC moved out into CBS
Template engine
---------------
Template is text file, which creates 'output' (for example HTML). It communciates with script by
'variables', 'arrays' and 'functions'.
Template directions stars with { and end by pair }. Inside can be commands, simple variable refs,
macros references, etc.
Tags doesn't remove any blanks or doesn't insert any additional blanks. One exception are commands.
Commands remves _ALL_ blanks before and after, if there are not present any other characters. It works
only within 'one line'. To be open, not ALL commands are remoing blanks. Usually, commands like if/else/include
are doing that. Commands like tcell, ... are not skipping. So, generaly, commands generating some 'output' doesn't
skip any blanks.
Example:
some text {command ...} continues ----> some text continues [ofsource, command can generate some text]
some text {command ...} [new line]
continues ----> some textcontinues
some text
{command ...} ----> some text continues
continues
some text {!command ...} [new line]
[new line]
continues ----> some text{new line}
continues
All directives have to be placed at one physical line.
1.0 General
-----------
TPL engine includes 'internal' and 'external' functions. Internal functions are called by
{:function param}
External
{*function param}
External functions are added to TPL engine by calling script or can be added by library.
TPL library is added to TPL engine by:
{:lib lib_name}
This command adds into TPL engine given 'library'. Library have full control over TPL engine,
can 'learn' some tables/variables/macros, add functions, whatecer.
System administrator have to install libraries.
TPL engine can use powerfull macros. Macros are referenced by
{!macro params}
Default 'command' is to refence variable
{varname} -> expands to value of 'varname'
Language string is referenced by
{@lng_id} -> translated and expand into text
Comment - everything to EOL (including) is ignored:
{// comment
Many commands support 'quit' mode, which doesn't generate 'error' - for example if referenced variable
doesn't exists. Use:
{?....
where ... is 'original' command.
Example:
{?varname}
{?:if varname=}
If you need to use { symbol, double it {{
1.1 Variables
---------------
Any text references inside template as {NAME} is replaced by value sets by script.
Example:
Script exports 'AUTHOR'. And it sets AUTHOR to 'Orcave inc.'
Author {AUTHOR} ---> Author Orcave inc.
No blanks are skipped around {..} tags.
Template can 'self' learn variables. Value, which template learns override original value.
{:learn var_name value}
If value includes HTML tags, they are converted to html entities.
There is also one way how to reference variable value:
{:var name}
This is identical to {name} but usefull sometimes.
1.2 Tables
-------------
Script can export tables. In this case, template have to create 'loop' to print all table context.
Its format:
{:tloop table_name [loop_name]}
inner loop
{:tloop}
This set of code 'executes' inner loop for every table row. If loop_name not given, table_name used
by default. table_name is required for nested loops with same datas. Table value can be referenced by
{:tval col_name[@loop_name]}
where col_name is 'name' of requested column from table (column name). It is required if table
hold more columns. If name not given, most 'inner' table loop is used.
General table commands:
{:tlen table_name} expand into integer - total table rows
{:trow loop_name} expand into integer - current "row"
Example:
PHP script exports table 'powers' which have 2 columns - 'num' and 'power'. We want to print it
into table. Template will look:
Order
Number
Power>
{:tloop powers}
{:trow powers}
{:tval num}
{:tval power}
{:tloop}
1.2.1 Accessing table data
--------------------------
Table cell can be directly accessed by tcell command:
{:tcell table col val_to_find col_to_return default_value}
searchs 'table' for row, where column 'col' will be equal 'to val_to_find' and will return
colum 'col_to_return' of matched row. If no row found, it returns 'default_value'
If you want to access some cell by its row number, you can use command tcellrow
{:tcellrow table row_number_from_zero column_to_return default_val}
If exists specified line and column, its value is returned. If not, default value is used instead.
Similar way can be replaced cell value:
{:tset table col val_to_find col1=val1&col2=val2&....}
All rows matching 'col=val_to_find' sets col1 to val1,col2 to val2 and so one.
Tables rows can be deleted by using command trowdel:
{:trowdel table col value}
All rows, where 'col' is equal to 'value' are deleted.
Table columns can be created on fly. There exists command trowexp which creates column from expreesion:
{:trowexp table col expression}
For each row of 'table' is processed 'expression' and stored co new column 'col'. Expression can include
other column names and operator : +-/*
Examle:
name price quantity price_tot
------------------------ ---------
beer1 20 2 {:trowexp table pricetot price*quantity} 40
beer2 50 4 will add column 'pricetot': 200
beer3 10 1 will add column 'pricetot': 10
Whole column in table can be also compuer by expression:
{:tcolewxp table expression}
This command expands into result of adding expression processed to each table row.
Example:
Look at previous table (columns: name/price/quantity/proce_tot). Command
{:tcolexp table price_tot} will expand to '250'
{:tcolexp table price_tot*2} will expand to '500'
Table can be also cleaned - all rows (and columns) will be deleted:
{:tclean table}
There also way how to glue 2 tables togeher. Imagine, you have table A and B. Both are connected by key:
{:tglue dst src col}
Every row of table dst is enhaced about columns in table src. 'col' is column name, which connects both tables.
It is like JOIN in database. If table src doesn't include row referenced by dst, it is DELETED from dst table.
Example: imagine table above (table1) and new table2:
name developer address
----------------------------------
beer1 Krusovice Krusovicka 123
beer2 Gambrinus Ceske pivovary a.s.
{:tglue table1 table2 name) will CHANGE 'table1' to:
name price quantity price_tot developer address
--------------------------------------------------------------------
beer1 20 2 40 Krusovice Krusovicka 123
beer2 50 4 200 Gambrinus Ceske pivovary a.s.
table row with 'beer3' were deleted, because there was no record found in table2.
if you will exchange table1/table2, new table will include all beers inside.
Tables can by simply copyied over:
{:tcopy dst src}
Table can be searched for specified cell:
{:tcheck table col value}
If table includes row in column 'col' with value 'value', then command expands to 1. Otherwise 0.
Example:
{:tcheck beers developer Krusovice} expands to 1
{:tcheck beers developer Gambac} expands to 0
Cells can be connected together into list by:
{:tlist table col}
List is divided by ,
Example:
{:tlist beers developer} will expands into "Krusovice,Gambrinus"
Runtime can be also inserted rows of tables
:tinsert tablename params
and
:tset tablename column value params
tinsert commands inserts new row into tablename. If table doesn't exists, it is created. tset sets particular
rows in table, which meet condition 'column=value'. If more rows matchs given conditions, ALL rows are processed
by 'params'. Params are parameters, from which are sets columns and their value. It uses URL form, that is
col=val&col2=val2&and so one.
Example:
{:tinsert mytable name=Krusovice&kind=beer&price=20}
{:tinsert mytable name=Whiskey&kind=hard&price=99}
{:tset mytable name Krusovice price=22}
will create following table:
name kind price
------------------------------------
Krusovice beer 22
Whiskery hard 99
For self learning bigger tables exists 'multi learn' command, whcih also allows to learn nested tables. Its form:
{:tinsertm tablename}
col = val [new line us used as colum delimiter]
col2 = val
col3 { [sub table]
col1 = val
col2 = val
}
col4 { col1,col2 [sub table with 'list' as column datas, ',' used as value delimiter]
val,val [new line separate RECORDS]
}
col5 = val
col6 = {:exec "{var 1}" "{var 2}"}
{:tinsertm}
Both modes also know enhanced format of "tablename". Table should be simple table name (like previous examples)
or
tablename.column:columncompare.value
tablename.column.column2:column.value:column2.value2
If this enhanced form is used, TPL engine inserts new row in subtable 'column' (or sub-sub). Table column
'columncompare' is searched for 'value' and if found, new row is inserted in the searched column row.
Example:
{:tinsertm mytable.exporters:name.Krusovice}
name=some_exporter
address=some_address
{:tisertm}
This example will search table 'mytable' and it will try to locate row, where 'name' is set to 'Krusovice'. In this
row, it will insert new record (name/address) to column called 'exportes'
tinsert & tinsertm automaticlaly entities datas. If you want to usnert RAW datas (x-site scripting !) use raw
form of these 2 commnads:
:tisertraw
:tinsertrawm
All parametres and using are exactly same, except entiting of datas.
1.2.2 Accessing tree related data
---------------------------------
Data into table can be access as 'tree' strucutre. It is required to have '2' columns, one unique 'id' and second
'parent'. Their meaning are usual.
Visualising tree - {:ttree} commands
Table tree - {:ttree img1,img2,size,x,link,nodes}
This command allows generating 'tree' structure (from table records). It uses folowing parametres:
img1 - path to 'tree' icons, * in name is replaced by required 'tree' item
0 empty
1 line down
2 line down-left
3 line down+left
4 line down-left and +
5 line down+left and +
6 line down-left and -
7 line down+left and -
img2 - like previous, but used for 'icons'
size - icon size (width=height)
x translate order for 'img2', X offsets:
0 default folder
1 default item
link - | divided 2 parts:
first: folder related
second: item related
Available contents:
"click:exec" - 'exec' after L click
"rclick:exec" - 'exec' after R click
navigation +-
"..." - default 'navigation' (open/close/...) - '...' are 'base' parametres
item/folder
"ref:link" - link (autoamticly added 'treenodes')
"..." - nothing
nodes - optinal, name of 'treenodes' (default: treenodes)
If you need to wipe out a part of tree structure, you can use command:
{:ttreenodes dst src[.parent[.id]] [start] [depth]}
This commands creates table 'dst' with rows which coresponds to rows from 'src', starting by node 'start'
(root by default) and goes into depth (1 by default). If parent is not given, 'parent' is used. Similar
for id.
Getting 'path' in tree is also trivial:
{:ttreenodes dst src[.parent[.id]] node}
Like previous command, except it returns rows (root to depth way) which are required to walk from
root node to tree 'node'. Including.
Rows can be sorted as 'tree' byu using:
{:ttreesort table id_col parent_col}
1.2.3. Miscellaneous functions
------------------------------
Table can be sorted, using {:tsort} command.
{:tsort col1}
{:tsort col1 col2...}
Nothing to add :)
Table also allows 'automatic' positions dections. Function is called 'tpos'
{:tpos loop_name}
This command 'expands' to flags - set of letters. Letters can be combined together. Known flags:
s - start of table (first row)
e - end of table (last row)
u - upper lines (first to last but one)
b - bottom (second to last)
m - middle (all out of first and last)
Table example:
Flags
+-------+-------------------+
| 12 | somedata | su
+-------+-------------------+
| 34 | somedata | ubm
+-------+-------------------+
| 45 | somedata | ubm
+-------+-------------------+
| 56 | somedata | ubm
+-------+-------------------+
| 12 | somedata | ubm
+-------+-------------------+
| 44 | somedata | e b
+-------+-------------------+
It can be used in conjuction with {:if to easy generation of header/footers/.... See also :if for '#=' equal
command.
1.3 User macros
---------------
Teplate can define macro. Its form:
{:macro name ....}
where 'name' is macro identifier and EVERYTHING after ONE blank and closing { is 'body of macro'. Macro
is referenced by
{!name}
Example:
{:macro test my big body}
some text with {!test} macro ref ---> some text with my big body macro ref
Macro can use parametres. Parametres count are not checked in any way. In macro body, you can use '@@1' for
reference first parameter, '@@2' for second, etc. While referencing macro, just simply make spaces
between parametres. Parametres are between closing } and macro name. Example:
{:macro test My macro with param1: @@1 and param2: @@2}
and use
{!test sex beer)
will end as
My macro with param1: sex and param2: beer
There is no way how to pass parameter which includes space. Use or similar if required.
Macro can be defined without initial valie assigment. Its form:
{:macro macro_name }
Space between macro name and ending } is required.
Macro body can't include special characters:
new line
{ or }
backslah - \
If you need to use some of these special chars, make it by following table:
{ -> \{
} -> \}
new line -> \n
\ -> \\
Macro can also execute next command (any) or call different macro/etc. Be aware of recursions !
Example of multi command process:
{:macro text_id 0001}
{:macro put_text_id My text ID is \{!text_id\}\{:macroinc text_id\}}
learned as -> My text ID is {!text_id}{:macroinc text_id}
_BUT_ without \{ \} -> My text ID is 001
{!put_text_id) -> My text ID is 0001
{!put_text_id) -> My text ID is 0002
{!put_text_id) -> My text ID is 0003
{!put_text_id) -> My text ID is 0004
See {:macroinc} for more details. See, that second directive uses \{ \} instead of direct { }. It
is because parser can't derermine, if you mean END or just 'some bracket'.
1.3.1 Macros on fly
-------------------
Template allows redefinning macros on fly. It means, you can re-define macro after its definition.
THere are few special which helps.
{:macroinc macro_name}
This cimmand 'increases' numeric value of given macro. It assumes, macro value consits of
two parts - name and numerical ID - for example: Picture0001. '0' is used as delimiter.
Macro keeps length of numeric part. Separating 0 is required -> it is not possible to do
for example. one number based ID - like Picture0, because after first increation, command
will not be abble to deremine where numerical part start. Example:
{:macro test Pic0001}
{:macroinc test} -> macro will be Pic0002
{:macroinc test} -> macro will be Pic0002
{:macroinc test} -> macro will be Pic0003
etc.
This is iseful for example, when you're generating code, where inside one macro body
you have to use some 'id' and next time 'different'.
{:macroadd macro_name what_to_add}
{:macroaddpar macro_name what_to_add}
Command works similar to previous, except it adds to macro body 'what_to_add'. List is
can be comma (,) separated - if user 'macroaddpar' version
{:macro test beer}
{:macroadd test &sex} -> macro will be "beer&sex"
{:macroaddpar test water} -> macro will be "beer&sex,water"
etc.
Example - let's look how it can help in real word. Imagine you're generating menu on fly,
and you have to generate 'mouse over' buttons (using java script).
We will use from script functions: MM_swapImgRestore,MM_swapImage.
How to fully automatize ?
First define 'id'
{:macro mm_img_id img_0001}
Then define container, which we will use for 'preload' images (see down). Set to empty value.
{:macro mm_img_preload }
// and our macro - first parameter nomral image, second mouse over.
{:macro mm_img \{:macroinc mm_img_id\}\{:macroadd mm_img_preload '@@2'\}}
Use:
{!mm_img images/normal.png images/mouse_ober.png}
Verry simple and powerfull. How it works ?
Macro generates proper script using 'current id'. Then it increases 'id' and store 'mouse over' file name
to container.
But there is small problem. 'preload' executed BEFORE tempalte executes real HTML code. So, see next
command which solves our problem.
1.3.2 Macro replace
-------------------
Sometimes you need to 'store' some results to HTML after template generates page. FOr example, when macros
creates 'list' of used parametres. This command allows to repalce ANY text in template by some macro body.
{:macrorep macro_name text_name}
macro_name is name of macro, which replaces 'text_name' within WHOLE generated output. You can use
this commadn also as regular search & replace:
{:macro replace
}
{:macrorep replace }
Above commands replaces in generated output by
. Only generated contents is processed.
It doesn't work 'to future'.
some text is here
{:macro replace nice_text}
{:macrorep replace text}
some other text is here
This piece of code replaces only FIRST line to "some nice_text is here".
Example:
Imagine we're creating list of used 'mouse over' images. It will be stored in mm_img_preload. Normally,
we want to put onLoad=(...) in some script or at tag.
real contents
So, as you can see, if we will not use post-replace, we code will not work, because container
at tag is empty. None image were generated yet. So, how to do ?
real contents
....
{:macrorep mm_img_preload ___PRELOAD___}
And this works :o) Just make sure, you select unique text identifier for replace, in this case.
1.3.3. Multiline macros
-----------------------
Multiline macros work similar way like normal macros. The only difference are tags:
{:mmacro macro_name}
Body of macro
with more lines
{:mmacro}
1.4 Including
-------------
Template can include any other templates in separate files. Be aware of recursions. Command form:
{:include path_to_file}
Included file 'shares' all variables - macros, variables, tables, etc. File can be included in loops.
If you want to 'end' current included file execution, use
{:return}
This commands skip entire remaining contents of current file and returns to 'caller'.
1.5 Conditions
--------------
Template can change its contens in dependency on conditions. Condition can test 'variable' exported by
script, or 'macro'.
Contruct:
{:if !macro=value} or {:if variable=value}
statement
{:endif}
Or form with else block:
{:ife !macro=value} or {:if variable=value}
statement
{:else}
statement
{:endif}
Value is taken from equal (=) up to > AS IS. Including spaces, blank characters, etc. Instead of equal can
be used non equal operator !=.
Example:
{:ife design=blue}
{:else}
{:endif}
Additional condition test is '#='. Its form is
string#=letters_to_test
This condition becomes true, of 'string' includes one or more letters_to_test. Its main purpose is to test
'flags' (see :tpos for example)
1.6 Comments
------------
It is recomended to use tempalte commets rather HTML one, because temaplte engine removes comments.
Comment starts with {// and end with EOL. Example:
{// this is my comment
....
1.7 Exit
--------
Sometimes is required debug template and immediatelly send to browser result and quit parsing. You
can use {:exit} command for these purposes. Command doesn't have any real use, except debug.
There is also possible to 'exit' only current file, but continue other includes. For this purposes ther is
built in command {:return}
1.8 Multilanguage support
-------------------------
Template support languages. How it works ? All text are written in SEPARATE file. More languages
means, you have more files (english, deutch, ...). Format of file is following:
----test.lng cut here----
@@language_id@@ body can start here
and continues
@@language_id2@@ or can be just one-line based
@@language_id3@@
or for larger text
you can use any
lines you want
----test.lng cur here----
By directive {@language_id} you reference language string. So, in our case, code:
{@language_id3}
Will expand to
or for larger text
you can use any
lines you want
As you can see, blanks around text are stripped out. It is recomended to use 'clever' language ID's.
Last thing to explain is how to use some file. By command
{:lng file}
where file is language file with contents showed above. In our case, we will use {:lng test.lng}
Real multilanguage have to be done with support of script side. Script can 'read' proper language,
so, template will not include anything (and german ppl will see german text and english english). Or
script can export variable, which template can use in IF statement and include proper file(s).
1.9. Debug
----------
Debug commands are useful sometimes :)
Sends directly text to browser:
{:echo text}
Dump all tables/functions/variables/macros avilable in the moment:
{:dump}
{:dump params}
If params is not given (empty), it shows list of all known thigns. Params is a list of following
words:
xxx - dump object 'xxx' - including its FULL BODY (e.g. show table contents)
$tables - show tables
$vars - show variables
$macros - show macros
$fns - show functions
$parse_stack - show call stack
Close current request (directly exits all scripts !)
{:exit}
1.10. Text formatting
---------------------
noblanks - skips all next physical blanks in TPL source
url - format 'parameter' as valid URL - parameter should start with : for 'command' invoke.
1.11. Nested execution
----------------------
Sometimes it is necessary to use various substitutes (variables, other commands, ...) There are '2' form of nested
template execution. First, 'contents' of nested exution is processed by TPL engine and then processed again to render
output. Of the contetns are used as parameters, they are not processed again, but passed to function instead.
1.11.1. Direct nested execution
-------------------------------
General form:
{>body with another TPL commands
producing new
commands which may
pvberlap on more lines<}
{>single nestec execution example<}
Everything inside 'body' is processed line NORMAL tpl and its output is again processed as part of TPL output.
If you want to render '{' to output, user '{{' or '}}'
Example:
Assume table:
Name Color
=======================
Red FF0000
Green 00FF00
Blue 0000FF
and variables:
styleRed -> RED
styleGreen -> GREEN
styleBlue -> BLUE
And following TPL:
{>>
{:tloop table}
{{style{:tval Name}}} - have color {:tval Color}
{:tloop}
<<}
This will 'generate'
{styleRed} - have color FF000
{styleGreen} - have color 00FF0
{styleBlue} - have color 000FF
Which will be processed to final output:
RED - have color FF000
GREEN - have color 00FF0
BLUE - have color 000FF
1.11.2. Command parameter inner execution
-----------------------------------------
For simpler execution of internal commands and external functions can be used shorter form. Its general form is
{:command >params<}
or
{*function >params<}
There is no other difference beween direct form, except outptu is used as 'parameter' for given command. New lines
in the body are converted to SPACES.
> have to follow immediatelly after command/function name.
Example:
Assumme variable 'color' having value 'green' or 'red' and variable named nameRed (RED) and nameGreen (GREEN).
{:learn >result {:ife color=red}RED{:else}NOT RED !!!{:endif}<}
Will produce output
{:learn result RED}
or
{:learn result NOT RED !!!}
So, in the result it will learn 'result' variable with 'RED' or 'NOT RED !!!' string.
1.2. XML support
----------------
xml.create name xml_body
vytvore XML strom pojmenovany 'name' z 'xml_body', xml_body MUSI byt validni, jinak se generje warning
xml.free
uvolni XML strom a pamet je k dispozici pro dalsi uziti
Pokud prikaz vyzaduje parametr xml, pak je minen prave XML strom.
Pokid prikaz vyzaduje parametr element, pak je mieno jmeno elementu
Pozor - XML je _CaSe_ sensitive.
1.2.1 kontextove zavisle prikazy
--------------------------------
Nasledujici prikazy jsou kontextove zavisle a funguje jen pri prochazeni stromu, transforamci a podobne.
Pokud budou pouzity mimo tento kontext, generuji warning. Po pocitani/testovani elementu, se pocita od
0 a ignoruje se aktualni element (nezapocitava se). Funguje vzdy pro 'posledni' (nejvnitrnejsi) akci
u XML.
xml.elemNest element typ
pocita pocet vyskytu elementu. Typ je nepovinny paramtr. Pokud schazi, pak je pouzito 'parents'.
Vyznam parametru typ:
parents - pocita vyskyt tagu i vsech parentu az do rootu
prevsiblings - vyskyt elementu ve vsech elementech pred aktualnim, vcetne jeho nadrazenych
prevs - vyskyt elementu pred aktualnim (pouze v aktualnim levelu)
xml.elemExists element typ
vraci 0 ci 1 v zavislosti na tom, zda se dany element vyskutuje v zadanem miste. Typ je nepovinny,
pokud neni zadan, je brano 'childs'. Vyznam parametru typ:
childs - vsechny child elementy
parent - parent elementu
parents - jakykoliv z rodicovskych (vsech) elementu
prevsiblings - vsechny predchozi elementy vcetne nadrazenych
nexts - vsechny nasledujici elementy v aktualni urovni
prevs - vsechny predchozi elementy v aktualni urovni
level - vsechny elementy (vyjma aktualniho) v aktualni urovni
xml.elemChildType
vraci 'typ' child elementu:
none - zadny child
combined - text+elementy
text - pouze textove elementy
element - elementy
Prikaz testuje vsechny child elementy daneho elementu
xml.elemValue
vraci 'value' elementu. Value elementu je dostupna pouze pro elementy typu text. Priklad:
Toto je value elementu
xml.elemExecute
zpracuje child elementy. Prikaz ma vyznam jen pokud se child elementy nezpracovavaji automaticky
(napr. pri transforamcnim pravidle s kombinaci flagu own_childs). Pokud se prikaz vola ikdyz
jsou childy zpracovavany 2x, budou na vystup predany take 2x.
xml.attrValue xml attr_name
vrati hodnotu atributu z elementu
xml.attrExists atr_name
vrati 0 ci 1 v zavislosti na tom, ma-li dany element atribut 'attr_name'
1.2.2 XML transformace
----------------------
Tranforamce funguje tak, ze je postupne prochazen cely XML strom. Pro kazdy tag se hleda transforamcni
pavidlo, ktera se sdruzuji to skupin (tj. transformace). Pravidla jsou prohledava PRESNE v tom poradi,
v jakem jsou registrovana, pokud se nezavola nejaky prikaz na jejich preskupeni. Kazde pravidlo na
condition, ktere dale urcuje zda je pravidlo v dany okamzik platne ci nikoliv. Jeho vyhodnocovani se provadi
u kazdeho tagu. Pokud je pravidlo shledano validnim, tak se provede 'body' pravidla. Po te se provedou
veskere transformace child elementu, Pokud si pravidlo natsavilo flag 'own_childs' tak se automaticky
neprovadi child elementy a je na pravidle, jak s nimi naloze. Pro provede body a pripadne child elementu
se vola bodyclose. Textove elementy (napr. toto je textovy element) se
pouze primo prodavaji na vystup. Pokud se pro dany element nenajde zadne pravidlo, element se z vystupu
bezezbytku a vcetne svych childu odstrani.
xml.transformCreate xlt
vytvori transformaci pojmenovanou 'xlt'
xml.transformRuleAdd xlt element flags condition body bodyclose
prida pravidlo do 'xlt' transformace
element - jmeno elementu (JEDNOHO)
flags - flagy pravidla, carkou odeleny seznam
own_childs - pravidlo samo zpracovava sve childy
condition - expression pro vyhodnoceni - pravidlo je platne pouze pokud je expression nenulovy
body - TLP kod namisto open tagu
bodyclose - TPL kod namisto closing tagu
xml.transform xml xlt
provede tranforamce nad stromem xml a pravidly xlt, vysledej je vystup prikazu
3.0. NEW TEMPLATE ENGINE
------------------------
Blech. Takze jedeeeem. Budu popisovat jen rozdily, protoze jinak vse suztalo stejne. Nejdrive prikazy.
Skriptne se deli do skupin, odeluji se teckama. Pokud neni zadna skupina, tak je to 'globlani' prikaz.
Obycejne knihovny delaji prikazy s prefixem sveho jmeno. Napr. knihovna 'menu' bude mit prikazy menu.abc
a pod. Neorzilsuje se nijak vestavenej a externi prikaz.
novy prikaz parametry stara TPL coment
--------------------------------------------------------------------------------------
var n :var vypise hodnotu variable
learn n?S :learn nauci novou variable
if `S :if proste if
else :else
endif :endif
return :return ukonci 'aktualni' soubor
exit :exit ukonci vsechny fajly
include S :include includne jinej fajl
eval S vypocita 'expression'
lib n?n :lib vlozi 'knihovnu' (pripavy k pouziti)
text.urlencode S :url de/encode URL
text.urldecode S -
output.replace sS :macrorep replace v jiz vygenerovanem textu
lng.load S :lng nahraje LNG fajl
tree.nodes nn?ii :ttreenodes vrati nody ze stromu
tree.path nni?i :ttreepath vrati cestu k node
tree.prepare n :tsorttree pripravi tabulku aby odpovidala 'stromu' (seradi zaznamy a pod)
tree.renderrow ssisssss :ttree vyrendruhe 'radku' stromu pri vykreslvoani
table.loop ?ns :tloop
table.val n :tval
table.len n :tlen
table.pos nn :tpos
table.row n :trow
table.nrow ni :tnrow
table.create n?ii :tcreate vytvori tabulku
table.clean n :tclean smaze tabulku
table.check nnS :tcheck otestuje zda-li existuje zaznam
table.set nnsS :tset setne cell
table.cell nnsn?S :tcell vrati cell
table.cellrow nin?S :tcellrow vrati cell podle radky
table.rowexp nnS :trowexp zpracuje 'radkovy' vyraz
table.colexp nS :tcolexp zpracuje 'sloupcovy' vyraz
table.rowdel nnS :trowdel smaze radku
table.insert nS :tinsert
table.insertm n :tisnertm
table.insertsubm nnns :tinsertm insert do 'tabulky' - subtabulka
table.list nn?s :tlist prevede tabulku do listu
table.glue nnn?n :tglue spoji tabulky
table.sift nnS do DST tabulky narve vsechny radky ze SRC vyhovujici danemu expressionu
table.copy nn :tcopy
table.sort ns?ss :tsort
macro.learn n?S :macro
macro.learnm n?s :mmacro
macro.learnstart n :xmacrob
macro.learnend n :xmacroe
macro.learnsub ns?s :xmacros
macro.inc n :macroinc
macro.add nS :macroadd
macro.addpar nS :macroaddpar
macro.ref n?ssssssssss
string.escape S da \ pred ridici znaky ala \"' a pod. funguje i na HTML entitied retezec - tedy '; a pod.
CBS prikazy
cbs.redir S *redir
cbs.link S *link
cbs.linke S *linke
cbs.linka ?S *linka
cbs.linkae S *linkae
cbs.access S *access
cbs.dataPrepareTypes n *preparedataypes
Dopisu jindy
cbs.data_writter
www.
Existuji i zkratky prikazu:
{!xx} je adekvatni {:macro.ref xx}
Jinak vse zustalo zachovano.
Generalni rozdily:
comandy ala {:table.insert} RVOU kdyz rtabulka neexistuje. Stare ji tise vytvorili.
poradne chybove halseni (kde, co a cesta)
jine parametry (viz nize)
if je opravdovej VYRAZ (viz nize)
jine komentare
jina zprava 'blank spaces'
jine preskakovani 'tagu co nejsou tagy' - staci za nim mit mezeru ci preradit \ -> \}
tagy PUZIVATELKY DEFINOVATELNE - defaultne { }
Parametry
---------
Komandy beoru parametry DLE typy. Poradi a typy je vise uvedeno. ? znamena, ze vsechny DALSI prikazy jsou
'volitelne'.
n name - alias
s string
S string az do KONCE TAGU - musi sedet pary { a } - pokud je tam nejaky tag, automaticky se provede
substituce TPL prikazu
i integer
Parametry MUZOU a NEMUSI byt uzavirany do " ci '. Pokud je parametr uzavren do " pak se vnitrek tohoto retzece
PROVEDE. Pokud do ' tak se NEPROVEDE a preda se tak jak je. string MUSI byt uzavren do " ci ' pokud obsahuje
jine nez dovolene znaky. Tech je celkem dost - :.+ a podobne. Nicmene, nejsou tam znaky jako mezera, tagy jako
takove, " a tak dale.
Uvnitr " ma specialni vyznam znak \ - pokud za ti mnasleduje ' " jsou prevedeny na odpovidajici znak, znaky r n
jsou pak konce radku. t je tabulator.
Pokud PRVNI znak parametru neni " ci ' tak se priapdne dalsi tyto znaku (pokud to dany typ dovoluje) berou tak jak
jsou bez dalsich zmen.
Parametry se odeluji jednou a vice mezeramy. Tolik seda teorie a ted praxe.
Prikaz table.val bere 'n' - tedy alias. Muzeme zapsat:
{:table.val sloupec}
{:table.val "sloupec"}
{:table.val 'table.val'}
{:table.val table.val }
{:table.val "{variable}"} - je adekvatni zapisu {:table.val hodnota_variable}
NEMUZEME zapsat:
{:table.val '{variable}'} -> {variable} NENI alias
zapis "{variable}" zaroven selze, pokud hodnota variable NENI 'alias'
vnorene prikazy
"{:command \"{:command2 par2}\"}"
"{:command \"{:command2 \\\"{:command3 par2}\\\"\"}"
output.replace ma 2 parametry: sS retezec a retezec do konce tagu.
muzeme zapsat
{:output.replace }
{:output.replace '' ''} (stejne jako prechozi)
{:output.replace '' {!macro}} nahradi tim co je v makru 'macro'
{:output.replace "" '{!macro}'} nahradi za {!macro}
{:output.replace 'neco s " uvnitr' za neco jineho s " ci '} zdroj: je neco s " uvnitr
cil: za neco jineho s " ci '
nemuzeme zapsat
{:output.replace source s mezerou } 'source' se nahradi za 's mezerou ' - nutno pouzit " ci '
{:output.replace source text s {nejakym tagem} -> nesedi pary tagu - kazdy { ma } v S parametru -> musi se prepsat
'text s {nejakym tagem'
(ikdyby to TPL vzalo, tak by to selkalo protoze '{nejakym' neni
platny TPL prikaz}
{:output.replace "neco kde je {xx{" za neco jineho TPL selze {xx{ neni platny TPL prikaz - nutne pouzit ' ne " !
Pozor na S - specilani u prikazu, ktere maji jen jedno S 'svadi' k chybam !!!
{:if "aa"="bb"} -> SPATNE !!!
PRVNI znak parametru je " -> parametr bude: aa"="bb -> zpracovani expression hodi chybu
Tato situace nastava pouze u expressionu a lze rezit jednouse pouzitim zpetncyh apostrofu ` - tu jsou adekvatni
normlanimu ', ale fungujou jen v rexpression a na parametry nemaji vliv. Pokud se ` objevy v expressionu
v ' tak se 'ignoguje' (jako kdyby tam nebyl)
Je mozne napsat
{:if {:tval abc}='abc'}
{:if {:tval abc}=abc}
{:if {:tval abc}={xxx}}
a tak dale. Je nutne si uvedomit, ze jedna vec je 'precteni parametru' a druhe je zpracovani expressionu, ten ma
take sve pravidla (viz nize)
Komentare
----------
{- komentaro do konce radku
{-- multiline komentar
klidne na jeden a vice
radku --}
Komentare muzou byt vnorene, pocet - na zacatku musi odpovidat poctu - na konci
VSE OK:
{--- debug
{:prikazy}
{--{:prikaz}--}
---}
SPATNE:
{-- debug
{:prikazy}
{--{:prikaz}--}
--}
zde komentar konci jiz po prvnim --} - sice zadna chyba nenastane, ale ....
Expression
----------
Podporovane operatory (ciselne)
+ - / * ( ) < > <= >= = klasicke operatory - co dodat ?
+ - negace/kladne cislo: 1--2 1+-2 1++2
&& || AND/OR - logycky. 1 && 4 -> 1
1 || 3 -> 1
0 || 2 -> 2
& | AND/OR - bitove 1 & 4 -> 0
1 | 3 -> 3
0 | 2 -> 2
~ bitova negace ~1 -> 0xffffffff (decimane nevim :)
<< >> bitovy posun 1 << 3 -> 8 (00001 -> 01000)
! logicke ne !1 -> 0
!23 -> 0
!0 -> 1
% zbytek po deleni 5 % 2 -> 1
Funknce (lze dodat dle potreb)
mod mod(5,2) zbytek po deleni
bits bits(a,b) pocita biti mezi a,b (offsety na bity)
Podporovane operator - retezcove
< > <= >= = klasicke operatory - co dodat ?
+ soucet retezcu
Funknce vzdy musi byt ve formatu 'jmeno(parametry)'
Pokud operator potrebuje VICE operandu, VZDY musi vsehny byt pritomne
NENI mozny zapis '!=3' -> chyba
Nektere operatory vyzaduji jeden operand (! ~ + - a pod.)
Operandy mohou byt CISLA a RETEZCE.
Vysledek vyrazu je CISLO nebo RETEZEC.
Pokud je vyraz pouzit v IFu tak IF je 'platny' pokud se vrati NENULOVE cislo nebo NEPRAZDNY retezec.
{:if 1!=2} znamena tedy:
operator != pro 1 2 (ciselny), vysledek bude 1 -> if se provede
Mixovani typu. Parser zpracovava operatory zleva. Dokud je to mozne, tak NEMENI typ. Pokud JEDEN z operatoru bude
retezec, pak se druhy operator automaticky na retezec prevede. Vysledek pak bdue retezec.
Priorita je smoazrejmosti. Priority operatoru (ov nejvetsi po nejmensi)
Priklady:
abc+xyz+56+1 abcxyz561
1+100+abc 101abc
1+2*3 7
1+2*3*(4*5+mod(10,4)) 133
HAHA HAHA
123 123
!(1=2) 1
`1`!=-2--3 0 -> 1!=-2--3 -> 1!=1
!(`xyz`!="xyz") 1
{test}='this is test' 1 (pokud je variable 'test' nastavena na retezec, ...)
Retezce
Retezec NEMUSI byt v " ci ' ci ` pokud osbahuje 'povolene' znaky - to jest: pisminka, cisla, . : ? @
mezi " a ' neni defacto zadny rozdil. Pozor na \ u " ktere se chova stejne jako u parametru.
- PROBLEMY s vyrazem
Na prvni pohled bezvadny vyraz:
{:if {var}!=''}
selze pokud bude 'var' PRAZNDY retezec. Pripadne kdyz bude obsahovat napr. 'aa='.... Proc ?
'TPL' parser jako parametr vezme:
{var}!=''
Protoze je to S parametr prozene to TPL enginem. Vznikne
!=''
priapdne
aa=!=''
Tento vysledke se prada prikazu IF, ktery zavola expression. A je tu chyba.
Toto se resi pomoci ` operatoru. Jak funguje ?
` je v epxressionu to same jako '. Rozdil je jediny - pokud se mezi ` ` objevy CISLO, bere se jako CISLO - ne jako
retezec !!!
'1'+1 11
`1`+1 2
'a'+1 a1
`a`+1 a1
To je jediny rozdil.
Pokud se zpracovava prikaz IF (nikdy jindy !!!) tak prikazy:
table.val
var (a tedy i {xxx})
(a dalsi)
provedou 'enclosing' do `. To znamena, ze pokud bude obsahovat jine znaky nez CISLA, tak se ozavre do `
Prikaz:
{:if {var}!=''} z prechozi casti se zmeni na
``!=''
`aa=`!=''
A vse bude v poradku.
Toto implicitni chovani jde zrusit pomoci * - koamdn flagu (stejne jako ?)
Pak lze udelat:
{:learn oper =}
{:if {test} {*oper} 'this is test'}...
Bez te * by se 'oper' (v nasem pripade =) prevedlo na `=` a byl by problem.
=======================================================================================================================
That's all folks :o)
Ray