mirror of
https://github.com/OlafvdSpek/ctemplate.git
synced 2025-10-05 19:16:54 +08:00

* Major documentation revamp: howto -> guide + reference (csilvers) * Protect auto-generated #include files with header guard (dnovillo) * PORTING: autoconf macros to get cygwin/mingw to compile (csilvers)
348 lines
12 KiB
HTML
348 lines
12 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>Template Examples</title>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<link href="http://www.google.com/favicon.ico" type="image/x-icon"
|
|
rel="shortcut icon">
|
|
<link href="designstyle.css" type="text/css" rel="stylesheet">
|
|
<style type="text/css">
|
|
ol.bluelist li {
|
|
color: #3366ff;
|
|
font-family: sans-serif;
|
|
}
|
|
ol.bluelist li p {
|
|
color: #000;
|
|
font-family: "Times Roman", times, serif;
|
|
}
|
|
ul.blacklist li {
|
|
color: #000;
|
|
font-family: "Times Roman", times, serif;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Template Examples</h1>
|
|
|
|
|
|
<h2> Simple Example </h2>
|
|
|
|
<p>One reason this example is so simple is that it doesn't even
|
|
require a separate template file, but instead uses
|
|
<code>StringToTemplateCache()</code>. It also doesn't use sections or
|
|
template-includes.</p>
|
|
|
|
<pre class=example>
|
|
|
|
int main() {
|
|
static const char template_text[] =
|
|
"ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
|
|
ctemplate::StringToTemplateCache("mytpl", template_text, ctemplate::DO_NOT_STRIP);
|
|
FILE* fp = fopen(argv[1], "r");
|
|
if (fp == NULL) {
|
|
int err_no = errno; // squirrel this away
|
|
ctemplate::TemplateDictionary dict("error_msg: fopen()");
|
|
dict.SetValue("FUNCTION", "fopen");
|
|
dict.SetValue("ARGS", argv[1]);
|
|
dict.SetIntValue("ERROR_CODE", err_no);
|
|
dict.SetValue("ERROR_MESSAGE", strerror(err_no));
|
|
|
|
string error_text;
|
|
ctemplate::ExpandTemplate("mytpl", ctemplate::DO_NOT_STRIP, &dict, &error_text);
|
|
puts(error_text.c_str());
|
|
}
|
|
}
|
|
|
|
</pre>
|
|
|
|
Note: If this template was intended to run in a web application, you can
|
|
leverage the functionality provided by the auto-escape mode. Simply add
|
|
the AUTOESCAPE pragma directive at the top of the template text and your
|
|
variables will be automatically escaped for the context you specify.
|
|
|
|
For example, if your template is returned in an HTML context,
|
|
change the <code>template_text</code> declaration as follows:
|
|
|
|
<pre class=example>
|
|
static const char template_text[] =
|
|
"{{%AUTOESCAPE context=\"HTML\"}}"
|
|
"ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
|
|
</pre>
|
|
|
|
<p>This example is only slightly more complicated: we only print the
|
|
": <error message>" part when the error message isn't the empty
|
|
string.</p>
|
|
|
|
<pre class=example>
|
|
|
|
int main() {
|
|
static const char template_text[] =
|
|
"ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}"
|
|
"{{#MSG_SECTION}}: {{ERROR_MESSAGE}}{{/MSG_SECTION}}\n";
|
|
ctemplate::StringToTemplateCache("mytpl", template_text, ctemplate::DO_NOT_STRIP);
|
|
FILE* fp = fopen(argv[1], "r");
|
|
if (fp == NULL) {
|
|
int err_no = errno; // squirrel this away
|
|
ctemplate::TemplateDictionary dict("file_error_message");
|
|
dict.SetValue("FUNCTION", "fopen");
|
|
dict.SetValue("ARGS", argv[1]);
|
|
dict.SetIntValue("ERROR_CODE", err_no);
|
|
if (err_no > 0)
|
|
dict.SetValueAndShowSection("ERROR_MESSAGE", strerror(err_no),
|
|
"MSG_SECTION");
|
|
|
|
string error_text;
|
|
ctemplate::ExpandTemplate("mytpl", ctemplate::DO_NOT_STRIP, &dict, &error_text);
|
|
puts(error_text.c_str());
|
|
}
|
|
delete tpl;
|
|
}
|
|
|
|
</pre>
|
|
|
|
<p>This maybe-show-text functionality is one way the template
|
|
machinery is more powerful than just using <code>printf</code>.
|
|
Another nice property of templates is you can reuse the same variable
|
|
multiple times in your template string. You can also define the
|
|
variable values in any order.</p>
|
|
|
|
|
|
<h2> Search Results Page </h2>
|
|
|
|
<p>Here is an example template that could be used to format a Google
|
|
search results page:</p>
|
|
|
|
<pre class=example>
|
|
|
|
{{>HEADER}}
|
|
<body bgcolor=white>
|
|
|
|
{{>PAGE_HEADING}}{{!The following div must be on the same line}}<div>
|
|
|
|
{{!The ONE_RESULT section displays a single search item}}
|
|
{{#ONE_RESULT}}
|
|
{{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
|
|
{{#SUBITEM_SECTION}}<blockquote>{{/SUBITEM_SECTION}}
|
|
{{! LEAD_LINE is received HTML-escaped from the backend.}}
|
|
<p><a href="{{JUMP_TO_URL:html_escape}}" target=nw>{{LEAD_LINE}}</a><font size=-1>
|
|
|
|
{{! SNIPPET1, SNIPPET2 are HTML-escaped in the snippet generator.}}
|
|
{{#SNIPPET1_SECTION}}
|
|
<br>{{SNIPPET1}}
|
|
{{/SNIPPET1_SECTION}}
|
|
|
|
{{#SNIPPET2_SECTION}}
|
|
<br>{{SNIPPET2}}
|
|
{{/SNIPPET2_SECTION}}
|
|
|
|
{{#DESCRIPTION_SECTION}}
|
|
{{! DESC is received HTML-escaped from the backend.}}
|
|
<br><span class=f>Description:</span> {{DESC}}
|
|
{{/DESCRIPTION_SECTION}}
|
|
|
|
{{#CATEGORY_SECTION}}
|
|
<br><span class=f>Category:</span> <a href="{{CAT_URL:html_escape}}" class=f>
|
|
{{CATEGORY:html_escape}}</a>
|
|
{{/CATEGORY_SECTION}}
|
|
|
|
{{#LASTLINE_SECTION}}
|
|
<br><font color="{{ALT_TEXT_COLOR:h}}">{{URL:h}}
|
|
{{#KS_SECTION}}} - {{KSIZE:h}}{{/KS_SECTION}}}
|
|
{{#CACHE_SECTION}}} - <a href="{{CACHE_URL:h}}" class=f>Cached</A>
|
|
{{/CACHE_SECTION}}}
|
|
{{#SIM_SECTION}}} - <a href="{{SIM_PAGES_URL:h}}" class=f>Similar pages</A>
|
|
{{/SIM_SECTION}}}
|
|
|
|
{{#STOCK_SECTION}}
|
|
- <a href="{{STOCK_URL:h}}" class=f>Stock quotes: {{STOCK_SYMBOL:h}}</a>
|
|
{{/STOCK_SECTION}}
|
|
</font>
|
|
{{/LASTLINE_SECTION}}
|
|
|
|
{{#MORE_SECTION}}
|
|
<br>[ <a href="{{MORE_URL:h}}" class=f>More results from {{MORE_LABEL:h}}</a> ]
|
|
{{/MORE_SECTION}}
|
|
|
|
</font><br>
|
|
{{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
|
|
{{#SUBITEM_SECTION}}</blockquote>{{/SUBITEM_SECTION}}
|
|
{{/ONE_RESULT}}
|
|
</div> {{! this /div closes the div at the top of this file}}
|
|
{{>PAGE_FOOTING}}
|
|
|
|
</pre>
|
|
|
|
<p> Here is a sample procedure that could populate a dictionary for
|
|
expanding that template. The "one procedure" entry point is
|
|
<code>fill_search_results_dictionary</code>. The
|
|
<code>SetTemplateValues</code> function is a separate entry point for
|
|
initializing each top-level template with some standard values.</p>
|
|
|
|
<pre class=example>
|
|
#include "template.h"
|
|
|
|
RegisterTemplateFilename(SEARCH_RESULTS_FN, "search_results.tpl");
|
|
#include "search_results.tpl.varnames.h" // defines ksr_HEADER, etc.
|
|
|
|
using ctemplate::TemplateDictionary;
|
|
using ctemplate::ExpandTemplate;
|
|
using ctemplate::STRIP_WHITESPACE;
|
|
|
|
// IsEmpty
|
|
// A simple utility function
|
|
static bool IsEmpty(const string &str) {
|
|
return str.empty();
|
|
}
|
|
|
|
// SetTemplateValues
|
|
// Use the TemplateDictionary object to set template-wide values that
|
|
// may be used in the top-level template and all its sub-sections
|
|
// and included templates. The template-wide values are all
|
|
// colors from the Palette object
|
|
void SetTemplateValues(TemplateDictionary *dictionary, const Palette* colors) {
|
|
// better would be to use ksr_LINK_COLOR, etc, assuming those are
|
|
// defined in search_results.tpl.varnames.h. But using literal
|
|
// text, as here, is legal as well.
|
|
dictionary->SetValue("LINK_COLOR", colors->link_color);
|
|
dictionary->SetValue("BAR_TEXT_COLOR", colors->bar_text_color);
|
|
dictionary->SetValue("TEXT_COLOR", colors->text_color);
|
|
dictionary->SetValue("FAINT_COLOR", colors->faint_color);
|
|
dictionary->SetValue("IMPORTANT_COLOR", colors->important_color);
|
|
dictionary->SetValue("BAR_COLOR", colors->bar_color);
|
|
dictionary->SetValue("ALT_TEXT_COLOR", colors->alt_text_color);
|
|
dictionary->SetValue("ALINK_COLOR", colors->alink_color);
|
|
dictionary->SetValue("VLINK_COLOR", colors->vlink_color);
|
|
}
|
|
|
|
// fill_search_results_dictionary
|
|
// Iterates through all the QueryResults contained in the Query object.
|
|
// For each one, it sets corresponding template dictionary values
|
|
// (or hides sections containing their variables, if appropriate) in
|
|
// a sub-dictionary and then adds that dictionary to the parent
|
|
void fill_search_results_dictionary(TemplateDictionary *dictionary,
|
|
const Query *query) {
|
|
dictionary->SetFilename(SEARCH_RESULTS_FN);
|
|
|
|
// These two functions are defined elsewhere
|
|
fill_header_dictionary(dictionary->AddIncludeDictionary(ksr_HEADER));
|
|
fill_page_heading_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_HEADING),
|
|
query);
|
|
|
|
ResultsList *results = query->GetResults();
|
|
int resCount = 0;
|
|
|
|
for (ResultsList::const_iterator iter = results->begin();
|
|
iter != results->end();
|
|
++iter) {
|
|
QueryResult *qr = (*iter);
|
|
|
|
// Create a new sub-dictionary named "Result Dict <n>" for this entry
|
|
|
|
++resCount;
|
|
|
|
TemplateDictionary *result_dictionary =
|
|
dictionary->AddSectionDictionary(ksr_ONE_RESULT);
|
|
|
|
result_dictionary->SetValue(ksr_JUMP_TO_URL, qr->GetUrl());
|
|
|
|
if (qr->IsSubItem()) {
|
|
result_dictionary->ShowSection(ksr_SUBITEM_SECTION);
|
|
}
|
|
|
|
result_dictionary->SetValue(ksr_LEAD_LINE, qr->GetLeadLine());
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_SNIPPET1, qr->GetSnippet1(),
|
|
ksr_SNIPPET1_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_SNIPPET2, qr->GetSnippet2(),
|
|
ksr_SNIPPET2_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_DESC, qr->GetDescription(),
|
|
ksr_DESCRIPTION_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_CAT_URL, qr->GetCategoryUrl(),
|
|
ksr_CATEGORY_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection("CATEGORY", qr->GetCategoryName(),
|
|
"CATEGORY_SECTION");
|
|
|
|
|
|
if (IsEmpty(qr->GetDisplayUrl()) &&
|
|
IsEmpty(qr->GetPageSize()) &&
|
|
IsEmpty(qr->GetCachedUrl()) &&
|
|
IsEmpty(qr->GetSimilarPagesUrl()) &&
|
|
(IsEmpty(qr->GetStockUrl()) ||
|
|
IsEmpty(qr->GetStockSymbol())) ) {
|
|
// there is nothing on the last line, so hide it altogether
|
|
} else {
|
|
result_dictionary->ShowSection("LASTLINE_SECTION");
|
|
|
|
result_dictionary->SetValue(ksr_URL, qr->GetDisplayUrl());
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_KSIZE, qr->GetPageSize(),
|
|
ksr_KS_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_CACHE_URL, qr->GetCachedUrl(),
|
|
ksr_CACHE_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_SIM_PAGES_URL,
|
|
qr->GetSimilarPagesUrl(),
|
|
ksr_SIM_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_STOCK_URL, qr->GetStockUrl(),
|
|
ksr_STOCK_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_STOCK_SYMBOL,
|
|
qr->GetStockSymbol(),
|
|
ksr_STOCK_SECTION);
|
|
}
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_MORE_URL, qr->GetMoreUrl(),
|
|
ksr_MORE_SECTION);
|
|
|
|
result_dictionary->SetValueAndShowSection(ksr_MORE_LABEL, qr->GetMoreLabel(),
|
|
ksr_MORE_SECTION);
|
|
|
|
}
|
|
|
|
fill_page_footing_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_FOOTING),
|
|
query);
|
|
}
|
|
|
|
void output_page(const Query* query) {
|
|
TemplateDictionary dict("search-results dict");
|
|
string output;
|
|
fill_search_results_dictionary(&dict, query);
|
|
ctemplate::ExpandTemplate(SEARCH_RESULTS_FN, STRIP_WHITESPACE, &dict, &output);
|
|
// output now holds the expanded template
|
|
}
|
|
|
|
</pre>
|
|
|
|
|
|
<hr>
|
|
<ul>
|
|
<li> <A HREF="guide.html">User's Guide</A> </li>
|
|
<li> <A HREF="reference.html">Reference Manual</A> </li>
|
|
<li> <A HREF="auto_escape.html">Auto Escape</A> </li>
|
|
<li> <A HREF="tips.html">Tips</A> </li>
|
|
<!--
|
|
<li> <A HREF="example.html">Example</A> </li>
|
|
-->
|
|
</ul>
|
|
|
|
<hr>
|
|
<address>
|
|
Craig Silverstein<br>
|
|
<script type=text/javascript>
|
|
var lm = new Date(document.lastModified);
|
|
document.write(lm.toDateString());
|
|
</script>
|
|
</address>
|
|
|
|
</body>
|
|
</html>
|