Fork me on GitHub

Syntax

I think a syntax should be very simple and, fit to the people who deal with as well as the output generated. In addition, the output data may even consist of different formats. Therefore I designed Snippetory independent from its syntax. So it's easy to switch the syntax, even dynamically within the file.

Intact templates

As Snippetory is a small project it can't generate perfect tool support for every supported output language. In turn I decided to go another way: Make the syntax so simple it's possible to create several of them, and keep all of them in mind. For instance the tags of FLUYT_X work great within the html part of a file, while causing errors in the javaScript part. As javaScript requires me to think in a completely different way it is no additional problem to switch over to FLUYT_CC that allows me to coat my Snippetory expressions in comments, giving them a highlighting color, as well as avoiding syntactical errors created by them.

How to implement a syntax

Additional syntaxes can be created by implementing the interface org.jproggy.snippetory.spi.Syntax. A good starting point to do so is RegExSyntax. It just needs a bunch of regular expressions to work and provides some snippets to create syntaxes consistent with the core syntaxes. Once your syntax is ready the interface provides a registry to register it. The harder part is to document the syntax.;->

Anatomy

As the syntax can be replaced easily, it's not that simple to describe. However there is a number of elements each concrete syntax may provide and some rules a syntax can't control. The main elements are

Names
Names should be valid java field names with one addition: '-'. The minus sign is allowed to support typical XML naming schemes. Like in java names are case-sensitive.
Location mark
A location mark is simply a point, where data can be bound to. It can be annotated, how this binding should happen, by meta data. The same data may be bound to different locations with different meta data each. I.e. there may be several locations with same name in one region. All locations are accessed with a single set or append method call. But the results may be different depending on the meta data.
Region
Syntactically a region consists of a start and an end. The content between start and end can be used as an independent template. As a region can be retrieved, its name has to be unique for the regions within the parent region.
Each region serves as location mark, as well. Therefore it can be configured by meta data.
Meta Data
Allows fine grained control over the Snippetory abstraction layer by several attributes.
Syntax selector
The syntax selector allows to switch the syntax at any point of parsing. To be able to use templates like output files in order to validate them, it's mandatory to use a syntax the fits its environment.
Template Data
The portion of the template file, that is not considered to be mark up and therefore is copied verbatim to the output, if used. Of course, there might be some regions, that are not always used.
Comment
The comment is an optional element and not yet supported by all of the core syntaxes.

Syntactical Elements

Names

Snippetory supports the full Java naming scheme with, in addition, allowing the minus sign '-' at any position of the name, to support typical XML naming strategies. The characters sharp '#' and period '.' will work but are reserved for future use. While the standard syntaxes enforce this naming scheme, there's no check in Snippetory whether other syntaxes enforce this too, or allow other names. But this might change in the future.

Names are always case-sensitive.

Location mark

A location mark has a name and may be configured by meta data. However there's a special variant without a name and at least one attribute. This is useful with so-called void formats, as such a location mark can't be accessed from java, so no data can be bound.
For more information on formatting see
the formats documentation and Formats in java doc

$value
$value(msg="cart_no_data")
$(msg="cart_no_data")

Region

Like a location mark it can be replaced entirely by actual data. Even though this string typically consists of one or more parameterized copies of itself, this might be any data appropriate. However replaced isn't that correct, as of it's not replaced it's not rendered anyway. In fact an inner template is absolutely independent of it's parent. It's just stored there for better understanding of the context and simpler access. But technically it could be taken from anywhere and used everywhere one likes.

A region is marked by a start and an end element. In some syntaxes the name of region can be repeated in the end element. If it repeated it will be checked. That's recommended for longer regions, because it makes it easier to get what ends there. The start element may be configured by meta data. (In fact the syntax defines where meta data can be placed...)

A region can contain any number of complete regions with distinct names. I.e. there mustn't be more than one region with the same name directly embedded into one region, but any of these child regions provides its own, distinct name space.

A region may contain any number of location marks, without any limitations to naming. I.e. a single write operation can target several location marks and one region. These location marks are all direct children of one region. Location marks within child regions are out of scope anyway.

