Formatted Search

Customize the display of search results.

The default output format of a %SEARCH{...}% is a table consisting of topic names and topic summaries. Use the format="..." parameter to customize the search result. The format parameter typically defines a bullet or a table row containing macros, such as %SEARCH{ "food" format="| $topic | $summary |" }%. See %SEARCH{...}% for other search parameters, such as separator="".

Syntax

Three parameters can be used to specify a customized search result:

1. header="..." parameter

Use the header parameter to specify the header of a search result. It should correspond to the format of the format parameter. This parameter is optional. Example:
header="| *Topic:* | *Summary:* |"

Format tokens that can be used in the header string:

Name: Expands To:
$web Name of the web
$ntopics Number of topics found in current web. Will be 0 (zero).
$nhits Number of hits if multiple="on". Will be 0 (zero).
$pager pager control - can be optionally customised using the pagerformat below
$n or $n() New line. Use $n() if followed by alphanumeric character, e.g. write Foo$n()Bar instead of Foo$nBar

TIP Most macros accept parameter strings which are split over multiple lines. This is usually more readable than using $n tokens. If you are familiar with sectional includes, you might also consider nested sectional includes to hold the newline content outside of the parameter string entirely.

TIP Note that newline is not a line break. The browser will wrap the lines together. If you require a line break, displaying the results on two lines, use %BR%. Or use two consecutive newlines to create a TML "Paragraph".

