De calibre sjabloontaal¶
De calibre sjabloontaal is een calibre-eigen taal gebruikt doorheen calibre voor taken zoals specificeren van bestandspaden, opmaken van waarden en berekenen van de waarde voor gebruiker-gespecificeerde kolommen. Voorbeelden:
Specificeer de mappenstructuur en bestandsnamen bij opslaan van bestanden van de calibre bibliotheek naar de schijf of e-boekreader.
Definieer regels voor toevoegen van iconen en kleuren aan calibre’s boekenlijst.
Definieer virtuele kolommen die data bevatten van andere kolommen.
Geavanceerd bibliotheek zoeken.
Geavanceerd metadata zoeken en vervangen.
De taal is gebouwd rond het concept van een sjabloon die specificeert welke metadata te gebruiken, berekeningen op die metadata en hoe het opgemaakt moet worden.
Basis sjablonen¶
Een basissjabloon bestaat uit één of meer template expressions
. Een template expression
bestaat uit tekst en namen tussen accolades ({}
) die wordt vervangen door de overeenkomende metadata van het boek in verwerking. Bv. de standaard sjabloon in calibre gebruikt voor boeken naar toestel opslaan heeft vier template expressions
:
{author_sort}/{title}/{title} - {authors}
Voor het boek “The Foundation” door “Isaac Asimov” wordt dit:
Asimov, Isaac/The Foundation/The Foundation - Isaac Asimov
De schuine strepen zijn geen template expressions
omdat ze tussen {}
staan. Zulke tekst blijft waar ie is. Bv., als de sjabloon is:
{author_sort} Some Important Text {title}/{title} - {authors}
dan voor “The Foundation” produceert de sjabloon:
Asimov, Isaac Some Important Text The Foundation/The Foundation - Isaac Asimov
Een template expression
heeft toegang tot alle metadata in calibre, inbegrepen aangepaste kolommen (kolommen die u zelf creëerde), door de kolom z’n lookup name
te gebruiken. Om een kolom z’n lookup name te vinden (soms velden genaamd), zweef met uw muis over de kolom header in calibre’s boekenlijst. Lookup names voor aangepaste kolommen beginnen altijd met #
. Voor reeks type kolommen is er een bijkomend veld genaamd #lookup name_index
wat de serie index is voor dat boek in de serie. Bv., als u een aangepaste serie hebt genaamd #myseries
dan zal er ook een kolom zijn genaamd #myseries_index
. De standaard serie kolom index heet series_index
.
Naast de kolom gebaseerde velden, kunt u gebruik maken van:
{formats}
- Een lijst van formaten beschikbaar in de calibre bibliotheek voor een boek
{identifiers:select(isbn)}
- De ISBN van het boek
Als de metadata voor het veld voor een bepaald boek niet gedefinieerd is wordt het veld in de sjabloon vervangen door de lege string (''
). Bv. overweeg volgende sjabloon:
{author_sort}/{series}/{title} {series_index}
Als Asimov’s boek “Second Foundation” in de serie “Foundation” is dan geeft de sjabloon:
Asimov, Isaac/Foundation/Second Foundation 3
Als er voor een boek geen serie is ingevoerd geeft de sjabloon:
Asimov, Isaac/Second Foundation
De sjabloonverwerker verwijdert automatisch meerdere schuine strepen en voorloop en volg spaties.
Geavanceerde opmaak¶
Bovenop metadatasubstitutie kunnen sjablonen voorwaardelijk extra tekst opnemen en de opmaak van gesubstitueerde gegevens controleren.
Voorwaardelijk tekst opnemen
Soms wilt u dat tekst enkel in de uitvoer verschijnt als een veld niet leeg is. Een veel voorkomend geval is series
en series_index
waar u ofwel niets wil of de twee waarden gescheiden door een streepje. calibre doet dit via een speciale template expression
syntaxis.
Bv. met het Foundation voorbeeld van boven, veronderstel dat u wilt dat de sjabloon Foundation - 3 - Second Foundation geeft. Deze sjabloon geeft die uitvoer:
{series} - {series_index} - {title}
Alhoewel, als een boek geen deel van een serie is, geeft de sjabloon - - de titel, wat waarschijnlijk niet is wat u wilt. Gewoonlijk willen de mensen als resultaat de titel zonder extra streepjes. Dit kan met de volgende sjabloon syntaxis:
{field:|prefix_text|suffix_text}
Deze template expression
zegt dat als field
de waarde XXXX heeft, het resultaat prefix_textXXXXXsuffix_text zal zijn. Als field
leeg is (heeft geen waarde) dan zal het resultaat de lege string zijn (niets) omdat voor- en achtervoegsel genegeerd worden. Het voor- en achtervoegsel kunnen lege plekken hebben.
Gebruik geen subsjablonen (`{ … }`) of functies (zie onder) in het voor- of achtervoegsel.
Met deze syntaxis kunnen we het geen-serie probleem boven oplossen met de sjabloon:
{series}{series_index:| - | - }{title}
De streepjes komen er enkel bij als het boek een serie index heeft, die het enkel heeft als het deel van een serie is. Verder weer met het Foundation voorbeeld, de sjabloon geeft Foundation - 1 - Second Foundation.
Aantekeningen:
U moet een dubbel punt zetten na de
lookup name
als u een voor- of achtervoegsel gebruikt.U moet ofwel beide ofwel geen
|
karakters gebruiken. Eén gebruiken, zoals in{field:| - }
, is niet toegelaten.Het is oké om geen tekst te voorzien voor voor- of achtervoegsel, zoals in
{series:|| - }
. De sjabloon{title:||}
is hetzelfde als{title}
.
Opmaak
Veronderstel dat u series_index
opgemaakt wilt als drie cijfers met voorloopnullen. Dit doet de truc:
{series_index:0>3s}
- Drie cijfers met voorloopnullen
Voor volgnullen, gebruik:
{series_index:0<3s}
- Drie cijfers met volgnullen
Als u reeksindexen gebruikt met fractionele waarden, bv. 1,1, hebt u de komma’s misschien graag uitgelijnd. Bv. u hebt misschien graag dat indexen 1 en 2,5 eruit zien als 01,00 en 02,50 zodat ze correct sorteren op een toestel dat lexicaal sorteert. Om dit te doen, gebruik:
{series_index:0>5.2f}
- Vijf karakters bestaande uit twee cijfers met voorloopnullen, een komma en twee cijfers na de komma.
Als u enkel de twee eerste letters van de data wil, gebruik:
{author_sort:.2}
- Enkel de eerste twee letters van de auteursorteernaam
Veel van de calibre sjabloontaalvormgeving komt van Python. Voor meer details over de syntaxis van deze geavanceerde vormgevingsoperaties zie de Python documentatie.
Sjablonen gebruiken om aangepaste kolommen te definiëren¶
Sjablonen kunnen gebruikt worden om informatie weer te geven niet in calibre’s metadata of metadata afwijkend van calibre’s gewone formaat. Bv. u wilt misschien het ISBN
tonen, een veld dat calibre niet weergeeft. Dit kan door een aangepaste kolom te creëren van het type Kolom gemaakt van andere kolommen (hierna samengestelde kolommen) en een sjabloon te voorzien om de weer te geven tekst te genereren. De kolom geeft het resultaat weer van het evalueren van de sjabloon. Bv. om het ISBN weer te geven, creëer de kolom en voer {identifiers:select(isbn)}
in in het sjabloon vak. Om een kolom weer te geven met de waardes van twee series aangepaste kolommen, gescheiden door een komma, gebruik {#series1:||,}{#series2}
.
Samengestelde kolommen kunnen elke sjabloonoptie gebruiken, inclusief opmaak.
Nota: U kan data getoond in een samengestelde kolom niet bewerken. U moet de bronkolommen bewerken. Als u een samengestelde kolom bewerkt, bv. door erop dubbel te klikken, zal calibre de bewerksjabloon openen, niet de onderliggende data.
Templates and plugboards¶
Plugboards are used for changing the metadata written into books during send-to-device and save-to-disk operations. A plugboard permits you to specify a template to provide the data to write into the book’s metadata. You can use plugboards to modify the following fields: authors, author_sort, language, publisher, tags, title, title_sort. This feature helps people who want to use different metadata in books on devices to solve sorting or display issues.
When you create a plugboard, you specify the format and device for which the plugboard is to be used. A special device is provided, save_to_disk
, that is used when saving formats (as opposed to sending them to a device). Once you have chosen the format and device, you choose the metadata fields to change, providing templates to supply the new values. These templates are connected to their destination fields, hence the name plugboards. You can of course use composite columns in these templates.
Plugboards are quite flexible and can be written in Single Function Mode, Template Program Mode, General Program Mode, or Python Template mode.
When a plugboard might apply (Content server, save to disk, or send to device), calibre searches the defined plugboards to choose the correct one for the given format and device. For example, to find the appropriate plugboard for an EPUB book being sent to an ANDROID device, calibre searches the plugboards using the following search order:
een adapter met een exacte overeenkomst op formaat en toestel, bv.
EPUB
enANDROID
a plugboard with an exact match on format and the special
any device
choice, e.g.,EPUB
andany device
een adapter met de speciale
any format
keuze en een exacte overeenkomst op toestel, bv.any format
enANDROID
a plugboard with
any format
andany device
De labels en auteurs velden hebben een speciale behandeling omdat beide velden meer dan één item kunnen vasthouden. Een boek kan vele labels en meerdere auteurs hebben. Als u opgeeft dat één van deze twee velden gewijzigd gaat worden, wordt de template resultaat onderzocht om te zien of meer dan één item is. Voor labels wordt het resultaat gescheiden waar Calibre een komma vindt. Bijvoorbeeld, als de template de waarde `` Thriller, Horror`` produceert, dan zal het resultaat twee labels zijn, Thriller
en Horror
. Er is geen manier om een komma in het midden van een tag te zetten.
The same thing happens for authors, but using a different character for the cut, a & (ampersand) instead of a comma. For example, if the template produces the value Blogs, Joe&Posts, Susan
, then the book will end up with two authors, Blogs, Joe
and Posts, Susan
. If the template produces the value Blogs, Joe;Posts, Susan
, then the book will have one author with a rather strange name.
Plugboards affect the metadata written into the book when it is saved to disk or written to the device. Plugboards do not affect the metadata used by save to disk
and send to device
to create the file names. Instead, file names are constructed using the templates entered on the appropriate preferences window.
Functies gebruiken in sjablonen - Eén Functie Modus¶
Veronderstel dat u de waarde van een veld in hoofdletters wil tonen wanneer dat veld normaal elk woord met beginhoofdletter toont. Dit kan met sjabloonfuncties. Bv., om de titel in hoofdletters te tonen, gebruik de uppercase
functie, zoals in {title:uppercase()}
. Om met beginhoofdletters te tonen, gebruik {title:titlecase()}
.
Functies gaan in het formaat deel van de sjabloon, na de :
en voor de eerste |
of de sluit }
als geen voor- of achtervoegsel is gebruikt. Als u zowel een formaat als een functie referentie hebt, komt de functie na een tweede :
. Functies geven de waarde terug van de kolom gespecificeerd in de sjabloon, gepast gewijzigd.
De syntaxis voor gebruik van functies is een van:
{lookup_name:function(arguments)}
{lookup_name:format:function(arguments)}
{lookup_name:function(arguments)|prefix|suffix}
{lookup_name:format:function(arguments)|prefix|suffix}
Functienamen moeten altijd gevolgd worden door open/sluithaakjes. Sommige functies hebben extra waarden (argumenten) nodig en deze staan tussen de haakjes. Argumenten worden gescheiden door komma’s. Letterlijke komma’s (als tekst, niet als argumenten scheiders) moeten vooraf gegaan worden door een achteroverhellend streepje (\
). Het laatste (of enige) argument kan geen tekstueel sluithaakje bevatten.
Functies worden geëvalueerd voor formaat specificaties en het voor-/achtervoegsel. Kijk verder beneden voor een voorbeeld van gebruik van zowel een formaat als een functie.
Belangrijk: Als u programmeerervaring hebt, hou er a.u.b. rekening mee dat de syntaxis in Eén Functie Modus niet is wat u verwacht. Strings hebben geen aanhalingstekens en spaties zijn belangrijk. Alle argumenten worden gezien als contanten; er zijn geen expressies.
Gebruik geen subsjablonen (`{ … }`) als functie argumenten. In plaats daarvan, gebruik Sjabloon Programma Modus en Algemene Programma Modus.
Notes on calling functions in Single Function Mode:
When functions are used in Single Function Mode, the first parameter,
value
, is automatically replaced by the content of the field specified in the template. For example, when the template{title:capitalize()}
is processed, the content of thetitle
field is passed as the parametervalue
to the capitalize function.In the function documentation, the notation
[something]*
means thatsomething
can be repeated zero or more times. The notation[something]+
means that thesomething
is repeated one or more times (must exist at least one time).Some functions use regular expressions. In the template language regular expression matching is case-insensitive.
Functions are documented in Template function reference. The documentation tells you what arguments the functions require and what the functions do. For example, here is the documentation of the ifempty function.
ifempty(value, text_if_empty)
– if thevalue
is not empty then return thatvalue
, otherwise returntext_if_empty
.
You see that the function requires two arguments, value
and text_if_empty
. However, because we are using Single Function Mode, we omit the value
argument, passing only text_if_empty
. For example, this template:
{tags:ifempty(No tags on this book)}
shows the tags for a book, if any. If it has no tags then it show No tags on this book.
The following functions are usable in Single Function Mode because their first parameter is value
.
capitalize
(value)
– returns thevalue
with the first letter in upper case and the rest lower case.ceiling
(value)
– returns the smallest integer greater than or equal tovalue
.cmp
(value, y, lt, eq, gt)
– comparesvalue
andy
after converting both to numbers.contains
(value, pattern, text_if_match, text_if_not_match)
– checks if the value is matched by the regular expressionpattern
date_arithmetic
(value, calc_spec, fmt)
– Calculate a new date fromvalue
usingcalc_spec
.floor
(value)
– returns the largest integer less than or equal tovalue
.format_date
(value, format_string)
– format thevalue
, which must be a date string, using theformat_string
, returning a string.format_number
(value, template)
– interprets thevalue
as a number and formats that number using a Python formatting template such as{0:5.2f}
or{0:,d}
or${0:5,.2f}
.fractional_part
(value)
– returns the part of the value after the decimal point.human_readable
(value)
– expects thevalue
to be a number and returns a string representing that number in KB, MB, GB, etc.ifempty
(value, text_if_empty)
– if thevalue
is not empty then return thatvalue
, otherwise returntext_if_empty
.language_strings
(value, localize)
– return the language names for the language codes (see here for names and codes) passed invalue
.list_contains
(value, separator, [ pattern, found_val, ]* not_found_val)
– interpret thevalue
as a list of items separated byseparator
, checking thepattern
against each item in the list.list_count
(value, separator)
– interprets the value as a list of items separated byseparator
and returns the number of items in the list.list_count_matching
(value, pattern, separator)
– interpretsvalue
as a list of items separated byseparator
, returning the number of items in the list that match the regular expressionpattern
.list_item
(value, index, separator)
– interpret thevalue
as a list of items separated byseparator
, returning the ‘index’th item.list_sort
(value, direction, separator)
– returnvalue
sorted using a case-insensitive lexical sort.lookup
(value, [ pattern, key, ]* else_key)
– The patterns will be checked against thevalue
in orderlowercase
(value)
– returns thevalue
in lower case.mod
(value, y)
– returns thefloor
of the remainder ofvalue / y
.rating_to_stars
(value, use_half_stars)
– Returns thevalue
as string of star (★
) characters.re
(value, pattern, replacement)
– return thevalue
after applying the regular expression.re_group
(value, pattern [, template_for_group]*)
– return a string made by applying the regular expressionpattern
tovalue
and replacing each matched instanceround
(value)
– returns the nearest integer tovalue
.select
(value, key)
– interpret thevalue
as a comma-separated list of items with each item having the formid:id_value
(the calibreidentifier
format).shorten
(value, left_chars, middle_text, right_chars)
– Return a shortened version of thevalue
str_in_list
(value, separator, [ string, found_val, ]+ not_found_val)
– interpret thevalue
as a list of items separated byseparator
then comparestring
against each value in the list.subitems
(value, start_index, end_index)
– This function breaks apart lists of tag-like hierarchical items such as genres.sublist
(value, start_index, end_index, separator)
– interpret thevalue
as a list of items separated byseparator
, returning a new list made from the items fromstart_index
toend_index
.substr
(value, start, end)
– returns thestart
’th through theend
’th characters ofvalue
swap_around_articles
(value, separator)
– returns thevalue
with articles moved to the end.swap_around_comma
(value)
– given avalue
of the formB, A
, returnA B
.switch
(value, [patternN, valueN,]+ else_value)
– for eachpatternN, valueN
pair, checks if thevalue
matches the regular expressionpatternN
test
(value, text_if_not_empty, text_if_empty)
– returntext_if_not_empty
if the value is not empty, otherwise returntext_if_empty
.titlecase
(value)
– returns thevalue
in title case.transliterate
(value)
– Return a string in a latin alphabet formed by approximating the sound of the words invalue
.uppercase
(value)
– returns thevalue
in upper case.
Functies en opmaak gebruiken in dezelfde sjabloon
Veronderstel, u hebt een aangepaste kolom met gehele getallen #myint
die u wilt weergeven met voorloopnullen, zoals in 003
. Een manier om dit te doen is met het formaat 003
. Hoewel, standaard, als een getal (geheel of decimaal) gelijk is aan nul wordt de waarde getoond als de lege string dus nul waardes geven de lege string, niet 000
. Als u 000
waardes wilt zien, gebruikt u zowel de formaat string als de ifempty
functie om de lege waarde terug op nul te zetten. De sjabloon wordt:
{#myint:0>3s:ifempty(0)}
Merk op dat u zowel het voor- als het achtervoegsel kan gebruiken. Als u wil dat het getal verschijnt als [003]
of [000]
, gebruik dan de sjabloon:
{#myint:0>3s:ifempty(0)|[|]}
Algemene Programma Modus¶
Algemene Programma Modus (APM) vervangt sjabloonexpressies door een programma geschreven in de sjabloontaal. De syntaxis van de taal is gedefinieerd door de volgende grammatica:
program ::= 'program:' expression_list
expression_list ::= top_expression [ ';' top_expression ]*
top_expression ::= or_expression
or_expression ::= and_expression [ '||' and_expression ]*
and_expression ::= not_expression [ '&&' not_expression ]*
not_expression ::= [ '!' not_expression ]* | concatenate_expr
concatenate_expr::= compare_expr [ '&' compare_expr ]*
compare_expr ::= add_sub_expr [ compare_op add_sub_expr ]
compare_op ::= '==' | '!=' | '>=' | '>' | '<=' | '<' |
'in' | 'inlist' | 'inlist_field' |
'==#' | '!=#' | '>=#' | '>#' | '<=#' | '<#'
add_sub_expr ::= times_div_expr [ add_sub_op times_div_expr ]*
add_sub_op ::= '+' | '-'
times_div_expr ::= unary_op_expr [ times_div_op unary_op_expr ]*
times_div_op ::= '*' | '/'
unary_op_expr ::= [ add_sub_op unary_op_expr ]* | expression
expression ::= identifier | constant | function | assignment | field_reference |
if_expr | for_expr | break_expr | continue_expr |
'(' expression_list ')' | function_def
field_reference ::= '$' [ '$' ] [ '#' ] identifier
identifier ::= id_start [ id_rest ]*
id_start ::= letter | underscore
id_rest ::= id_start | digit
constant ::= " string " | ' string ' | number
function ::= identifier '(' expression_list [ ',' expression_list ]* ')'
function_def ::= 'def' identifier '(' top_expression [ ',' top_expression ]* ')' ':'
expression_list 'fed'
assignment ::= identifier '=' top_expression
if_expr ::= 'if' condition 'then' expression_list
[ elif_expr ] [ 'else' expression_list ] 'fi'
condition ::= top_expression
elif_expr ::= 'elif' condition 'then' expression_list elif_expr | ''
for_expr ::= for_list | for_range
for_list ::= 'for' identifier 'in' list_expr
[ 'separator' separator_expr ] ':' expression_list 'rof'
for_range ::= 'for' identifier 'in' range_expr ':' expression_list 'rof'
range_expr ::= 'range' '(' [ start_expr ',' ] stop_expr
[ ',' step_expr [ ',' limit_expr ] ] ')'
list_expr ::= top_expression
break_expr ::= 'break'
continue_expr ::= 'continue'
separator_expr ::= top_expression
start_expr ::= top_expression
stop_expr ::= top_expression
step_expr ::= top_expression
limit_expr ::= top_expression
Aantekeningen:
een
top_expression
heeft altijd een waarde. De waarde van eenexpression_list
is de waarde van de laatstetop_expression
in de lijst. Bv. de waarde van de expressielijst1;2;'foobar';3
is3
.In een logische context is elke niet-lege waarde
True
In een logische context is de lege waarde
False
Strings en getallen kunnen door elkaar gebruikt worden. Bv.
10
en'10'
zijn identiek.Commentaar zijn regels die beginnen met ‘#’. Commentaar verder in de regel wordt niet ondersteund.
Operator voorrang
De operator voorrang (volgorde van evalueren) van hoogste (eerst geëvalueerd) naar laagste (laatst geëvalueerd) is:
Functie aanroep, constanten, uitdrukkingen tussen haakjes, instructie-expressies, opdracht-expressies, veldreferenties.
Unary plus (
+
) en min (-
). Deze operatoren evalueren van rechts naar links.Deze en alle andere rekenkundige operatoren geven integers terug als het resultaat van de expressie een fractioneel deel gelijk aan nul is. Bv. als een expressie
3.0
terug geeft, wordt dit veranderd in3
.Vermenigvuldigen (
*
) en delen (/
). Deze operatoren zijn associatief en evalueren van links naar rechts. Gebruik haakjes als u de volgorde van evaluatie wilt veranderen.Optellen (
+
) en aftrekken (-
). Deze operatoren zijn associatief en evalueren van links naar rechts.Numerieke en string vergelijkingen. Deze operatoren geven
'1'
terug als de vergelijking door gaat, anders de lege string (''
). Vergelijkingen zijn niet associatief:a < b < c
is een syntaxis fout.String concatenation (
&
). The&
operator returns a string formed by concatenating the left-hand and right-hand expressions. Example:'aaa' & 'bbb'
returns'aaabbb'
. The operator is associative and evaluates left to right.Unary logisch niet (
!
). Deze operator geeft'1'
terug als de expressie Vals is (evalueert naar de lege string), anders''
.Logisch en (
&&
). Deze operator geeft ‘1’ terug als zowel de linker- als de rechter-kant expressies Waar zijn, of de lege string''
als een van beide Vals is. Het is associatief, evalueert van links naar rechts en doet aan kort-sluiten.Logische of (
||
). Deze operator geeft'1'
terug als ofwel de linker- ofwel de rechterkant expressie Waar is, of''
als beide Vals zijn. Hij is associatief, evalueert van links naar rechts en doet aan kort-sluiten. Het is een inclusieve of, geeft'1'
terug als zowel de linker- en rechterkant expressies Waar zijn.
Veldreferenties
A field_reference
evaluates to the value of the metadata field named by lookup name that follows the $
or $$
. Using $
is equivalent to using the field function. Using $$
is equivalent to using the raw_field function. Examples:
* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')
If expressies
If
expressies evalueren eerst de condition
. Als de condition
Waar is (een niet-lege waarde) wordt de expression_list
in de then
clausule geëvalueerd. Als ze Onwaar is wordt, indien aanwezig, de expression_list
in de elif
of else
clausule geëvalueerd. De elif
en else
delen zijn optioneel. De woorden if
, then
, elif
, else
, en fi
zijn gereserveerd; U kan ze niet gebruiken als identificator namen. U kan nieuwe regels en spaties zetten overal waar het zin heeft. De condition
is een top_expression
geen expression_list
; puntkomma’s zijn niet toegelaten. De expression_lists
zijn puntkomma gescheiden reeksen met top_expressions
. Een if
expressie geeft het resultaat terug van de laatste top_expression
in de geëvalueerde expression_list
, of de lege string als geen expressie lijst werd geëvalueerd.
Voorbeelden:
* program: if field('series') then 'yes' else 'no' fi
* program:
if field('series') then
a = 'yes';
b = 'no'
else
a = 'no';
b = 'yes'
fi;
strcat(a, '-', b)
Genest if
voorbeeld:
program:
if field('series') then
if check_yes_no(field('#mybool'), '', '', '1') then
'yes'
else
'no'
fi
else
'no series'
fi
Zoals boven gezegd, een if
geeft een waarde. Dat betekent dat al de volgenden equivalent zijn:
* program: if field('series') then 'foo' else 'bar' fi
* program: if field('series') then a = 'foo' else a = 'bar' fi; a
* program: a = if field('series') then 'foo' else 'bar' fi; a
For example, this program returns the value of the series
column if the book has a series, otherwise the value of the title
column:
program: field(if field('series') then 'series' else 'title' fi)
For expressies
The for
expression iterates over a list of values, processing them one at a time. The list_expression
must evaluate either to a metadata field lookup name
e.g., tags
or #genre
, or to a list of values. The range generates a list of numbers. If the result is a valid lookup name
then the field’s value is fetched and the separator specified for that field type is used. If the result isn’t a valid lookup name then it is assumed to be a list of values. The list is assumed to be separated by commas unless the optional keyword separator
is supplied, in which case the list values must be separated by the result of evaluating the separator_expr
. A separator cannot be used if the list is generated by range()
. Each value in the list is assigned to the specified variable then the expression_list
is evaluated. You can use break
to jump out of the loop, and continue
to jump to the beginning of the loop for the next iteration.
Voorbeeld: Deze sjabloon verwijdert de eerste hiërarchische naam voor elke waarde in Genre (#genre
), een lijst opbouwend met de nieuwe namen:
program:
new_tags = '';
for i in '#genre':
j = re(i, '^.*?\.(.*)$', '\1');
new_tags = list_union(new_tags, j, ',')
rof;
new_tags
Als het originele Genre History.Military, Science Fiction.Alternate History, ReadMe is dan geeft de sjabloon Military, Alternate History, ReadMe terug. U kan deze sjabloon gebruiken in calibre’s Metadata bewerken in bulk → Zoeken & vervangen met Zoeken naar ingesteld op template
om het eerste niveau van de hiërarchie te verwijderen en de resulterende waarde aan Genre toe te wijzen.
Merk op: de laatste regel in de sjabloon, new_tags
, is niet strikt nodig in dit geval omdat for
de waarde van de laatste top_expression terug geeft in de expressie lijst. De waarde van een opdracht is de waarde van zijn expressie, dus de waarde van het for
bericht is wat was toegewezen aan new_tags
.
Function definition
If you have repeated code in a template then you can put that code into a local function. The def
keyword starts the definition. It is followed by the function name, the argument list, then the code in the function. The function definition ends with the fed
keyword.
Arguments are positional. When a function is called the supplied arguments are matched left to right against the defined parameters, with the value of the argument assigned to the parameter. It is an error to provide more arguments than defined parameters. Parameters can have default values, such as a = 25
. If an argument is not supplied for that parameter then the default value is used, otherwise the parameter is set to the empty string.
The return
statement can be used in a local function.
A function must be defined before it can be used.
Example: This template computes an approximate duration in years, months, and days from a number of days. The function to_plural()
formats the computed values. Note that the example also uses the &
operator:
program:
days = 2112;
years = floor(days/360);
months = floor(mod(days, 360)/30);
days = days - ((years*360) + (months * 30));
def to_plural(v, str):
if v == 0 then return '' fi;
return v & ' ' & (if v == 1 then str else str & 's' fi) & ' '
fed;
to_plural(years, 'year') & to_plural(months, 'month') & to_plural(days,'day')
Relationele operatoren
Relational operators return '1'
if the comparison is true, otherwise the empty string (''
).
Er zijn twee soorten relationele operatoren: string vergelijkingen en numerieke vergelijkingen.
String comparisons do case-insensitive string comparison using lexical order. The supported string comparison operators are ==
, !=
, <
, <=
, >
, >=
, in
, inlist
, and inlist_field
.
For the in
operator, the result of the left hand expression is interpreted as a regular expression pattern. The in
operator is True if the value of left-hand regular expression matches the value of the right hand expression.
The inlist
operator is true if the left hand regular expression matches any one of the items in the right hand list where the items in the list are separated by commas. The inlist_field
operator is true if the left hand regular expression matches any of the items in the field (column) named by the right hand expression, using the separator defined for the field. NB: the inlist_field
operator requires the right hand expression to evaluate to a field name, while the inlist
operator requires the right hand expression to evaluate to a string containing a comma-separated list. Because of this difference, inlist_field
is substantially faster than inlist
because no string conversions or list constructions are done. The regular expressions are case-insensitive.
De numerieke vergelijkingsoperatoren zijn ==#
, !=#
, <#
, <=#
, >#
, >=#
. De links en rechts expressies moeten evalueren naar numerieke waarden met twee uitzonderingen: zowel de string waarde “None” (niet gedefinieerd veld) en de lege string evalueren naar de waarde nul.
Voorbeelden:
program: field('series') == 'foo'
returns'1'
if the book’s series is foo, otherwise''
.
program: 'f.o' in field('series')
geeft'1'
terug als het boek z’n serie overeenkomt met de reguliere expressief.o
(bv., foo, Off Onyx, enz.), anders''
.
program: 'science' inlist $#genre
returns'1'
if any of the values retrieved from the book’s genres match the regular expressionscience
, e.g., Science, History of Science, Science Fiction etc., otherwise''
.
program: '^science$' inlist $#genre
returns'1'
if any of the book’s genres exactly match the regular expression^science$
, e.g., Science, otherwise''
. The genres History of Science and Science Fiction don’t match.
program: 'asimov' inlist $authors
returns'1'
if any author matches the regular expressionasimov
, e.g., Asimov, Isaac or Isaac Asimov, otherwise''
.
program: 'asimov' inlist_field 'authors'
returns'1'
if any author matches the regular expressionasimov
, e.g., Asimov, Isaac or Isaac Asimov, otherwise''
.
program: 'asimov$' inlist_field 'authors'
returns'1'
if any author matches the regular expressionasimov$
, e.g., Isaac Asimov, otherwise''
. It doesn’t match Asimov, Isaac because of the$
anchor in the regular expression.
program: if field('series') != 'foo' then 'bar' else 'mumble' fi
returns'bar'
if the book’s series is not foo. Otherwise it returns'mumble'
.
program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi
returns'yes'
if series is either foo or 1632, otherwise'no'
.
program: if '^(foo|1632)$' in field('series') then 'yes' else 'no' fi
returns'yes'
if series is either foo or 1632, otherwise'no'
.
program: if 11 > 2 then 'yes' else 'no' fi
geeft'no'
omdat de>
operator een lexicale vergelijking doet.
program: if 11 ># 2 then 'yes' else 'no' fi
geeft'yes'
terug omdat de>#
operator een numerieke vergelijking doet.
Functions in General Program Mode
See Template function reference for the list of functions built into the template language.
Aantekeningen:
As opposed to Single Function Mode, in General Program Mode you must specify the first parameter
value
.All parameters are expression_lists (see the grammar above).
Meer complexe programma’s in sjabloonexpressies - Sjabloon Programma Modus¶
Sjabloon Programma Modus (SPM) is een mengeling van Algemene Programma Modus en Eén Functie Modus. TPM verschilt van Eén Functie Modus in dat het toelaat sjabloon expressies te schrijven die verwijzen naar andere metadata velden, geneste functies gebruikt, variabelen wijzigt, en rekenkunde doet. Het verschilt van Algemene Programma Modus in dat de sjabloon gevat wordt tussen {
en }
karakters en niet begint met het woord program:
. Het programma deel van de sjabloon is een Algemene Programma Modus expressie lijst.
Example: assume you want a template to show the series for a book if it has one, otherwise show the value of a custom field #genre. You cannot do this in the Single Function Mode because you cannot make reference to another metadata field within a template expression. In TPM you can, as the following expression demonstrates:
{series_index:0>7.1f:'ifempty($, -5)'}
Het voorbeeld toont meerdere dingen:
TPM is used if the expression begins with
:'
and ends with'}
. Anything else is assumed to be in Single Function Mode.If the template contains a prefix and suffix, the expression ends with
'|
where the|
is the delimiter for the prefix. Example:{series_index:0>7.1f:'ifempty($, -5)'|prefix | suffix}
Functions must be given all their arguments. For example, the standard built-in functions must be given the initial parameter
value
.The variable
$
is usable as thevalue
argument and stands for the value of the field named in the template,series_index
in this case.spaties worden genegeerd en kunnen eender waar in de expressie gebruikt worden
constante strings zijn omringd door overeenkomende aanhalingstekens, ofwel
'
ofwel"
.
In TPM, met {
en }
karakters in string literals kan leiden tot fouten of onverwachte resultaten omdat ze de sjabloonprocessor in verwarring brengen. Het probeert ze te behandelen als sjabloon expressie grenzen, niet karakters. In sommige maar niet alle gevallen kan u een {
vervangen door [[
en een }
door ]]. In het algemeen, als uw programma {
en }
karakters bevat, moet u Algemene Programma Modus gebruiken.
Python Template Mode¶
Python Template Mode (PTM) lets you write templates using native Python and the calibre API. The database API will be of most use; further discussion is beyond the scope of this manual. PTM templates are faster and can do more complicated operations but you must know how to write code in Python using the calibre API.
A PTM template begins with:
python:
def evaluate(book, context):
# book is a calibre metadata object
# context is an instance of calibre.utils.formatter.PythonTemplateContext,
# which currently contains the following attributes:
# db: a calibre legacy database object.
# globals: the template global variable dictionary.
# arguments: is a list of arguments if the template is called by a GPM template, otherwise None.
# funcs: used to call Built-in/User functions and Stored GPM/Python templates.
# Example: context.funcs.list_re_group()
# your Python code goes here
return 'a string'
You can add the above text to your template using the context menu, usually accessed with a right click. The comments are not significant and can be removed. You must use python indenting.
The context object supports str(context)
that returns a string of the context’s contents, and context.attributes
that returns a list of the attribute names in the context.
The context.funcs
attribute allows calling Built-in and User template functions, and Stored GPM/Python templates, so that you can execute them directly in your code. The functions are retrieved using their names. If the name conflicts with a Python keyword, add an underscore to the end of the name. Examples:
context.funcs.list_re_group()
context.funcs.assert_()
Here is an example of a PTM template that produces a list of all the authors for a series. The list is stored in a Column built from other columns, behaves like tags. It shows in Book details and has the on separate lines checked (in Preferences → Look & feel → Book details). That option requires the list to be comma-separated. To satisfy that requirement the template converts commas in author names to semicolons then builds a comma-separated list of authors. The authors are then sorted, which is why the template uses author_sort.
python:
def evaluate(book, context):
if book.series is None:
return ''
db = context.db.new_api
ans = set()
# Get the list of books in the series
ids = db.search(f'series:"={book.series}"', '')
if ids:
# Get all the author_sort values for the books in the series
author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
# Add the names to the result set, removing duplicates
for aus in author_sorts:
ans.update(v.strip() for v in aus.split('&'))
# Make a sorted comma-separated string from the result set
return ', '.join(v.replace(',', ';') for v in sorted(ans))
The output in Book details looks like this:
Opgeslagen sjablonen¶
Both General Program Mode and Python Template Mode support saving templates and calling those templates from another template, much like calling stored functions. You save templates using Preferences → Advanced → Template functions. More information is provided in that dialog. You call a template the same way you call a function, passing positional arguments if desired. An argument can be any expression. Examples of calling a template, assuming the stored template is named foo
:
foo()
– roep de sjabloon aan zonder argumenten door te geven.foo(a, b)
roep de sjabloon aan met doorgeven van de waardes van de twee variabelena
enb
.foo(if field('series') then field('series_index') else 0 fi)
– als het boek eenseries
heeft, passeer deseries_index
, anders de waarde0
.
In GPM you retrieve the arguments passed in the call to the stored template using the arguments
function. It both declares and initializes local variables, effectively parameters. The variables are positional; they get the value of the parameter given in the call in the same position. If the corresponding parameter is not provided in the call then arguments
assigns that variable the provided default value. If there is no default value then the variable is set to the empty string. For example, the following arguments
function declares 2 variables, key
, alternate
:
arguments(key, alternate='series')
Voorbeelden, er weer vanuit gaand dat de opgeslagen sjabloon foo
heet:
foo('#myseries')
– argumentkey
krijgt de waarde'myseries'
toegewezen en het argumentalternate
krijgt de standaard waarde'series'
toegewezen.foo('series', '#genre')
de variabelekey
krijgt de waarde'series'
toegewezen en de variabelealternate
de waarde'#genre'
.foo()
– de variabelekey
krijgt de lege string toegewezen en de variabelealternate
de waarde'series'
.
In PTM the arguments are passed in the arguments
parameter, which is a list of strings. There isn’t any way to specify default values. You must check the length of the arguments
list to be sure that the number of arguments is what you expect.
An easy way to test stored templates is using the Template tester
dialog. For ease of access give it a keyboard shortcut in Preferences → Advanced → Keyboard shortcuts → Template tester. Giving the Stored templates
dialog a shortcut will help switching more rapidly between the tester and editing the stored template’s source code.
Bijkomende informatie voor sjablonen voorzien¶
A developer can choose to pass additional information to the template processor, such as application-specific book metadata or information about what the processor is being asked to do. A template can access this information and use it during the evaluation.
Ontwikkelaar: hoe bijkomende informatie doorgeven
The additional information is a Python dictionary containing pairs variable_name: variable_value
where the values must be strings. The template can access the dictionary, creating template local variables named variable_name
containing the value variable_value
. The user cannot change the name so it is best to use names that won’t collide with other template local variables, for example by prefixing the name with an underscore.
This dictionary is passed to the template processor (the formatter
) using the named parameter global_vars=your_dict
. The full method signature is:
def safe_format(self, fmt, kwargs, error_value, book,
column_name=None, template_cache=None,
strip_results=True, template_functions=None,
global_vars={})
Sjabloon schrijver: hoe toegang krijgen tot de bijkomende informatie
You access the additional information (the globals
dictionary) in a template using the template function:
globals(id[=expression] [, id[=expression]]*)
where id
is any legal variable name. This function checks whether the additional information provided by the developer contains the name. If it does then the function assigns the provided value to a template local variable with that name. If the name is not in the additional information and if an expression
is provided, the expression
is evaluated and the result is assigned to the local variable. If neither a value nor an expression is provided, the function assigns the empty string (''
) to the local variable.
A template can set a value in the globals
dictionary using the template function:
set_globals(id[=expression] [, id[=expression]]*)
This function sets the globals
dictionary key:value pair id:value
where value
is the value of the template local variable id
. If that local variable doesn’t exist then value
is set to the result of evaluating expression
.
Notes on the difference between modes¶
The three program modes, Single Function Mode (SFM), Template Program Mode (TPM), and General Program Mode (GPM), work differently. SFM is intended to be ‘simple’ so it hides a lot of programming language bits.
Verschillen:
In SFM the value of the column is always passed as an ‘invisible’ first argument to a function included in the template.
SFM doesn’t support the difference between variables and strings; all values are strings.
The following SFM template returns either the series name or the string “no series”:
{series:ifempty(no series)}
De soortgelijke sjabloon in SPM is:
{series:'ifempty($, 'no series')'}
De soortgelijke sjabloon in APM is:
program: ifempty(field('series'), 'no series')
The first argument to
ifempty
is the value of the fieldseries
. The second argument is the stringno series
. In SFM the first argument, the value of the field, is automatically passed (the invisible argument).Several template functions, for example
booksize()
andcurrent_library_name()
, take no arguments. Because of the ‘invisible argument’ you cannot use these functions in SFM.Nested functions, where a function calls another function to compute an argument, cannot be used in SFM. For example this template, intended to return the first 5 characters of the series value uppercased, won’t work in SFM:
{series:uppercase(substr(0,5))}
TPM and GPM support nested functions. The above template in TPM would be:
{series:'uppercase(substr($, 0,5))'}
In GPM it would be:
program: uppercase(substr(field('series'), 0,5))
As noted in the above Template Program Mode section, using
{
and}
characters in TPM string literals can lead to errors or unexpected results because they confuse the template processor. It tries to treat them as template boundaries, not characters. In some but not all cases you can replace a{
with[[
and a}
with ]]. Generally, if your program contains{
and}
characters then you should use General Program Mode.
User-defined Python template functions¶
You can add your own Python functions to the template processor. Such functions can be used in any of the three template programming modes. The functions are added by going to Preferences → Advanced → Template functions. Instructions are shown in that dialog. Note that you can use Python Templates for a similar purpose. As calling user-defined functions is faster than calling a Python template, user-defined functions might be more efficient depending on the complexity of what the function or template does.
Extra opmerkingen voor opslaan/versturen van sjablonen¶
Special processing is applied when a template is used in a save to disk or send to device template. The values of the fields are cleaned, replacing characters that are special to file systems with underscores, including slashes. This means that field text cannot be used to create folders. However, slashes are not changed in prefix or suffix strings, so slashes in these strings will cause folders to be created. Because of this, you can create variable-depth folder structure.
For example, assume we want the folder structure series/series_index - title, with the caveat that if series does not exist, then the title should be in the top folder. The template to do this is:
{series:||/}{series_index:|| - }{title}
The slash and the hyphen appear only if series is not empty.
The lookup function lets us do even fancier processing. For example, assume that if a book has a series, then we want the folder structure series/series index - title.fmt. If the book does not have a series then we want the folder structure genre/author_sort/title.fmt. If the book has no genre then we want to use ‘Unknown’. We want two completely different paths, depending on the value of series.
Om dit te bereiken:
Create a composite field (give it lookup name #aa) containing
{series}/{series_index} - {title}
. If the series is not empty, then this template will produce series/series_index - title.Create a composite field (give it lookup name #bb) containing
{#genre:ifempty(Unknown)}/{author_sort}/{title}
. This template produces genre/author_sort/title, where an empty genre is replaced with Unknown.Set the save template to
{series:lookup(.,#aa,#bb)}
. This template chooses composite field#aa
if series is not empty and composite field#bb
if series is empty. We therefore have two completely different save paths, depending on whether or not series is empty.
Tips¶
Use the Template Tester to test templates. Add the tester to the context menu for books in the library and/or give it a keyboard shortcut.
Templates can use other templates by referencing composite columns built with the desired template. Alternatively, you can use Stored Templates.
In a plugboard, you can set a field to empty (or whatever is equivalent to empty) by using the special template
{}
. This template will always evaluate to an empty string.The technique described above to show numbers even if they have a zero value works with the standard field series_index.
Template function reference¶
- Reference for all built-in template language functions
- Arithmetic
- Boolean
- Case changes
- Database functions
- Date functions
- Formatting values
- Get values from metadata
- annotation_count
- approximate_formats
- author_links
- author_sorts
- booksize
- connected_device_name
- connected_device_uuid
- current_library_name
- current_library_path
- current_virtual_library_name
- field
- formats_modtimes
- formats_paths
- formats_sizes
- has_cover
- is_marked
- language_codes
- language_strings
- ondevice
- raw_field
- raw_list
- series_sort
- user_categories
- virtual_libraries
- Interate over values
- List lookup
- List manipulation
- Overige
- Recursion
- Relational
- String manipulation
- API of the Metadata objects