The start and end elements are provided in two variants each.

  • In the inline variant only the element itself is considered to be part of the markup and is therefore omitted from output. All white-space before and after is normal part of the template.
  • If the element is found in its 'own' line with only white space and a single region start or end element the entire line including the line break is considered to be markup, and therefore not part of the template. Let's call this the block variant.

The gray part is to be removed. $inline-region{ Containing some text }$$block-region{ Also with text contained }block-region$

Conditional regions

Starting with Snippetory 0.9.5 there is an addition type of region: Conditional regions have no name, and so they can't be controlled by java logic. Instead their contained locations control them. This makes it easy to implement cases where the absence of data removes some infrastructre as well.

Optional attribute:

${title="$title"}$

If there are no rows the entire table will be omitted.

<t:>
<table>
  <tr>
    <th>Heading1</th><th>Heading2</th>
  </tr>
  <t:row>
  <tr>
    <td>$data1</td><td>$data2</td>
  </tr>
  </t:row>
</table>
</t:>

Meta Data

For the core syntaxes the syntax of attributes is similar to XML (Other definitions may overwrite this, of course):

<name>=<quoted_value>

Where name consists on alphanumeric chars plus '.-_'. The quoted_value may be quoted either in single or double quotes. Again similar to XML. However, in contrast to XML the escaping of special characters works, similar to Strings in many programming languages, with the backslash character:

\\
backslash
\'
single quote (In double quoted values the backslash is optional)
\"
double quote (In single quoted values the backslash is optional)
\n
new line
\r
carriage return
\b
bell
\t
tabulator
\f
form feed

A single backslash might cause the piece of markup being considered to be template code.

Meta data consists of a bunch of attributes. Some of these attributes are implemented directly:

enc
Valid values are the name of all registered encodings. The encodings shipped with Snippetory are documented in org.jproggy.snippetory.Encodings.
default
Declares how a value is rendered if no value is set. The value will not be escaped but it's formatted by string formatters. Without additional definition a location mark will be rendered as its markup while a region will be rendered by an empty string.
delimiter
Is rendered only in case the values gets appended data more than once between the final content created by two subsequent calls to the append method. I.e. it's prepended any but the first call to the append method. The value will be neither formatted nor escaped. Note: Calls to some render-methods will cause calls to the append method, too.
prefix
is only prepended if the region or location mark got data by appending or setting.
However, the prefix attribute will prevent the rendering of markup if no value is bound on a location mark. Deprecated: Consider use of conditional regions instead
suffix
same as prefix but behind. Deprecated: Consider use of conditional regions instead
backward
This is a very advanced technique that allows 'touch-less' value binding. In some case it's very useful to keep the template syntactically intact. However, this makes it impossible to bind data to some places, where the syntax of the output format is too strict. In those cases it's possible to place the insert location behind the real target.

 var language = 'de' // $language(backward='(de)')

Other attributes are created by registration of a Format. There's an example how to do that.

And there come some predefined formats with Snippetory to convert

Syntax selector

The syntax selector allows to change the syntax on the fly. It can be placed inside a region. This might lead to regions with start and end element defined in different syntaxes. The only data of a syntax selector is the selected syntax. I.e. no name, hence a syntax selector can't be accessed from java.

The syntax selector is expressed as empty tag in name-space s with no attributes. The tag name is the name of the syntax. Typically the entire line is considered to be markup.

<!-- Syntax:XML_ALIKE --> <s:FLUYT_X />

Syntax Variants

The syntaxes shipped with Snippetory are documented in org.jproggy.snippetory.Syntaxes.

FLUYT

FLUYT is the main syntax of Snippetory and the root of an entire syntax family. It's designed to be concise and unified. Following this concept locations and regions are integrated into one syntactical concept where about every part is optional. In fact this perfectly shows that regions are location with an additional template part. There are 3 segments. Each segment is optional, but there has to be at least one. The segments are:

  • Name
  • Attribute brackets (i.e. Meta data surrounded by round brackets)
  • The template region (Surrounded by curly brackets and finalized by a dollar sign. Repeating the name is optional even if there is one)

$[<name>][([<atribute>='value'...])][{<content_area>}[<name>]$]

