X2TL Templating Language

X2TL

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.

Delimeters and Fragments

A template is comprised of Command Fragments and Text Fragments. Command Fragments are determined by finding blocks of text 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.

Given the following XML Document

<User>
<row lastName="Fine" firstName="Howard" userName="HFINE" />
</User>

This Template

<span>
{{ = row/@lastName}}, {{ = row/@firstName }} ({{ = row/@userName }})
</span>

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.

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 considered part of the surrounding Text Fragment.

Template

<span>
This example has {{{{ mustaches }} in it.
</span>
<span>
This one has lots of {{{{{{{{ mustaches }}}} in it.
</span>

Resulting Output

<span>
This example has {{ mustaches }} in it.
</span>
<span>
This one has lots of {{{{ mustaches }}}} in it.
</span>

Command Fragments

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.

Template Variations

{{ 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, carriage return, line feed, 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 for more information)

See Also: Format String (String)

NOTE: This is “value-replacement” only. For full “node-replacement”, please refer to the Copy (*) command.


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 (Alternative)

<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.

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" />
</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&amp;source=hp&amp;q=RelWare&amp;aq=f
</span>
<span>
This is Invalid XML: http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f
</span>
<span>
User's favorite URL is: http://www.google.com/#hl=en&amp;source=hp&amp;q=RelWare&amp;aq=f
</span>
<span>
This is Invalid XML: http://www.google.com/#hl=en&source=hp&q=RelWare&aq=f
</span>
</div>

Replace (~)

The Replace command, which has a shorthand of ~ is used to perform a regular-expression based string replacement on either an Xpath or variable value. This command takes (3) parameters: regExp, replaceText, input. The first two of these are as defined by Microsoft .Net framework relating to the RegEx Replace method. (see also .NET Framework Regular Expressions)


Source XML

<node>
<data d1="08/26/2010" />
</node>

Template

<div>
<span>
Original: {{ = data/@d1 }} Updated: {{ ~ "\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b" "${day}-${month}-${year}" data/@d1 }}
</span>
</div>

Resulting Output

<span>
Original: 08/26/2010 Updated: 26-08-2010
</span>

FromURL

There are many times that we need to obtain data from a URL, whose encoding can be awkard to deal with as a simple string. The FromURL command fixes issues, such as %20 being used for a space.


Source XML

<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<Pref favURL="http://example.org/data?this%20value%20has%20encoded%20data%22%23%24" />
</User>

Template

<div>
<span>
Original: {{ = Pref/@favURL }}
</span>
<span>
FromURL: {{ FromURL Pref/@favURL }}
</span>
</div>

Resulting Output

<div>
<span>
Original: http://example.org/data?this%20value%20has%20encoded%20data%22%23%24
</span>
<span>
FromURL: http://example.org/data?this value has encoded data"#$
</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.

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 also: DateAdd)

(see Standard Date Format Strings and Custom Date Format Strings)


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 numeric format string, and an XPath value that points to a numeric value. There is no error handling for this, nor “invalid number message”. Please use with care.

(see Standard Numeric Format Strings and Custom Numeric Strings)


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.

(see .Net Custom String Formatting)


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>

DateAdd

Simple parsing of date strings is quite simple, especially if you combine a MultiVar with a Format Date as its child. However, doing any math with that becomes a far more difficult task. The DateAdd command allows you to take advantage of the undelying .Net DateAdd function to generate ranges, cut-offs, etc. DateAdd takes 3 parameters, and optionally a 4th. The first is the XPath to the date value. As noted with Format Date please take care with the date contexts. The second and third parameters are the Date Interval and the positive or negative number to be added (or subtracted). (See .Net DateAdd Date Intervals) The fourth parameter, which is optional, is the output format. (See also Format Date as well as .Net Standard Date/Time Format strings and .Net Custom Date/Time Format strings)


Source XML

<SystemTime utc="8/26/2010 2:30:51 PM" local24="08/26/2010 10:30:51" />

Template

<div>
<span>
Original: {{ = SystemTime/@utc }}
</span>
<span>
+60 Days: {{ dateadd SystemTime/@utc D 60 }} ({{ dateadd SystemTime/@utc D 60 (h:mm:ss tt) }})
</span>
<span>
+60 Hours: {{ DateAdd SystemTime/@utc h 60 }}
</span>
</div>

Resulting Output

<div>
<span>
Original: 8/26/2010 2:30:51 PM
</span>
<span>
+60 Days: 10/25/2010 14:30:51 (2:30:51 PM)
</span>
<span>
+60 Hours: 08/29/2010 02:30:51
</span>
</div>

The following shows how involving variables and the optional output formatting can perform complex tasks.


Complex Template

<div>
<span>
Original: {{ = SystemTime/@utc }}
</span>
{{ mvar TwoMonths }}{{ dateadd SystemTime/@utc M 2 (MM\/dd\/yyyy h:mm:ss tt) }}{{ /mvar}}
<span>
End of Next Month: {{ dateadd $TwoMonths D -1 (MM\/dd\/yyyy h:mm:ss tt) }}
</span>
</div>

Resulting Output

<div>
<span>
Original: 1/01/2016 12:34:56 PM
</span>
<span>
End of Next Month: 02/29/2016 12:34:56 PM
</span>
</div>

MD5

The MD5 command is used to generate an MD5 Hash value of a given string or XML node. This can be used for ensuring data integrity and more. The only parameter is the XPath of the data to be hashed.


Source XML

<html>
<div unquoted=1 specials="<>&amp;&quot;"><br></br><BR><textarea>&lt;&gt;&amp;&quot;</textarea><HR empty ><hr />&lt;&gt;&amp;&quot;</div>
</html>

Template

<div>
{{md5 /html }}
</div>

Resulting Output

<div>
f2e35c11b7bbee227c6201a534c02010
</div>

SHA1

The SHA1 command is nearly identical to the MD5 command, except that it generates an SHA-1 hash instead of MD5. The only parameter is the XPath of the data to be hashed.


Source XML

<html>
<div unquoted=1 specials="<>&amp;&quot;"><br></br><BR><textarea>&lt;&gt;&amp;&quot;</textarea><HR empty ><hr />&lt;&gt;&amp;&quot;</div>
</html>

Template

<div>
{{sha1 /html }}
</div>

Resulting Output

<div>
31d69b566323ed39bc018799b6616ad7b2c51458
</div>

Node-Replacement Commands

Copy (*)

The Copy command, which has a shorthand equivalent of *, is used to bring a copy of the actual XML of a selected node into the result. Unlike the above Value-Replacement commands, which work only on the requested node’s inner text / value, this actually brings forward full “outer-XML” of a requested node. With that, no additional formatting options apply.

NOTE: This is a full “XML node-copy”. For simple “value-replacement”, please refer to the Result (=) command.


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

<xml id="User_{{ = @userNo }}">
{{ copy CheckIn }}
</xml>

Resulting Output

<xml id="User_1001">
<CheckIn status="CHECKED-IN" availability="Busy" lastUpdate="08/31/2010 16:18" />
</xml>

CopyEncoded (*=)

The CopyEncoded command, which has a shorthand equivalent of *=, is used to bring an XML encoded copy selected node into the result. This operates exactly like the above Copy command, except that the XML is encoded for display instead of the raw xml (for instance, < becomes &lt;). Again, no additional formatting options apply.

NOTE: This is a full “XML node-copy”. For simple “value-replacement”, please refer to the Result (=) command.


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

<xml id="User_{{ = @userNo }}">
{{ copyEncoded CheckIn }}
</xml>

Resulting Output

<xml id="User_1001">
&lt;CheckIn status=&quot;CHECKED-IN&quot; availability=&quot;Busy&quot; lastUpdate=&quot;08/31/2010 16:18&quot; /&gt;
</xml>

CopyDecoded (=*)

The CopyDecoded(or its shorthand =*) is used for the exact opposite case of the above CopyEncoded (*=) command. As you can probably already guess, it is for when XML has been Encoded for display, but now needs to be Decoded for XML use.


Source XML

<textarea>
&lt;p&gt;asdasd&lt;/p&gt;&lt;p&gt;asd&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;u&gt;&lt;em&gt;asasdas&lt;/em&gt;&lt;/u&gt;&lt;/li&gt;&lt;li&gt;a&lt;u&gt;&lt;strong&gt;sdadsdaasd&lt;/strong&gt;&lt;/u&gt;as&lt;/li&gt;&lt;li&gt;&lt;strong&gt;asdsadad&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;assadad&lt;/p&gt;
</textarea>

Template

<template>
<html>
{{ CopyDecoded /textarea }}
</html>
</template>

Resulting Output

<html>
<p>
asdasd
</p>
<p>
asd
</p>
<ul>
<li>
<u>
<em>
asasdas
</em>
</u>
</li>
<li>
a
<u>
<strong>
sdadsdaasd
</strong>
</u>
as
</li>
<li>
<strong>
asdsadad
</strong>
</li>
</ul>
<p>
assadad
</p>
</html>

XHTML

The XHTML command is used to take straight HTML and make it XML (aka XHTML) encoded. For instance, in HTML, tags like br and hr are open-ended. They exist as <br> and <hr> with no closing indicator. In XML, everything must have a closing tag, or be self-closing, such as <br /> and <hr />. Additionally, HTML allows for attribute definitions without values. The XHTML command converts these to loadable XML. The only parameter is an XPath to the container of the HTML string.


Source XML

<html>
<div unquoted=1 specials="<>&amp;&quot;"><br></br><BR><textarea>&lt;&gt;&amp;&quot;</textarea><HR empty ><hr />&lt;&gt;&amp;&quot;</div>
</html>

Template

<div>
{{xhtml /html }}
</div>

Resulting Output

<div>
<div unquoted="1" specials="<>&"">
<br />
<BR />
<textarea>
<>&"
</textarea>
<HR empty="empty" />
<hr />
<>&"
</div>
</div>

Conditional Commands

If … Else … EndIf (/If)

Any language worth its salt has some form of the If//Else/EndIf logic, and X2TL is no different. In X2TL, the If command takes an XPath parameter that is used to perform a “does-node- exist” test. The test can consist of a simple relative XPath, a root-node based XPath, or a logic-based XPath, each of which will be shown below. Like most languages, the Else command is optional, however, the EndIf(or its shorthand equivalent /If ) is required. In the future, an error message will most likely result in this situation, however at present, it may simply provide unpredictable results.


Source XML

<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<CheckIn status="CHECKED-IN" availability="Busy" lastUpdate="8/31/2010 16:18">
<message>
In meetings until lunch
</message>
</CheckIn>
</User>

Template

<div id="User_{{ = @userNo }}">
<span>
{{ string "{0}, {1} ({2})" @last @first @username }})
</span>
{{ IF /User/CheckIn }}
<span>
User is {{ = CheckIn/@status }} {{ If CheckIn/@facility }}at the {{ = CheckIn/@facility }}{{ Else }}but whereabouts are unknown{{ EndIF }}
</span>
{{ if (count(*/message)!=0) }}
<div>
{{ = */message }}
</div>
{{ /if }} {{ ENDIF }}
</div>

Resulting Output

<div id="User_1001">
<span>
Fine, Howard (hfine)
</span>
<span>
User is CHECKED-IN but whereabouts are unknown
</span>
<div>
In meetings until lunch
</div>
</div>

NOTE: In the above example, we see each of the three types of XPath tests: root-node based ( IF /User/Check-In ), relative( If Check-In/@facility ), and logical( if (count(*/message)!=0) ).

Looping Commands

Each … EndEach (/Each)

As with the simple conditional logic, one cannot get far in templating without providing a simple looping logic. More complex conditional looping commands such as Do…Until and While…EndWhile may come later, but until then, the simple Each command is provided. Each acts almost identically to XSL’s for-each command, taking an XPath as its parameter, which can either be a relative XPath against the context node, or a root-based XPath which will be applied against the context node’s document root element. Each XmlNode matching the given XPath will then be “looped”, with any Text or Command Fragments contained within the Each … EndEach block (or its shorthand equivalent of /Each) being repeated against the looped node as their context node. As with If…EndIf above, there is presently no error checking on un-matched Each…EndEach. While nesting of Each commands is valid, if you miss an EndEach(or /Each) command, the results may be unpredictable.


Source XML

<Patient lastName="Brown" firstName="Charlie">
<Allergies>
<row AllergyNo="1001" description="PEANUTS" reaction="Hives" />
<row AllergyNo="1002" description="LUCYVANPELT" reaction="Irritation" />
</Allergies>
</Patient>

Template

<div>
{{ = @lastName}}, {{ = @firstName }}
<table>
<tbody>
{{ EACH * }}
<tr>
<td colspan="2">
{{ = "translate(name(),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" }}
</td>
</tr>
{{ EACH row }}
<tr>
<td>
{{ = @description }}
</td>
<td>
{{ = @reaction }}
</td>
</tr>
{{ ENDEACH }} {{ /EACH }}
</tbody>
</table>
</div>

Resulting Output

<div>
Brown, Charlie
<table>
<tbody>
<tr>
<td colspan="2">
ALLERGIES
</td>
</tr>
<tr>
<td>
PEANUTS
</td>
<td>
Hives
</td>
</tr>
<tr>
<td>
LUCYVANPELT
</td>
<td>
Irritation
</td>
</tr>
</tbody>
</table>
</div>

Variable Commands

Variable (var, :=)

The Variable command, which has the shorthand equivalents of var and :=, is used to store a textual value as a (global) variable that can be used later. This command takes (2) parameters: name, xpath. The first parameter gives it a name to be used, and the second indicates what value should be stored. A named variable can then be referenced at any point that a single xpath expression is expected, by simply providing the variable name prefixed by the variable delimiter (default being $).

Source XML

<node>
<data d1="08/26/2010" />
</node>

Template

<div>
{{ := myVar data/@d1 }}
<span>
From Xpath: {{ = data/@d1 }} From Variable: {{ = $myVar }}
</span>
</div>

Resulting Output

<div>
<span>
From Xpath: 08/26/2010 From Variable: 08/26/2010
</span>
</div>

NOTE: As these are global variables, they can also be used in supporting templates.


Template

<div>
{{ := InputDate data/@d1 }}
<span>
Original: {{ = $InputDate }} EuroDate: {{ % EuroDate }}
</span>
</div>

Supporting Templates

<templates>
<template name="EuroDate">
{{ Date $InputDate "dd-MM-yyyy" }}
</template>
</templates>

Resulting Output

<div>
<span>
Original: 08/26/2010 EuroDate: 26-08-2010
</span>
</div>

MultiVar … EndMultiVar (MVar,::= … EndMVar,/MVar,/:==)

The MultiVar command is used to start creating a variable out of multiple pieces, and is completed with an EndMultiVar command. Any data that would have been resulted that is contained within a multivar start and end command will be stored as the contents of the variable. The start command has two shorthand equivalents: mvar, ::=, and several shorthand versions of the end command: endmvar, /MultiVar, /mvar, /::=. This command takes a single parameter of the name, and the resulting contents are considered the value, which can contain any number of other commands. Once created, Multipart Variables act identically to standard variables.


Source XML

<node>
<data att1="some" att2="more" att3="other" att4="weird">
stuff
</data>
</node>

Template

<div>
Multipart: {{ mvar totalstuff }}{{ each data/@* }}{{ = . }} {{ /each }}{{ = data }}{{ /mvar }}
<span>
{{ = $totalstuff }}
</span>
</div>

Resulting Output

<div>
Multipart:
<span>
some more other weird stuff
</span>
</div>

Load (:::)

Sometimes you need to include external data to assist in decision making, data validation, lookup values, etc. This is the purpose of the Load statement (or its shorthand version :::). Load takes (2) parameters, the first being the variable name, just like in the Var and MultiVar commands. The second paramter, however, is the path (relative, full, or UNC) to an XML file that should be loaded into memory and used as the variable from this point on. Please note that these variables support full XPath and similar functions, including Each looping.


Source XML

<User userNo="1001" lastName="Fine" firstName="Howard" userName="hfine">
<CheckIn status="CHECKED-IN" availability="Busy" lastUpdate="8/31/2010 16:18" facilityID="HQN" />
</User>

External XML

<Facilities>
<facility id="HQN" name="HeadQuarters - North" />
</Facilities>

Template

<div>
{{ Load Facilities "../DataFiles/Facilities.xml" }} {{ Var FacID CheckIn/@facilityID }}
<span>
User: {{ = @userName }} - {{ = CheckIn/@status }} @ {{ = ($Facilities/facility[@id=$FacID]/@name) }} ({{ = $FacID }})
</span>
</div>

Resulting Output

<div>
<span>
User: HFINE - CHECKED-IN @ HeadQuarters - North (HQN)
</span>
</div>

Template Commands

Both of the Template Commands, Apply (%%) and ParamApply (%%) expect that a separate XML block containing named template elements will exist. The Supporting Templates should be a single XML document, with any-named root element, and containing a simple list of any-named child elements, having a name attribute. These will be considered “named templates” that can be used by the Apply (%%) and ParamApply (%%) commands.

Apply (%)

While templates as described so far, provide for powerful formatting options, the true potential is unlocked when allowing them to Apply(with shorthand equivalent of %) other templates, either to the current context node, or against a different yet relative context. Apply always expects the name of a supporting template to be provided. Optionally, you can provide an XPath to apply the template against a different node context. Otherwise, the template will be applied against the current node context.


Source XML

<Patient lastName="Brown" firstName="Charlie">
<Diagnoses>
<row DiagnosisNo="1001" description="Depression" />
</Diagnoses>
<Allergies>
<row AllergyNo="1001" description="PEANUTS" reaction="Hives" />
<row AllergyNo="1002" description="LUCYVANPELT" reaction="Irritation" />
</Allergies>
<Medications />
</Patient>

Template

<div>
<h1>
{{ % FullName }}
</h1>
{{ Apply PatientDiagnoses Diagnoses }} {{ Apply PatientAllergies Allergies }} {{ Apply PatientMedications Medications }}
</div>

Supporting Templates

<templates>
<t name="FullName">
{{ = @lastName}}, {{ = @firstName }}
</t>
<t name="PatientDiagnoses">
{{ if (count(row)!=0) }}
<table>
<tbody>
{{ % PatientDiagnosisRow row }}
</tbody>
</table>
{{ else }}
<span>
No active diagnoses
</span>
{{ /if }}
</t>
<t name="PatientDiagnosisRow">
<tr>
<td>
{{ = @description }}
</td>
</tr>
</t>
<t name="PatientAllergies">
{{ if (count(row)!=0) }}
<table>
<tbody>
{{ % PatientAllergyRow row }}
</tbody>
</table>
{{ else }}
<span>
No documented allergies
</span>
{{ /if }}
</t>
<t name="PatientAllergyRow">
<tr>
<td>
{{ = @description }}
</td>
<td>
{{ = @reaction }}
</td>
</tr>
</t>
<t name="PatientMedications">
{{ if (count(row)!=0) }}
<table>
<tbody>
{{ % PatientMedicationRow row }}
</tbody>
</table>
{{ else }}
<span>
No active medications
</span>
{{ /if }}
</t>
<t name="PatientMedicationRow">
<tr>
<td>
{{ = @description }}
</td>
<td>
{{ = @strength }}
</td>
</tr>
</t>
</templates>

NOTE: The actual name of the child elements for a Supporting Templates block is irrelevant and ignored by the engine. The child tag <t> is used for illustration purposes only, to show that it is unimportant.


Resulting Output

<div>
<h1>
Brown, Charlie
</h1>
<table>
<tbody>
<tr>
<td>
Depression
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>
PEANUTS
</td>
<td>
Hives
</td>
</tr>
<tr>
<td>
LUCYVANPELT
</td>
<td>
Irritation
</td>
</tr>
</tbody>
</table>
<span>
No active medications
</span>
</div>

ParamApply (%%)

In some cases, you will find a desire to pass parameters to supporting templates, which can be accomplished with the ParamApply command (with shorthand equivalent of %%). Unlike the Apply command, the ParamApply command requires an end command, being EndParamApply(or its shorthand options /ParamApply or /%%). Within the begin and end wrapper commands, you can specify either Variable (:=) or MultiVar (::=) commands, which will be scoped to within this template application. These variable declarations will act exactly like standard variables, however they will fall out of scope immediately after the template call.


Source XML

<Root>
<input click="this.focus();" desc="text field" />
<emptyEl />
<button click="alert(this.desc);" desc="stuff" />
</Root>

Template

<div>
{{ := onclick "'return void();'" }}{{ := description "'Howdy!'" }} {{ apply BuildElement }} {{ EACH * }} {{ paramapply BuildElement . }} {{ := element "name(.)" }}{{ := onclick @click }}{{ := description @desc }} {{ /paramapply }} {{ /EACH }} {{ apply BuildElement }}
</div>

Supporting Templates

<templates>
<t name="BuildElement">
<span onclick="{{ = $onclick }}" sourceEl="{{ = $element }}">
{{ = $description }}
</span>
</t>
</templates>

NOTE: The actual name of the child elements for a Supporting Templates block is irrelevant and ignored by the engine. The child tag <t> is used for illustration purposes only, to show that it is unimportant.


Resulting Output

<div>
<span onclick="return void();" sourceEl="">
Howdy!
</span>
<span onclick="this.focus();" sourceEl="input">
text field
</span>
<span onclick="" sourceEl="emptyEl" />
<span onclick="alert(this.desc);" sourceEl="button">
stuff
</span>
<span onclick="return void();" sourceEl="">
Howdy!
</span>
</div>

Miscellaneous Commands

NewID (GUID)

The NewID(or its alternate and more popular, GUID) command is used to generate a Globally Unique ID, and takes no parameters.


Source XML

<dontCare />

Template

<span>
{{ GUID }}
</span>

Resulting Output

<span>
4f3f639f-8891-4721-9f73-189773b3c4ae
</span>

Version (ver)

The Version command (or its shorthand ver) is used to simply display the current version information of the X2TL engine, and takes no parameters.


Source XML

<dontCare />

Template

<span>
{{ Version }}
</span>

Resulting Output

<span>
X2TL v1.1.0 rev.0
</span>