# Template Examples

(as of 1 September 2006)

## Simple Example

One reason this example is so simple is that it doesn't even require a separate template file, but instead uses `TemplateFromString`. It also doesn't use sections or template-includes.

    int main() {
      static const char template_text[] =
        "ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
      Template* tpl = TemplateFromString::GetTemplate("error_msg_tpl", template_text,
                                                      DO_NOT_STRIP);
      FILE* fp = fopen(argv[1], "r");
      if (fp == NULL) {
        int err_no = errno;   // squirrel this away
        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;
        tpl->Expand(&error_text, &dict);
        puts(error_text.c_str());
      }
    }

This example is only slightly more complicated: we only print the ": <error message>" part when the error message isn't the empty string.

    int main() {
      static const char template_text[] =
         "ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}"
         "{{#MSG_SECTION}}: {{ERROR_MESSAGE}}{{/MSG_SECTION}}\n";
      Template* tpl = TemplateFromString::GetTemplate("error_msg", template_text,
                                                      DO_NOT_STRIP);
      FILE* fp = fopen(argv[1], "r");
      if (fp == NULL) {
        int err_no = errno;   // squirrel this away
        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;
        tpl->Expand(&error_text, &dict);
        puts(error_text.c_str());
      }
    }

This maybe-show-text functionality is one way the template machinery is more powerful than just using `printf`. 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.

## Search Results Page

Here is an example template that could be used to format a Google search results page:

    {{>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}}

Here is a sample procedure that could populate a dictionary for expanding that template. The "one procedure" entry point is `fill_search_results_dictionary`. The `SetTemplateValues` function is a separate entry point for initializing each top-level template with some standard values.

    #include "template.h"

    RegisterTemplateFilename(SEARCH_RESULTS_FN, "search_results.tpl");
    #include "search_results.tpl.varnames.h"  // defines ksr_HEADER, etc.

    using google::Template;
    using google::TemplateDictionary;
    using google::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) {
      Template* tpl = Template::GetTemplate(SEARCH_RESULTS_FN, STRIP_WHITESPACE);
      TemplateDictionary dict("search-results dict");
      string output;
      fill_search_results_dictionary(&dict, query);
      tpl->Expand(&output, &dict);
      // output now holds the expanded template
    }

- Howto
- Tips