In addition there is a 3-slash comment and the normal syntax selector.

Example:

$item(delimiter=","){
  {
    id: $id
/// Empty attribute brackets can be used to clarify the end the expressing
    image: 'details_$id()_small.jpg'
    name: '$name(enc="string")'
    values: [$values(delimiter=","){$value}$]
  }
}item$

Usage

The vanilla FLUYT syntax is most likely to be used in add hoc formatting, or when generating natural text, like a plain text e-mail, as there is not integration needed.

FLUYT_X

FLUYT_X adds an alternative region mark-up to the FLUYT syntax scheme, looking like XML tags in name space 't'. Those tags are very convenient for XML or HTML integration. Many editors support one by closing the tags consistently and by this it's easy to build valid output. Typical tools recognize them as part of the document structure and display them nicely.

Example:

<t:cart>
<table>
  <tr><th colspan="2">Product</th><th>Quantity</th><th>Price</th></tr>
    <t:entry>
    <tr>
      <td><img src="imgs/icon_$imgId().jpg" ${title="$desc"}$ /></td>
      <td>$prodName</td><td>$quantity</td><td>$price(number="currency")</td>
    </tr>
    <t:><tr><td colspan="4">$longDescription</td></tr></t:>
    </t:entry>
</table>
</t:cart>

Usage

FLUYT_X is designed for integration with HTML and XML. But FLUYT_X is no XML. Empty tags with the slash at the end aren't supported and there is no entity support. The escaping within attribute values works like described above.

FLUYT_CC

FLUYT_CC allows the FLUYT syntax to be coated with comments. Those comments will be considered to be part of the respective expression and removed together with the expression itself. To achieve this each token can be prefixed with either '//' or '/*' and can be suffixed with '*/'. In addition there is an optional mock part before the closing attribute bracket. This is a portion of free text prefixed with '*/' and suffixed with '/*'. If used within an comment region this will make the free text visible for a tool handling it:

/* $name(default="" */<mock>/*)*/

Example:

package /*$package(*/org.jproggy.examples/*)*/;

// $imports{
/// comment lines will not appear in the output....
import /*$type(*/org.jproggy.snippetory.Template/*)*/;
// }$

public class /*$name(*/TemplateName/*)*//*${ implements $interfaces(delimiter=", ")}$*/ {
/*$body*/
}

Usage

FLUYT_CC integrates nicely with languages like java, javaScript, C, C++, or CSS.

xml_alike

The regions of this syntax look almost like XML within the name space t. If the name-space identifier 't' is already used for some reason, it's easy to create a similar syntax better supporting your needs. However there are some differences to XML. The empty tag variant with the slash at the end is not allowed. And there's no entity support. But the rules for attribute definition are similar. However, the values are defined the programming way with backslashes as described above.

Location marks are limited by curly braces. The content start with v: immediately followed by the name.

Example:

<t:region-one>inline variant</t:region-one>
{v:value default="xyz"}
<t:region-two>
produces only a single line of output, whenever rendered.
</t:region-two>

Usage

XML_ALIKE provides a rather robust syntax scheme so it might be used where conflicts with the template code are likely.

hidden_blocks

This syntax is quite similar to xml_alike. Just the start and end sequences of the region elements are modified to let it look like comments in a number of environments.

start element

Start sequence may be either


/*t:

or


<!--t:

and the end sequence may be


*/

or


-->

End element

While end sequences stay identical start sequences are


/*!t:

or


<!--!t:

In either case it is allowed to mix the variants as needed.

<!--s:hidden_blocks-->
<script>
/*t:region-one-->code might be hidden from javaScript<t:!--!t:region-one*/
/*t:region-two*/or visible, just as needed /*!t:region-two*/
</script>
<!--t:region-three*/same works in HTML, too, of course/*!t:region-three-->
<!--t:region-four-->
The markup lines work here, too.
<!--!t:region-four-->

c_comments

Deprecated: Has been effectively replaced by FLUYT_CC.

Bernd Ebertz

Head, Founder and chief technology evangelist of
jproggy.org
Java, and all Java-based marks are trademarks or registered trademarks of Oracle.
This site is not affiliated in any way with Oracle.