util.xtemplate

util.xtemplate implements a string template language, similar to util.interpolation but different. Notably, it takes as input an XML stanza rather than a Lua table.

For example:

local st = require "util.stanza"
local xtemplate = require "util.xtemplate"

print(xtemplate.render("{greet}", st.stanza("root"):text_tag("greet", "Hello")));
--> Hello

Syntax

template ::= "{" path { "|" function { "(" path ")" }? {"{" template "}"}? }* "}"
path ::= See the :find() method in util.stanza

The variable interpolation is based on the stanza.find(path) method, so {path} would be replaced with root:find("path") or rather its text content.

Built-in functions

In examples, XML is the parse() function from util.xml.

local XML = require"util.xml".parse;

and, or

Conditional templates, allows fallback values or rendering parts if some value is present.

render("{foo/bar|or{Nope}}", XML [[
<root>
  <foo>
    <bar>Hello</bar>
  </foo>
</root>
]])
-- > Hello

render("{foo/bar|or{Nope}}", XML [[
<root>
  <foo>
</root>
]])
-- > Nope

These functions can take an optional path to base the condition on instead of the “current” path (foo/bar in previous examples).

render("{foo|and(yes){{print}}}", XML[[
<root>
  <foo>
    <yes/>
    <print>Hello</print>
  </foo>
</root>
]])
--> Hello

each

Allows iterating over XML element children. When the path passed consists of more than one element (e.g. foo/bar, as opposed to just foo) then the child tag to iterate must be given as an argument in parenthesis.

{foo/bar|each(baz){this}}

given

<foo>
  <bar>
    <baz>Hello</baz>
    <baz>World</baz>
  </bar>
</foo>

would result in

thisthis

Another example, this time without an argument:

{entry|each{
# {title}

by {author/name}

{content}
}}
<feed>
  <entry>
    <title>Hello World</title>
    <author>
      <name>Juliet</name>
    </author>
    <content>Lorem ipsum.</content>
  </entry>
  <entry>
    <title>Another Post</title>
    <author>
      <name>Romeo</name>
    </author>
    <content>Dolor sit amet.</content>
  </entry>
</feed>

would result in

# Hello World

by Juliet

Lorem ipsum.

# Another Post

by Romeo

Dolor sit amet.

Custom filter functions

In addition to these built-in functions, further filters can be passed as table argument to render() like so:

render("{foo/bar|upper}", XML[[
<root>
  <foo>
    <bar>Hello</bar>
  </foo>
</root>
]], nil, { upper = string.upper });
--> HELLO