March 2009

Introducing JSON Template

JSON Template is a minimal but powerful templating language, currently implemented in both Python and JavaScript.

To use it, simply copy the Python file or the JavaScript file into your project. Neither has any external dependencies.

Since there are over one bajillion template languages for Python alone, it deserves some explanation. But first here are some examples.

Simple example

>>> import jsontemplate
>>> jsontemplate.expand('Hello {name}', {'name': 'world'})
'Hello world'

This Python example should look familiar to many people.* The JavaScript version is a straightforward translation of this API.

Full Example

To read this example, keep in mind the following:

  • A variable can be substituted by surrounding its name with curly braces: {}
  • Template "directives" start with a period: .
  • In place of for loops and if statements, the basic idea is that the template declares sections and repeated sections. The sections are named after keys in the JSON data dictionary. The presence or absence of the keys in the JSON dictionary implicitly determines if and how many times a section is expanded.
  • If a JSON dictionary key is missing or empty ([], {}, or null), then the {.or} section is expanded.

These few constructs are surprisingly powerful.

The following example uses most of the language, but not all.

A template string ...

{# This is a comment and will be removed from the output.}

{.section songs}
  <h2>Songs in '{playlist-name}'</h2>

  <table width="100%">
  {.repeated section @}
    <tr>
      <td><a href="{url-base|htmltag}{url|htmltag}">Play</a>
      <td><i>{title}</i></td>
      <td>{artist}</td>
    </tr>
  {.end}
  </table>
{.or}
  <p><em>(No page content matches)</em></p>
{.end}

... combined with a data dictionary ...

{
  "url-base": "http://example.com/music/", 
  "playlist-name": "Epic Playlist", 
  "songs": [
    {
      "url": "1.mp3", 
      "artist": "Grayceon", 
      "title": "Sounds Like Thunder"
    }, 
    {
      "url": "2.mp3", 
      "artist": "Thou", 
      "title": "Their Hooves Carve Craters in the Earth"
    }
  ]
}

... gives output:

  <h2>Songs in 'Epic Playlist'</h2>

  <table width="100%">
    <tr>
      <td><a href="http://example.com/music/1.mp3">Play</a>
      <td><i>Sounds Like Thunder</i></td>
      <td>Grayceon</td>
    </tr>
    <tr>
      <td><a href="http://example.com/music/2.mp3">Play</a>
      <td><i>Their Hooves Carve Craters in the Earth</i></td>
      <td>Thou</td>
    </tr>
  </table>

Here is the rendered output:

Songs in 'Epic Playlist'

Play Sounds Like Thunder Grayceon
Play Their Hooves Carve Craters in the Earth Thou

Here is the same example live in JavaScript.

Motivation

There are a few problems with the state of the art:

  • Nearly all template languages are inexpressive and ill-specified procedural languages. That is, they reinvent things like for loops, if statements, and expressions poorly. A notable exception is google-ctemplate, a declarative language which runs google.com, no less, and JSON Template is strongly influenced by it.
  • Template languages grow "hairs" over time, and thus become bound to a specific implementation and a specific implementation language (e.g. Java, Python). Here is a good example of the "smell" I'm talking about.
  • AJAX programming makes client side templating more important. I'd like to use the same system on both the client and the server.
  • Every successful website needs an API. That's almost the definition of success -- people have put their important information in your site, and they need to get it out through means other than a browser. However, bolting an API on top of a web app not architected for it can result in fragile code, or at least unwanted duplication. JSON is a common choice for APIs.

Design

JSON Template addresses these issues with the following design choices:

JSON is the "data dictionary" format.

This has a number of consequences. One small but surprisingly useful consequence is that you can serialize your data dictionaries to files, which is useful for testing, internationalization, and a few more things I haven't thought of.

A more important consequence is that you use your programming language, rather than the template system, for application logic. Every language has a way to create JSON-like structures. You can use your language's features for manipulating dictionaries, arrays, and strings. In dynamic languages like Python and JavaScript, this is especially powerful.

Thus, there's a very simple programming pattern for "Web 2.0" sites:

  1. Create a JSON structure in response to an HTTP request.
  2. If say ?format=json is in the URL, then output the raw JSON.
  3. If not, combine the JSON with a Template string and output an HTML page (or Atom feed, etc.).

In this way, JSON Template is the complement of JSON. When you use a template language to express program logic, this one-to-one correspondence between human-consumable data and machine-consumable data is hard to achieve.

The language is deliberately small, and it is declarative rather than procedural.

It's intended to be easily reimplemented in multiple languages. Right now there's a JavaScript and a Python implementation -- each 500-ish lines of code in a single file -- with no dependencies. And they both pass the same tests! I'm hoping that people will contribute more implementations (Java, Ruby, PHP, etc.), which can be easily verified against these tests.

More Features

  • Comes with a default set of "formatters", so it's easy to get escaping/security right.
  • Extensible with your own application-specific formatters
  • A small degree of customizable syntax makes it appropriate for many problem domains (not just web programming).
  • Fast and hackable implementation. Tokenization, parsing, compilation, and template expansion are all cleanly separated in the code. (Like many template languages, instantiating a jsontemplate.Template object compiles the template string, and it can be subsequently re-expanded with different data dictionaries without parsing.)

Despite being simple and minimal, it's still powerful. See the Features wiki page for more details.

License

I picked the Apache 2.0 license for maximum compatibility with liberal open source licenses, copyleft licenses, and proprietary software.

Feedback

File bugs or send mail to the mailing list. There's also a reddit thread for comments.

As mentioned, I've kept the language minimal on purpose. There are a couple more features that I may want to add, so feedback is useful.

* The {} syntax for variable substitution seems to be getting popular. It's used in Python 3.0 string formatting, URI templates, JsonT, etc.