$nop or $nop() Is a "no operation". This token gets removed; useful for nested search
$quot Double quote (") (\" also works)
$percent Percent sign (%) ($percnt also works)
$dollar Dollar sign ($)
$lt Less than sign (<)
$gt Greater than sign (>)
$amp Ampersand (&)
$comma Comma (,)

ALERT! Note that if the separator parameter for SEARCH is not defined a newline is added after the header.

2. footer="..." parameter

Use the footer parameter to specify the footer of a search result. It should correspond to the format of the format parameter. This parameter is optional. Example:
footer="| *Total:* | *$nhits* |"

Format tokens that can be used in the footer string:

Name: Expands To:
$web Name of the web
$ntopics Number of topics found in current web
$nhits Number of hits if multiple="on". Cumulative across all topics in current web. Identical to $ntopics unless multiple="on"
$pager pager control - can be optionally customised using the pagerformat below
$n or $n() New line. Use $n() if followed by alphanumeric character, e.g. write Foo$n()Bar instead of Foo$nBar

TIP Most macros accept parameter strings which are split over multiple lines. This is usually more readable than using $n tokens. If you are familiar with sectional includes, you might also consider nested sectional includes to hold the newline content outside of the parameter string entirely.

TIP Note that newline is not a line break. The browser will wrap the lines together. If you require a line break, displaying the results on two lines, use %BR%. Or use two consecutive newlines to create a TML "Paragraph".

$nop or $nop() Is a "no operation". This token gets removed; useful for nested search
$quot Double quote (") (\" also works)
$percent Percent sign (%) ($percnt also works)
$dollar Dollar sign ($)
$lt Less than sign (<)
$gt Greater than sign (>)
$amp Ampersand (&)
$comma Comma (,)

ALERT! Note that if the separator parameter for SEARCH is not defined a newline is added after the last search result.

3. pagerformat="..." parameter

Use the pagerformat parameter to customise the appearance of the paging control. It should correspond to the format of the format parameter. This parameter is optional. Example:
pagerformat="Page $currentpage of $numberofpages [[$nexturl][next page]]"

Format tokens that can be used in the pagerformat string:

Name: Expands To:
$previouspage The page number before the currently displayed one
$currentpage The currently displayed page number
$nextpage The page number after the currently displayed one
$numberofpages Total number of pages there are results for
$pagesize The number of results per page
$previousurl full URL to the previous page - IF using the built in pager system
$nexturl full URL to the previous page - IF using the built in pager system
$previousbutton skin template (SEARCH:pager_previous) html for the full URL to the previous page - IF using the built in pager system
$nextbutton skin template (SEARCH:pager_next) html for the full URL to the previous page - IF using the built in pager system
$n or $n() New line. Use $n() if followed by alphanumeric character, e.g. write Foo$n()Bar instead of Foo$nBar

TIP Most macros accept parameter strings which are split over multiple lines. This is usually more readable than using $n tokens. If you are familiar with sectional includes, you might also consider nested sectional includes to hold the newline content outside of the parameter string entirely.

TIP Note that newline is not a line break. The browser will wrap the lines together. If you require a line break, displaying the results on two lines, use %BR%. Or use two consecutive newlines to create a TML "Paragraph".

$nop or $nop() Is a "no operation". This token gets removed; useful for nested search
$quot Double quote (") (\" also works)
$percent Percent sign (%) ($percnt also works)
$dollar Dollar sign ($)
$lt Less than sign (<)
$gt Greater than sign (>)
$amp Ampersand (&)
$comma Comma (,)

4. format="..." parameter

Use the format parameter to specify the format of one search hit. Example:
format="| $topic | $summary |"

Format tokens that can be used in the format string:

Name: Expands To:
$web Name of the web
$topic Topic name
$topic(20) Topic name, "- " hyphenated every 20 characters
$topic(30, -<br />) Topic name, hyphenated every 30 characters with separator "-<br />"
$topic(40, ...) Topic name, shortened to 40 characters with trailing ellipsis.
$parent Name of parent topic; empty if not set
$parent(20) Name of parent topic, same hyphenation/shortening as $topic()
$text Formatted topic text. In case of a multiple="on" search, it is the line found for each search hit.
$locked LOCKED flag (if any)
$date Time stamp of last topic update, e.g. 12 Nov 2024 - 17:10
$isodate Time stamp of last topic update, e.g. 2024-11-12T17:10Z
$index number of total results - can be used as a running counter in the format, or in the footer. This $index is not affected by web based partitioning of results.
$item the full name of a result item - in a SEARCH context, equivalent to $web.$topic
$rev Number of last topic revision, e.g. 4
$username Login username of last user to update the topic, e.g. jsmith
$wikiname WikiName of last user to update the topic, e.g. JohnSmith
$wikiusername WikiName of last usr to update the topic, like Main.JohnSmith
$createdate Time stamp of topic revision 1
$createusername Login username of topic revision 1, e.g. jsmith
$createwikiname WikiName of topic revision 1, e.g. JohnSmith
$createwikiusername WikiName topic link of topic revision 1, e.g. Main.JohnSmith
$summary Topic summary, just the plain text, all formatting and line breaks removed; up to 162 characters
$summary(50) Topic summary, up to 50 characters shown
$summary(showvarnames) Topic summary, with %SOMEMACRO{...}% macros shown as SOMEMACRO{...}
$summary(noheader) Topic summary, with leading ---+ headers removed
Note: The tokens can be combined, for example $summary(100, showvarnames, noheader)
$summary(searchcontext) Creates a topic summary with the search terms highlighted
$summary(searchcontext, 50) Creates a topic summary with the search terms highlighted, up to 50 characters
$changes Summary of changes between latest rev and previous rev
$changes(n) Summary of changes between latest rev and rev n
$formname The name of the form attached to the topic; empty if none
$formfield(name) The field value of a form field; for example, if Definition of "WikiWiki" was a search hit, $formfield(TopicClassification) would get expanded to =. This applies only to topics that have a DataForm. For multi-line textfields new lines are replaced by the value of the =newline parameter if it is defined, otherwise by an HTML <br />
$formfield(name, 10) Form field value, "- " hyphenated every 10 characters
$formfield(name, 20, -<br />) Form field value, hyphenated every 20 characters with separator "-<br />"
$formfield(name,30,...) Form field value, shortened to 30 characters with trailing ellipsis.
$formfield(name, display) Form field value after mapping the stored value to the display value (use with +values form fields). You can still use the hyphenation controls described above by placing them after display e.g. $formfield(name, display, 10)
$extract(reg-exp) A regular expression pattern to extract some text from a topic (does not search meta data; use $formfield instead). Escapes some characters to their standard FormatTokens in the discovered text to make embedding in other macros easier. See Using $extract and $pattern below for more information.
$pattern(reg-exp) As $extract, with the difference that $pattern does not escape quotes or precent signs in the result.
$count(reg-exp) Count of number of times a regular expression pattern appears in the text of a topic (does not search meta data). Follows guidelines for use and limitations outlined above under $pattern(reg-exp). Example: $count(.*?(---[+][+][+][+]) .*) counts the number of <H4> headers in a page.
$ntopics Number of topics found in current web. This is the current topic count, not the total number of topics
$nhits Number of hits if multiple="on". Cumulative across all topics in current web. Identical to $ntopics unless multiple="on"
$pager pager control - can be optionally customised using the pagerformat below
$n or $n() New line. Use $n() if followed by alphanumeric character, e.g. write Foo$n()Bar instead of Foo$nBar

TIP Most macros accept parameter strings which are split over multiple lines. This is usually more readable than using $n tokens. If you are familiar with sectional includes, you might also consider nested sectional includes to hold the newline content outside of the parameter string entirely.

TIP Note that newline is not a line break. The browser will wrap the lines together. If you require a line break, displaying the results on two lines, use %BR%. Or use two consecutive newlines to create a TML "Paragraph".

$nop or $nop() Is a "no operation". This token gets removed; useful for nested search
$quot Double quote (") (\" also works)
$percent Percent sign (%) ($percnt also works)
$dollar Dollar sign ($)
$lt Less than sign (<)
$gt Greater than sign (>)
$amp Ampersand (&)
$comma Comma (,)

Using $extract and $pattern

$extract and $pattern are subtle. These tokens specify a RegularExpression that covers the whole text (of each line found by the search if multiple="on", of the entire topic text otherwise). The regular expression typically starts with .*, and must end in .*

The leading .* matches all the content up to the start of the string you want to find. It will try to match the longest string of characters it can, so if your pattern occurs several times in the content it will always match the last occurence. If you always want to match the first occurrence, use .*? instead.

You _must* end the pattern with .*

Put the section of the pattern that matches the text you want to keep in parenthesis, like this $extract(.*?(from here.*?to here).*)
  • Example: $extract(.*?\*.*?Email\:\s*([^\n\r]+).*) extracts the e-mail address from * Email: ...

Do not use .* inside the parentheses, e.g. $extract(.*foo(.*)bar.*) does not work. You can however use .*? thus $extract(.*foo(.*?)bar.*)

Make sure that the integrity of a web page is not compromised; for example, if you include an HTML table make sure to include everything including the table end tag. $extract will automatically escape "<>&%$ characters so that the string matched by the pattern doesn't break any macros that are wrapped around it. $pattern does not do this, and should be used with care. $extract is only available in Foswiki 2.0 and later.

Examples

Here are some samples of formatted searches. The SearchPatternCookbook has other examples, such as creating a picklist of usernames, searching for topic children and more.

Search showing topic name and summary

%STARTSECTION{"example1"}%
%SEARCH{
   "VarREMOTE"
   scope="topic"
   nonoise="on"
   header="| *Topic*        | *Summary*  |"
   format="| [[$topic]]     | $summary   |"
   footer="| *Topics found* | *$ntopics* |"
}%
%ENDSECTION{"example1"}%

Click to execute

Table showing form field values of topics with a form

In a web where there is a form that contains a TopicClassification field, an OperatingSystem field and an OsVersion field we could write:

%STARTSECTION{"example2"}%
%SEARCH{
   "TopicClassification~'FrequentlyAskedQuestion'"
   type="query"
   nonoise="on"
   header="| *Topic:* | *Summary:* | *Related Topics:* |"
   format="| [[$topic]] | $formfield(TopicSummary) | $formfield(RelatedTopics) |"
}%
%ENDSECTION{"example2"}%

Click to execute

Extract some text from a topic using regular expression

The following example makes use of the $pattern() token to extract the first level-1 heading for each topic:


%SEARCH{
    "^---[+][^+][^\r\n]+[\r\n]"
    type="regex"
    nonoise="on"
    header="Headings:"
    limit="5"
    format="   * [[$topic][$pattern([\r\n\-+!]+([^\r\n]*?)[\r\n].*)]]"
    footer="Found $ntopics topics with level-1 headings"
}%

Click to execute

SEARCH is one of many macros that produce output which may be controlled with format, header and footer parameters, among others. To make use of additional macros in the output, familiarity with inside-out, left-to-right order of expansion rules is required. There are two forms:
  1. Standard: Use %INNERMACRO% to build the parameter string before %OUTERMACRO% is expanded
     %OUTERMACRO{
       format="%INNERMACRO%"
     }%
  2. Delayed: Use the parameter string to incorporate %INNERMACRO% into the output of %OUTERMACRO%
     %OUTERMACRO{
       format="$percentINNERMACRO$percent"
     }%
TIP When working with a given macro, consult its documentation to determine which parameters support the $percent/$percnt format tokens. Generally only output parameters like header, format and footer support format tokens.

Standard form

The key to understanding nested expressions in Foswiki is to understand that macros are expanded "inside-out, left-to-right". Example:

%MACRO1{
   something="%MACRO2{
      somethingelse="%MACRO3%, %MACRO4%"
   }%"
}%
The macros are expanded in this order: MACRO3, MACRO4, MACRO2, MACRO1.

Step-by-Step Example

Delayed form

Standard form macros can nearly always be used to build the parameter string of another macro; however, sometimes it is desirable to bypass the inside-out expansion order and delay the inner macro until after the outer macro has finished expansion. This is accomplished by using the $percent format token instead of %, and escaping any " character it uses (becomes \")

TIP When working with a given macro, consult its documentation to determine which parameters support the $percent/$percnt format tokens. Generally only output parameters like header, format and footer support format tokens.
Example:
%MACRO1{
   format="$percentMACRO2{
      format=\"%MACRO3%, %MACRO4%\"
   }$percent"
}%
The macros are expanded in this order: MACRO3, MACRO4, MACRO1, MACRO2.

Step-by-Step Example

From the conditional output example:

Worked example

Problem: search for some topics in an initial (outer) search, and for each of them apply a second (inner) search. The idea is to use the outer search to build a series of inner seraches.

Consider the following example. Let's search for all topics that contain the word "culture" (outer search), and find out where each topic found is linked from (inner search).

Initial (outer) search:
%SEARCH{
   "culture"
   nonoise="on"
   format="   * $topic is referenced by: (list all references)"
}%

Second (inner) search:

For each hit, we want this search:
%SEARCH{
   "(topic found in outer search)"
   nonoise="on"
   format="$topic"
   separator=", "
}%

Now let's nest the two.
Method 1 (nesting with escapes)
The inner search cannot be placed directly into the format string of the outer, because of the "inside-out, left-to-right" macro expansion behaviour discussed earlier. It must be delayed so that the outer search is evaluated first. To do this, we need to escape the inner search, i.e. let the outer search build a series of inner searches, which are executed only when the outer list is complete..
  • Use $percent to escape (delay) the inner search's SEARCH macro
  • Use \" to escape the double quotes
  • Use $dollar to escape the $ of $topic

%STARTSECTION{"example3"}%
%SEARCH{
   "culture"
   nonoise="on"
   limit="5"
   format="\
   * [[$topic]] is referenced by:
      * $percentSEARCH{
         \"$topic\"
         nonoise=\"on\"
         format=\"[[$dollartopic]]\"
         separator=\", \"
      }$percent"
}%
%ENDSECTION{"example3"}%

Click to execute

ALERT! When nesting with escapes, each new nesting level must "escape the escapes", e.g. write $dollarpercentSEARCH{ for level three, $dollardollarpercentSEARCH{ for level four, etc.

Method 2 (nesting with sectional includes)
Nested expressions with delayed macros can be difficult to write: care must be taken to escape all the quotes of the inner delayed macro, and it may become confusing whether to use $topic, $dollartopic or $dollardollartopic.

If you find yourself using escaped tokens like $dollartopic, another approach is to use the STARTSECTION/ENDSECTION feature of INCLUDE. Instead of nesting the inner search expression directly inside the format string of the outer, the inner search is written as a separate stand-alone section of a topic which is INCLUDEd into the format string of the outer.

%STARTSECTION{"example4"}%
%SEARCH{
   "culture"
   nonoise="on"
   limit="5"
   format="\
   * $topic is referenced by:
      * $percentINCLUDE{\"%TOPIC%\" section=\"mysearch\" thetopic=\"$topic\"}$percent"
}%

<verbatim class="foswikiHidden">
%STARTSECTION{"mysearch"}%%SEARCH{
   "%thetopic%"
   nonoise="on"
   format="$topic"
   separator=", "
}%%ENDSECTION{"mysearch"}%
</verbatim>
%ENDSECTION{"example4"}%

Click to execute

Most recently changed pages

%STARTSECTION{"example5"}%
%SEARCH{
   "1"
   type="query"
   nonoise="on"
   order="modified"
   reverse="on"
   limit="7"
   header="| *Topic* | *Changed* | *By* |"
   format="| [[$topic]] | $date  | $wikiusername |"
}%
%ENDSECTION{"example5"}%

Click to execute

Search with conditional output

Sometimes it may be desirable for each hit to be displayed differently depending on some criteria. For example, maybe you want to list 20 topics modified in 2009, but decorate the hits which are children of UserDocumentationCategory with an info icon.
  1. Specify a search which returns the hits you need
  2. For each search hit, test the condition that will influence the output using a nested IF statement

%STARTSECTION{"example6"}%
%SEARCH{
   "info.date >= d2n('2009-01-01') AND info.date <= d2n('2009-12-31')"
   type="query"
   limit="20"
   format="   * $percentICON{
      \"$percentIF{
         \"'$topic'/parent.name='UserDocumentationCategory'\"
         then=\"info\"
         else=\"gear\"
      }$percent\"
   }$percent [[$topic]]"
}%
%ENDSECTION{"example6"}%

Click to execute

info Details:
  • The SEARCH has a delayed ICON. The $percent ensures that ICON is evaluated once for each search hit
  • The ICON contains an IF, which again is delayed with the $percent token and will also be evaluated for each SEARCH hit. Additionally, the inside-out, left-to-right rule discussed earlier means that this IF expression will be evaluated before ICON.
  • If $topic is a child of UserDocumentationCategory, the info icon is used; otherwise, gear.

Embedding search forms to return a formatted result

Use an HTML form and an embedded formatted search on the same topic. You can link them together with an URLPARAM macro. Example:

%STARTSECTION{"example7"}%
<input type="text" id="search_field" size="32" />
%BUTTON{"Search" icon="find" id="search_button"}%

<verbatim class="jqLoader" data-section="example7_results" id="result_loader">
%STARTSECTION{"example7_results"}%
<div class="search_results">
%SEARCH{
   "%URLPARAM{"q" encode="entity, quote"}%"
   decode="entity"
   type="keyword"
   nosearch="on"
   format="<div class='search_hit'> [[$web.$topic]]
      <div class='search_summary'>$summary(searchcontext)<!-- --></div> 
      <div class='search_info'>$date, $wikiusername</div>
    </div>"
}%
</div>
%ENDSECTION{"example7_results"}%
</verbatim>

<literal>
<script>
jQuery(function($) {
  function doSearch() {
    $("#result_loader").trigger("refresh", {
      params: {
        q: $("#search_field").val()
      }
    });
    return false;
  };
  $("#search_button").on("click", doSearch);
  $("#search_field").on("keydown", function(ev) {
    if (ev.keyCode == 13) {
      doSearch();
    }
  });
});
</script>
<style>
.search_results em {
  color:red;
}
.search_hit {
  margin-bottom:1em;
}
.search_info a,
.search_info {
  color:#64B000;
}
</style>
</literal>
%ENDSECTION{"example7"}%

Search


<div class="search_results">
%SEARCH{
   "%URLPARAM{"q" encode="entity, quote"}%"
   decode="entity"
   type="keyword"
   nosearch="on"
   format="<div class='search_hit'> [[$web.$topic]]
      <div class='search_summary'>$summary(searchcontext)<!-- --></div> 
      <div class='search_info'>$date, $wikiusername</div>
    </div>"
}%
</div>


Related topics: UserDocumentationCategory, SearchHelp, Macros#VarSEARCH, SearchPatternCookbook, RegularExpression
Topic revision: r1 - 17 Jun 2022, ProjectContributor
This site is powered by FoswikiCopyright © by the contributing authors. All material on this site is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback