Page structure
The same content can be delivered to the Web in different structured formats, and the transformation of that content in the final pages must be completely automatic.
General operation
Web pages structure is defined by the HTML markup, and using jqt it is added to the input content and data using a template. jqt transforms templates into jq scripts, but before that GPP is used to preprocess them. The generated script will be combined with the document and data inputs in the render stage to produce the final HTML page. This is described on the top of this diagram:
When invoking jqt
you can use the -D
, -I
, -i
, -j
and -L
options to modify template rendering:
- -D NAME=STRING
- Defines the user macro NAME as equal to STRING.
- -I DIRECTORY
- Appends DIRECTORY to the end of the preprocessor list of directories to be searched for include files.
- -i MODULE
- Includes the jq MODULE in the render stage.
- -j NAME:MODULE
- Imports the jq MODULE in the render stage and define helper function named NAME if MODULE is a data module and has the suffix
.json
. - -L DIRECTORY
- Appends DIRECTORY to the end of the jq list of directories to be searched for included and imported modules.
Template syntax
A template is a text file with intermixed snippets of jq code. Snippets can be expressions (delimited by {{
and }}
), which get replaced with values when a template is rendered and actions (delimited by {%
and %}
), which control the logic of the template. Comments (delimited by {#
and #}
) are ignored and not copied to the output. This is a complete template example:
<html lang='{{page.lang//site.lang}}'>
<head>
<title>{{page.title | gsub("<[^>]*>"; "")}}</title>
{# include files in preprocessing stage: #}
<%include "head.html">
<meta name="generator" content="JQT v<%version>"/>
{# optional line: #}
<meta name='dcterms.modified' content='{{page.updated//empty}}' />
{# implicit loop for all authors: #}
{% page.author | sort[] %}<meta name='author' content='{{.}}' />
</head>
<body>
<h1>{{page.title}}</h1>
<div id="CONTENT">
{{$jqt._content}}
</div>
{# macro calls: #}
<%partial analytics 'UA-82432866-1'>
</body>
</html>
Preprocessing
Templates are preprocessed using GPP. All the expected options in a preprocessor are available, like defining new macros, include other files, etc. For example, a template fragment like
will expand to the string <meta name=“generator” content=“JQT v0.5.1”/>
(assuming the macro version
has been defined) as you can see in the internal code of this page.
Macro calls
The macro syntax used by jqt in templates and MarkDown documents precedes macro names with the characters <%
and finishes the macro calls with the character >
. Here are some of the predefined macros:
<%defeval x y>
<%define x y>
<%elif expr>
<%else>
<%endif>
<%eval expr>
<%if expr>
<%ifdef x>
<%ifeq x y>
<%ifndef x>
<%ifneq x y>
<%include file>
<%undef x>
Inside macro definitions parameters are prefixed by a dollar ($1
, $2
, etc.), but named parameters are also possible:
<%define stylesheet
<link rel="stylesheet" type="text/css" href="$1"/>
>
Predefined macros and user define macros have the same call sequence:
<%include head.html>
<%stylesheet jqt.css>
With these simple tools is possible to emulate features considered advanced in some template engines, like template inheritance (also known as blocks). For example, in the base template (assume it is named default.html
) you can put this conditional macro call to define a default title block:
<%ifndef HEAD_TITLE>
<title>{{page.title}}</title> {# default block #}
<%else><%call HEAD_TITLE><%endif>
And in the derived template you can define a new macro for the desired block, before include the base template:
<%define HEAD_TITLE
<title>{{page.title}} – {{site.title}}</title>
>
<%include default.html>
In addition to GPP predefined macros jqt define some macros to be included in the render stage. The more useful will be perhaps <%partial name arg...>
, to include a template file passing arguments to it and <%call name arg...>
, to call a macro by name.
Warning: you must see the GPP manual if you want to know all the gory details.
Skips
Some fragments of text are skipped during macro expansion, like comments, continuation lines and delimited strings of characters:
<# Block comments, removed #>
Continuation lines using an ampersand &
just before the newline character
Strings are copied to the output, but evaluation of macros inside strings can be enabled or disabled. String delimiters can be copied, or not, to the output:
<!-- XML comments -->
<%sc 'Single quoted strings, only available in user defined macro calls'>
<%sc "Double quoted strings, only available in user defined macro calls">
All jqt template delimited regions: {#...#}, {%...%}, {{...}}
This table summarizes all the available skips:
Delimiters | Macro expansion | Delimiters removed | Content removed |
---|---|---|---|
&\n 1 |
No | Yes | There is no content |
<# #> |
No | Yes | Yes |
' ' 2 |
No | Yes | No |
" " 3 |
Yes | Yes | No |
<!-- --> |
No | No | No |
{{ }} |
No | No | No |
{% %} |
No | No | No |
{# #} |
No | No | No |
Code snippets
The input text for a template is UTF-8 text with intermixed snippets of jq code. Snippets can be expressions, actions and comments. The delimiters used by jqt are as follows:
Delimiters | Purpose |
---|---|
{{ ... }} |
Expressions to evaluate |
{% ... %} |
Actions for conditional evaluation and loops |
{# ... #} |
Comments not included in the output |
Expressions
The text in expressions and actions is normal jq code, where as a bonus, the $jqt
global variable points to the jq
JSON input (the initial .
). The rules for expression evaluation are very simple:
- If an expression evaluates to
empty
the whole line vanishes. - If an expression produces only one value the delimited snippet is replaced with this value.
- If an expression produces multiple values the whole line is repeated multiple times, with the expression evaluated again each time.
Warning: if a line contains two or more expressions producing multiple values a cartesian product is generated!
Actions
There are two kinds of actions:
- One line actions: lines beginning with optional space, followed by a
{%...%}
snippet and more text. - Multiline actions: initial line prefixed with optional space, followed by an opening
{%...%}
snippet and a newline character immediately after the character}
; then zero or more template lines; final line prefixed with optional space, the ending{% end %}
snippet and a newline character. Multiline actions can nest and contain expressions and other actions.
The evaluation rules for one line actions are as follows:
- If the delimited snippet evaluates to
empty
the whole line vanishes. - Otherwise, for each value produced the text following the snippet is evaluated with the value assigned to the dot (
.
). The initial dot is still available in the global variable$jqt
.
The evaluation rules for multiline actions are as follows:
- If the opening snippet evaluates to
empty
all lines until the ending snippet disappear. - Otherwise, for each value produced the lines until the ending snippet are evaluated with the value assigned to the dot (
.
). The initial dot is still available in the global variable$jqt
.