Class BSLTemplate

  • All Implemented Interfaces:
    java.io.Serializable, TemplateInterface

    public class BSLTemplate
    extends Template
    implements java.io.Serializable
    The BSLTemplate takes an HTML document with embedded "BSL" markup tags in it and evaluates those special tags to produce a standard HTML document.

    BSL stands for Brazil Scripting Language. BSL can be used to substitute data from the request properties into the resultant document. However, rather than simple property substitution as is provided by the SetTemplate, this class provides the ability to iterate over and choose amongst the values substituted with a set of simple flow-control constructs.

    BSL uses the following special tags as its language constructs:

    • <if>
    • <foreach>
    • <abort>
    • <break>
    • <continue>
    • <extract>

    This template recursively evalutes the bodies/clauses of the BSL commands, meaning that they may contain nested BSL and/or other tags defined by other templates.

    The following configuration parameter is used to initialize this template.

    debug
    If this configuration parameter is present, this template replaces the BSL tags with comments, so the user can keep track of where the dynamically generated content is coming from by examining the comments in the resultant HTML document. By default, the BSL tags are completely eliminated from the HTML document rather than changed into comments.

    <if> TAG

    The <if> tag evaluates one of its clauses dependant upon the value of the provided conditions. The other clauses are not evaluated and do not appear in the resultant HTML document. The general format of the <if> tag is as follows:
     <if [not] condition>
         clause
     <elseif [not] condition>
         clause
     <else>
         clause
     </if> 
    The <elseif> and <else> tags are optional, and multiple <elseif> tags may be present. <elseif> may also be spelled <elif> or <else if>. The optional parameter not reverses the sense of the specified condition.

    Following are the formats of the condition:

    <if name=var>
    Test if the value of property var is set and is not "", "false", "no", "off", or the number 0.

    <if name=var value=string>
    Test if the value of property var is equal to the given string.

    <if name=pattern any>
    Test if any property exists that matches matches the given glob pattern. Note: This may be expensive if there are large numbers of properties.

    <if name=var glob=pattern>
    Test if the value of property var matches the given glob pattern.

    <if name=var match=pattern>
    Test if the value of property var matches the given regular expression pattern.

    if the attribute nocase is present, then a case insensitive match is performed.

    <if expr=numeric expression>
    The numeric expression is evaluated. If the result is "1", then the condition is satisfied. This uses Calculator to evaluate the expression. Any vaiable that is defined, but not "0"m "off" or "no" is considered to have a value of "1" for the purposes of the expression evaluation. This allows (as an example) the expression "x && y && ! z" to evaluate to "true" only if the variables "x" and "y", but not "z" are defined *(and not "0", "no" or "false".
    Normally, the variable is look-up in the Properties Stack, starting with the Reqest Properties. The attribute "namespace" may be used to look-up the variable in the specified namespace.

    <foreach> TAG

    The <foreach> tag repeatedly evaluates its body a selected number of times. Each time the body is evaluated, the provided named property is set to the next word in the provided list of words. The body is terminated by the </foreach> tag. This tag is especially useful for dynamically producing lists and tables.
    •  <foreach name=var list="value1 value2 ..." [delim="chars"]>
           <get var>
           body
       </foreach>
      Iterate over the set of values "value1 value2 ...". The named property var is assigned each value in turn.

      If the optional parameter delim specifies, the delimiter for splitting the list into elements.

      • If delim is a single character, then that character is used as the delimiter.
      • If delim is not specified or is the empty string "", the delimiter is whitespace.
      • Otherwise, the delimeter is taken to be a regular expression. If the regular expression is invalid, the entire list is taken as a single element.
      • If the delimiter is a regular expression, and no sorting is requested (I was lazy), in addition to the property var, the properties var.delime, var.delim.1 ... are made available that represent the value of the previous delimiter and all of its sub-matches (if any).
      .

    •  <foreach name=var property=property [delim="chars"]>
           <get var>
           body
       </foreach> 
      Iterate over the values in the other property. The value of the other property is broken into elements and each element is assigned to the named property var in turn. This form is equivalent to <foreach name=var list=${property}>.

      If the optional parameter delim is specified, the characters are delimiters for splitting the list into elements using the StringTokenizer rules. If delim is not specified or is the empty string "", the delimiter is whitespace.

    •  <foreach name=var glob=pattern>
           <get var.name>
           <get var.value>
      
           <get var.name.1>
           <get var.name.2>
           body
       </foreach> 
      Iterate over all the properties whose name matches the glob pattern. In turn, the following properties are set:
      var.name is the name of the property.
      var.value is the value of the property.
      var.name.1, var.name.2, ... are the substrings matching the wildcard characters in the pattern, if any.

    •  <foreach name=var match=pattern>
           <get var.name>
           <get var.value>
      
           <get var.name.0>
           <get var.name.1>
           <get var.name.2>
           body
       </foreach> 
      Iterate over all the properties whose name matches the regular expression pattern. In turn, the following properties are set:
      var.name is the name of the property.
      var.value is the value of the property.
      var.name.0 is the substring that matched the whole pattern.
      var.name.1, var.name.2, ... are the substrings matching the parenthesized subexpressions, if any.

      NOTE: In the current implementation, when there are large numbers of property values, using glob is (potentially) much more efficient than match for locating names.

    All the temporary properties that this tag creates are visible only within the body for the duration of the <foreach>.

    if the attribute nocase is present, then a case insensitive match is performed.

    When either glob or match is specifies, then the "namespace" attribute may be used to restrict the name lookups to start with that namespace. However, the values aren't restricted to being in the specified namespace. [Not clear if this is useful for anything]

    Sorting using foreach

    The <foreach> tag contains a feature to change the order of iteration. This facility is intended for common sorting operations. For general purpose manipulation of the iteration order, the order should be defined either in another handler, or by using the <server> directive.

    The four additional parameters used to control sorting are:

    reverse
    The list of items is iterated in the reverse order.

    sort[=key]
    The items to be iterated over are sorted. If no key is supplied, the items are sorted by the property name. If a key is supplied, its value is used as the sort key for the iteration. For this to be meaningful, the key should contain variable substitutions (e.g. ${...}, see getProperty). A sample use of the sort key would be:
     <foreach name=id property=employee.ids sort="${employee.${id}.last}, ${employee.${id}.first}">
    This option can be tricky to use correctly. The following example will not sort employees by last name:
     1. <foreach name=id property=employee.ids sort="employee.${id}.last">
    Why? Because another level of ${...} needs to be inserted in the sort key:
     2. <foreach name=id property=employee.ids sort="${employee.${id}.last}">
    Example (1) will just sort the literal strings "employee.1234.last", "employee.5678.last", etc. while example (2) will do the correct thing and sort the values "Stevens" and "Johnson". Remember that BSL sorts based on exactly what you pass it and does not know that the provided string should be treated as another variable itself.

    numeric
    When used in conjunction with the sort parameter, it causes the items to be interpreted as numbers (or zero if the item doesn't look like a number).

    nocase
    When used in conjunction with the sort parameter, it causes the items to be sorted in a case-insensitive fashion.

    Note that when used with "glob=..." or "match=...", it does NOT cause the glob or regular expression to be case insensitive. It causes the results of the glob or regexp to be sorted in a case-insensitive fashion. There is currently no way to specify a case-insensitive glob or regular expression.


    <abort> TAG

    The <abort> tag terminates processing of the current HTML page at the point it is evaluated. All HTML on the page after the <abort> tag is discarded, and the HTML processed up to that point is returned. This tag can be placed anywhere on a page, including within a <foreach> or <if> construct.

    The following is an example usage of this tag:

     <foreach name=x list="0 1 2 3">
       <if name=x value=3>
         <abort>
       </if>
       <get name=x>
     </foreach> 
     Testing
     
    This example produces the output:

     0 1 2
     

    <break> TAG

    The <break> tag terminates processing within a <foreach> construct. The processing of HTML continues immediately after the </foreach>. This tag can only be used inside of a <foreach> tag.

    The following is an example usage of this tag:

     <foreach name=x list="0 1 2 3">
       <if name=x value=3>
         <break>
       </if>
       <get name=x>
     </foreach> 
     Testing
     
    This example produces the output:

     0 1 2 Testing
     

    <continue> TAG

    The <continue> tag continues processing at the top of a <foreach> construct. This skips any HTML after the <continue> tag and before the </foreach>. This tag can only be used inside of a <foreach> tag.

    The following is an example usage of this tag:

     <foreach name=x list="0 1 2 3">
       <if name=x value=2>
         <continue>
       </if>
       <get name=x>
     </foreach> 
     Testing
     
    This example produces the output:

     0 1 3 Testing
     

    <extract> TAG

    The <extract> tag permits portions of a property's value to be extracted into additional properties, based on either glob or regular expression patterns. The extract tag takes the following tag parameters:
    name=var
    The name of the property whose value will be split up and extracted.

    prepend=base
    Optional parameter that specifies the base string to prepend to the extracted properties. The default value for base is the specified property name var.

    glob=pattern
    The glob pattern to match against. In turn, the following properties are set:
    base.1, base.2, ... are the substrings that matched the wildcard characters in the pattern.

    match=pattern
    The regular expression pattern to match against. In turn, the following properties are set:
    base.0 is the substring that matched the whole pattern.
    base.1, base.2, ... are the substrings that matched the parenthesized subexpressions in pattern, if any.

    If the attribute all is present, then all matches and submatches are extracted into properties. The properties base.0, base.1, etc., are set to the 1st matched expression, the 2nd matched expression, etc. The properties base.0.0, base.0.1... are set to the sub-matches of the first full match, and so forth. If any matches are found the following additional properties are set:

    basematches
    The number of times the regular expression was matched.
    basesubmatches.
    The number of sub-expressions for this regular expression.
    basematchelist.
    The list of matches (e.g. "1 2 3 ...").
    replace=substitution
    If specified (with match), then no portions of the value are extracted. Instead, a regular expression substitution is performed (see substitution). The resultant substituted value is placed in the property: prefix.replace.
    map
    A white space separated list of names that will be used to name sub-matches, instead of .1, .2, ... etc. See tag_extract(sunlabs.brazil.template.RewriteContext) for more detail.
    One of glob or match must be specified.

    In addition, the property base.matches is set to a value indicating the number of matches and submatches stored. This property can be examined and compared with 0 to determine if the <extract> tag matched at all. If there was no match, the numbered properties base.N are not set or changed from their previous value.


    Anytime an argument is specified to one of the BSL tags, variable substitution as described in getProperty may be used.

    Any time a boolean parameter (XXX) is allowed (nocase, not, numeric, or reverse) it is considered false if it takes any of the forms: XXX=0, XXX=no, XXX=false XXX="". If it takes the forms XXX or XXX="anything else", the value is true.

    see a sample HTML page that contains some BSL markup.

    See Also:
    SetTemplate, Serialized Form
    • Constructor Detail

      • BSLTemplate

        public BSLTemplate()
    • Method Detail

      • tag_abort

        public void tag_abort​(RewriteContext hr)
        Handles the "abort" tag.
      • tag_break

        public void tag_break​(RewriteContext hr)
        Handles the "break" tag.
      • tag_continue

        public void tag_continue​(RewriteContext hr)
        Handles the "continue" tag.
      • tag_foreach

        public void tag_foreach​(RewriteContext hr)
        Handles the "foreach" tag.
      • tag_if

        public void tag_if​(RewriteContext hr)
        Handles the "if" tag.
      • tag_extract

        public void tag_extract​(RewriteContext hr)
        Handle the [experimental] "extract" tag. This permits parts of a property's value to be extracted into additional properties, based on either glob or regular expression patterns.
        <extract name= prepend= glob= match=>
        name
        The name of the property to extract
        prepend
        The base name for all extracted properties (defaults to "name"). If it doesn't end with a ".", one is added.
        glob
        The glob pattern to use for extraction. The text matching each wildcard in the pattern is extracted.
        match
        The regular expression pattern to use for extraction. The text matching each sub-expression is extracted. If "glob" is specified, then "match" is ignored.
        null
        the value to return if there was no match [or sub-match] (defaults to "").
        map
        a white space separated list of names that will be used to name sub-matches, instead of .1, .2, ... etc. If there are more sub expressions than names, then the indeces are used after the names run out. The example:
                        <set name=entry value="joe:211A:x3321">
                        <extract name=entry glob=*:*:* map="name room phone">
                        
        Will return the values:
                  entry.name=joe
                  entry.room=211A
                  entry.phone=x3321
                  
        In "glob" extraction, each wildcard in the glob pattern is assigned the next token in "map". in Regular expression extractions, when "all" is specified, the map names are used to name the sub-expressions. Without "all" the names are assigned like "glob", only the first name gets the entire match (e.g. you need one more name for "match" than for "glob". namespace
        Normally, results are extracted into the current request namespace. If namespace is specified, then the results are placed into the named namespace. The names "server" and "local" are special (see SetTemplate).

        NOTE: The namespace will be accessable by any other templates associated with the same TemplateRunner, using the default sessionTable (see SetTemplate).