X2TL is a language that applies custom built templating to an XML document. The templates are purely string based, and therefore can be any format, from straight text to XML to JSON. They utilize the double-brace aka {{ mustaches }} to embed commands, which are applied against the source XML document or the current context node within that XML.
Command Fragments are determined by finding blocks wrappered in a start and end delimiter, {{ and }} respectively, referred to in the templating community as Mustaches. Within the {{ mustaches }} are commands that are evaluated and processed against the context node. Anything outside of the {{ mustaches }} is considered a Text Fragment and is copied as-is.
Following is a simple example, using a snippet of HTML
This Template:
<span>{{ = row/@lastName}}, {{ = row/@firstName }} ({{ = row/@userName }})</span>
Given the following XML Document:
<User>
<row lastName="Fine" firstName="Howard" userName="HFINE"/>
</User>
Results in the following output:
<span>Fine, Howard (HFINE)</span>
By combining and embedding commands, and even libraries of supporting templates, this becomes a very powerful tool for generating XML sourced output.
X2TL – X2A2 Templating Language – HTML Templating Language and Engine (Reflection Class) – RelWare Wiki
Escaped Delimiters
There may come a time that you actually wish to include the delimiters {{ or }} within your template and NOT have them process as a command. This is referred to as escaping the delimiters. The X2TL handles this as many languages do, by allowing the author of the template to ‘double-delimit’. This concept should be familiar to anyone that has needed to double-quote a double-quote in other languages. In X2TL, you only need to double-up the start delimiter {{. The end delimiter }} can remain intact and will be ignored.
Escaped Delimiters Example
<template>
<span>This example has {{{{ mustaches }} in it.</span>
<span>This one has lots of {{{{{{{{ mustaches }}}} in it.</span>
</template>
Result
<span>This example has {{ mustaches }} in it.</span>
<span>This one has lots of {{{{ mustaches }}}} in it.</span>
X2TL Commands
The X2TL has a limited command set, however, its flexibility allow for countless variations. The X2TL currently supports the following commands, with the syntax for each command being described in detail below.
Please also note that some commands provide for one or more “shorthand” alternatives. These are shown in parenthesis following the command itself (i.e. Result (=)). Shorthand versions of commands are treated identical to the engine, and it does not distinguish between either writing of the command. It should be noted that X2TL command words themselves are NOT case-sensitive, however, of course, their XPath parameters are. With that, the following are multiple ways of writing the same command, each of which will provide identical output.
{{ RESULT node/@attrib }}
{{ Result node/@attrib }}
{{ rESULT node/@attrib }}
{{ result node/@attrib }}
{{ = node/@attrib }}
Command Delimiters
A command itself may be broken down into parameters, the first of which is always the command name. Some commands do not require any parameters, and some can take any number of parameters. To properly determine the parameters within the command fragment, X2TL understands the following command delimiters: double- quotes ( ” ), parenthesis ( ( and ) ), and whitespace ( space, newline, tab ). Any text contained within a quoted- string, or within an outer set of parenthesis, is considered its own parameter. Any other text is broken down via whitespace. This will become more clear in the following examples.
X2TL Command Set
Value-Replacement Commands
Result ( = )
The Result command, which has a shorthand equivalent of =, is the most commonly used command, as value-replacement is primarily the point of a templating language. It expects a single parameter being an XPath within the current node context to locate the value that you wish resulted. It should be noted that the resulting value of the XML node will be XML-escaped before it is added to the resulting string. (see RawResult below for more information)
NOTE: This is “value-replacement” only. For full “node-replacement”, please refer to the Copy (*) command.
Example Source XML:
<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<CheckIn status="CHECKED-IN" availability="Busy" lastUpdate="08/31/2010 16:18"/>
</User>
Template:
<div id="User_{{ = @userNo }}">
<span>{{ result @lastName }}, {{ result @firstName }} ({{ = @userName }})</span>
<span>User is {{ = CheckIn/@status }} - ( {{ = /User/CheckIn/@availability }} ) as of {{ Result "*/@lastUpdate" }}</span>
</div>
Resulting Output:
<div id="User_1001">
<span>Fine, Howard (hfine)</span>
<span>User is CHECKED-IN - ( Busy ) as of 08/31/2010 16:18</span>
</div>
The above template was written in several different ways in order to illustrate the flexibility of the language. With the understanding of XPath and its commands, we can simplify and empower some of the above as follows, which will generate the same result.
Template:
<div id="User_{{ = @userNo }}">
<span>{{ = ( concat(@lastName, ‘, ‘, @firstName, ‘ (‘, @userName, ‘)’ ) ) }}</span>
<span>User is {{ = “concat( CheckIn/@status, ‘ - ( ‘= CheckIn/@availability, ‘ ) as of ‘, CheckIn/@lastUpdate )” }}</span>
</div>
RawResult (==, raw)
The RawResult command, which has two shorthand equivalents of == and raw, will be lesser used than its counterpart Result, as RawResult provides back its resulting data as-is in string form, without any XML escaping performed. To better illustrate the use of this command, it will be compared to the Result command in the example below.
Example Source XML:
<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<Pref favURL="
http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f&aqi=g1gUs1/>
</User>
Template:
<div>
<span>User's favorite URL is: {{ Result Pref/@favURL }}</span>
<span>This is Invalid XML: {{ RawResult Pref/@favURL }}</span>
<span>User's favorite URL is: {{ = Pref/@favURL }}</span>
<span>This is Invalid XML: {{ == Pref/@favURL }}</span>
</div>
Resulting Output:
<div>
<span>User's favorite URL is:
http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f&am</span>
<span>This is Invalid XML: http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f&am</span>
<span>User's favorite URL is: http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f&am</span>
<span>This is Invalid XML: http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f&am</span>
</div>
Format (?)
The Format command, which has a shorthand equivalent of ?, is similar to the Result command, except that it is used to specifically change the output format of a given value, or in the case of a String format, multiple variables. The Format command expects (3) parameters: datatype (date, number, string), format (see .Net Framework Format Strings), and value (XPath reference to node value).
Unlike other commands, Format also has three ‘shortcuts’, being that you can omit the Format (or ?) portion of the command, and simply use the commands: Date, Number or String, each of which are described in more detail below. Other than the obvious lack of initial parameter, they operate identically.
Example Source XML:
<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<CheckIn status="CHECKED-IN" availability="Busy" lastUpdate="08/31/2010 16:18" phoneNum="123456789012345"/>
</User>
Template:
<span>User is {{ = CheckIn
/@status }} as of {{ Format Date MM/dd/yyyy CheckIn
/@lastUpdate }}
and can be reached at {{ ? Number "#(###)###-#### x.####" CheckIn/
@phoneNum }}</span>
Resulting Output:
<span>User is CHECKED-IN as of 08/31/2010
and can be reached at 1(234)567-8901 x.2345</span>
Format Date (Date)
The Date command is a shortcut to the fully qualified Format Date command. It expects to receive a valid date format string, and an XPath value that points to a date value. There is no error handling for this, nor “invalid date message”. Please use with care.
Note: While the command name only specifies Date, it is truly a DateTime format, and supports any .Net supported date/time string.
(see Supported Date Format Strings and Custom Date Format Strings)
Example Source XML:
<SystemTime utc="8/26/2010 5:44:47 PM" local24="8/26/2010 13:44:47" />
Template:
<span>UTC: {{ Format Date MM/dd/yyyy @utc }} - Local: {{ ? Date MM/dd/yyyy @local24 }} - English: {{ Date @local24 "MMMM dd, yyyy at h:mm:ss tt" }}</span>
Resulting Output:
<span>UTC: 08/26/2010 - Local: 08/26/2010 - English: August 26, 2010 at 1:44:47 PM</span>
Format Number (Number)
The Number command is a shortcut to the fully qualified Format Number command. It expects to receive a valid number formatted string, and an XPath value that points to a numeric value (either Int64 or Double). There is no error handling for this, nor “invalid numeric message”. Please use with care.
(see .Net Standard Number Format strings and Custom Numerical Format Strings)
Example Source XML:
<data n0="0" n1="123" n2="1234567890" n3="-765.4321" n4="12345678901.2345"/>
Template:
<div>
<span>Original: {{ = data/@n1 }} Zero-padded: {{ format Number 000000 data/@n1 }}</span>
<span>Comma-Separated: {{ ? Number "#,#" data/@n2 }}</span>
<span>Negative currency: {{ Number "$#,#.##" data/@n3 }}</span>
<span>Telephone Ext: {{ Number "#(###)###-#### x.####" data/@n4 }}</span>
<span>Pos: {{ number "##.#;(##.#);**Zero**" data/@n1 }} Neg: {{ number "##.#;(##.#);**Zero**" data/@n3 }}</span>
<span>Dec: {{ = data/@n1 }} Hex: {{ ? number X data/@n1 }}</span>
</div>
Resulting Output:
<div>
<span>Original: 123 Zero-padded: 000123</span>
<span>Comma-Separated: 1,234,567,890</span>
<span>Negative currency: -$765.43</span>
<span>Telephone Ext: 1(234)567-8901 x.2345</span>
<span>Pos: 123 Neg: (765.4) Zero: **Zero**</span>
<span>Dec: 123 Hex: 7B</span>
</div>
Format String (String)
The String command is a shortcut to the fully qualified Format String command. It expects to receive a format string, and unlike the other commands, any number of XPath values, each pointing to their own string value nodes. This command uses the .Net String.Format() method for its internal resulting. There is no error handling for invalid format strings. Please use with care.
Example Source XML:
<User username="HFINE" first="Howard" last="Fine" />
Template:
<span>{{ Format String "{0}, {1} ({2})" @last @first @username }}</span>
Resulting Output:
<span>Fine, Howard (HFINE)</span>