Basics - FreeMarker Manual

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# Basics

Note:

This section uses the DOM tree and the variable made in the previous chapter.

Assume that the programmer has put the XML document into the data-model as variable `doc`. This variable corresponds to the root of the DOM tree, the ``document''. The actual variable structure behind `doc` is wily enough, and only roughly resembles the DOM tree. So instead of getting lost in the details, let's see how to use it by example.

## Accessing elements by name

This FTL prints the title of the book:

    <h1>${doc.book.title}</h1>

The output will be:

    <h1>Test Book</h1>

As you see, both `doc` and `book` can be used as hashes; you get their child nodes as sub variables. Basically, you describe the path by which you reach the target (element `title`) in the DOM tree. You may notice that there was some swindle above: with `${doc.book.title}`, it seems that we instruct FreeMarker to print the `title` element itself, but we should print its child text node (check the DOM tree). It still works, because elements are not only hash variables, but string variables as well. The scalar value of an element node is the string resulting from the concatenation of all its text child nodes. However, trying to use an element as scalar will cause error if the element has child elements. For example `${doc.book}` would stop with error.

This FTL prints the titles of the two chapters:

    <h2>${doc.book.chapter[0].title}</h2>
    <h2>${doc.book.chapter[1].title}</h2>

Here, as `book` has 2 `chapter` element children, `doc.book.chapter` is a sequence that stores the two element nodes. Thus, we can generalize the above FTL, so it works with any number of chapters:

    <#list doc.book.chapter as ch>
      <h2>${ch.title}</h2>
    </#list>

But what's if there is only one chapter? Actually, when you access an element as hash subvariable, it is always a sequence as well (not only hash and string), but if the sequence contains exactly 1 item, then the variable also acts as that item itself. So, returning to the first example, this would print the book title as well:

    <h1>${doc.book[0].title[0]}</h1>

But you know that there is exactly 1 `book` element, and that a book has exactly 1 title, so you can omit the `[0]`-s. `${doc.book.chapter.title}` would work too, if the book happen to have only 1 `chapter`-s (otherwise it is ambiguous: how is it to know if the `title` of which `chapter` you want? So it stops with an error.). But since a book can have multiple chapters, you don't use this form. If the element `book` has no `chapter` child, then `doc.book.chapter` will be a 0 length sequence, so the FTL with `<#list ...>` will still work.

It is important to realize the consequence that, for example, if `book` has no `chapter`-s then `book.chapter` is an empty sequence, so `doc.book.chapter??` will not be `false`, it will be always `true`! Similarly, `doc.book.somethingTotallyNonsense??` will not be `false` either. To check if there was no children found, use `doc.book.chapter[0]??` (or `doc.book.chapter?size == 0`). Of course you can use similarly all the missing value handler operators (e.g. `doc.book.author[0]!"Anonymous"`), just don't forget that `[0]`.

Note:

The rule with sequences of size 1 is a convenience feature of the XML wrapper (implemented via multi-type FTL variables). It will not work with other sequences in general.

Now we finish the example by printing all the `para`-s of each chapter:

    <h1>${doc.book.title}</h1>
    <#list doc.book.chapter as ch>
      <h2>${ch.title}</h2>
      <#list ch.para as p>
        <p>${p}
      </#list>
    </#list>

this will print:

    <h1>Test</h1>
      <h2>Ch1</h2>
        <p>p1.1
        <p>p1.2
        <p>p1.3
      <h2>Ch2</h2>
        <p>p2.1
        <p>p2.2

The above FTL could be written more nicely as:

    <#assign book = doc.book>
    <h1>${book.title}</h1>
    <#list book.chapter as ch>
      <h2>${ch.title}</h2>
      <#list ch.para as p>
        <p>${p}
      </#list>
    </#list>

Finally, a ``generalized`` usage of the child selector mechanism: this template lists all `para`-s of the example XML document:

    <#list doc.book.chapter.para as p>
      <p>${p}
    </#list>

The output will be:

      <p>p1.1
      <p>p1.2
      <p>p1.3
      <p>p2.1
      <p>p2.2

This example shows that hash sub variables select the children of a sequence of notes (just in the earlier examples that sequence happened to be of size 1). In this concrete case, subvariable `chapter` returns a sequence of size 2 (since there are two `chapter`-s), and then subvariable `para` selects the `para` child nodes of all nodes in that sequence.

A negative consequence of this mechanism is that things like `doc.somethingNonsense.otherNonsesne.totalNonsense` will just evaluate to an empty sequence, and you don't get any error messages.

## Accessing attributes

This XML is the same as the original, except that it uses attributes for the titles, instead of elements:

    <!-- THIS XML IS USED FOR THE "Accessing attributes" CHAPTER ONLY! -->
    <!-- Outside this chapter examples use the XML from earlier.       -->

    <book title="Test">
      <chapter title="Ch1">
        <para>p1.1</para>
        <para>p1.2</para>
        <para>p1.3</para>
      </chapter>
      <chapter title="Ch2">
        <para>p2.1</para>
        <para>p2.2</para>
      </chapter>
    </book>

The attributes of an element can be accessed in the same way as the child elements of the element, except that you put an at-sign (@) before the name of the attribute:

    <#assign book = doc.book>
    <h1>${book.@title}</h1>
    <#list book.chapter as ch>
      <h2>${ch.@title}</h2>
      <#list ch.para as p>
        <p>${p}
      </#list>
    </#list>

This will print exactly the same as the previous example.

Getting attributes follows the same logic as getting child elements, so the result of `ch.@title` above is a sequence of size 1. If there were no `title` attribute, then the result would be a sequence of size 0. So be ware, using existence built-ins is tricky here too: if you are curious if `foo` has attribute `bar` then you have to write `foo.@bar[0]??`. (`foo.@bar??` is wrong, because it always returns `true`.) Similarly, if you want a default value for the `bar` attribute, then you have to write `foo.@bar[0]!"theDefaultValue"`.

As with child elements, you can select the attributes of multiple nodes. For example, this template prints the titles of all chapters:

    <#list doc.book.chapter.@title as t>
      ${t}
    </#list>

## Exploring the tree

This FTL will enumerate all child nodes of the book element:

    <#list doc.book?children as c>
    - ${c?node_type} <#if c?node_type == 'element'>${c?node_name}</#if>
    </#list>

this will print:

    - text
    - element title
    - text
    - element chapter
    - text
    - element chapter
    - text

The meaning of `?node_type` is probably clear without explanation. There are several node types that can occur in a DOM tree, such as `"element"`, `"text"`, `"comment"`, `"pi"`, ...etc.

The `?node_name` returns the name of element for element nodes. For other node types, it also returns something, but that's mainly useful for declarative XML processing, which will be discussed in a later chapter.

If the book element had attributes, they would not appear in the above list, for practical reasons. But you can get a list that contains all attributes of the element, with subvariable `@@` of the element variable. If you modify the first line of the XML to this:

    <book foo="Foo" bar="Bar" baaz="Baaz">

and run this FTL:

    <#list doc.book.@@ as attr>
    - ${attr?node_name} = ${attr}
    </#list>

then you get this output (or something similar):

    - baaz = Baaz
    - bar = Bar
    - foo = Foo

Returning to the listing of children, there is a convenience subvariable to list only the element children of an element:

    <#list doc.book.* as c>
    - ${c?node_name}
    </#list>

This will print:

    - title
    - chapter
    - chapter

You get the parent of an element with the `parent` built-in:

    <#assign e = doc.book.chapter[0].para[0]>
    <#-- Now e is the first para of the first chapter -->
    ${e?node_name}
    ${e?parent?node_name}
    ${e?parent?parent?node_name}
    ${e?parent?parent?parent?node_name}

This will print:

    para
    chapter
    book
    @document

In the last line you have reached the root of the DOM tree, the document node. It's not an element, and this is why it has that strange name; don't deal with it now. Obviously, the document node has no parent.

You can quickly go back to the document node using the `root` built-in:

    <#assign e = doc.book.chapter[0].para[0]>
    ${e?root?node_name}
    ${e?root.book.title}

This will print:

    @document
    Test Book

For the complete list of built-ins you can use to navigate in the DOM tree, read the reference of node built-ins.

## Using XPath expressions

Note:

XPath expressions work only if Jaxen (recommended, but use at least Jaxen 1.1-beta-8, not older) or Apache Xalan classes are available. (Apache Xalan classes are included in Sun J2SE 1.4, 1.5 and 1.6 (and maybe later too); no separate Xalan jar is needed.)

Note:

Don't use the sample XML from the previous section, where `title` is an attribute; that applies only to that section.

If a hash key used with a node variable can't be interpreted otherwise (see the next section for the precise definition), then it will by interpreted as an XPath expression. For more information on XPath, please visit http://www.w3.org/TR/xpath.

For example, here we list the `para` elements of the chapter with `title` element (not attribute!) content "Ch1'':

    <#list doc["book/chapter[title='Ch1']/para"] as p>
      <p>${p}
    </#list>

It will print:

      <p>p1.1
      <p>p1.2
      <p>p1.3

The rule with sequences of length 1 (explained in earlier sections) stands for XPath results as well. That is, if the resulting sequence contains exactly 1 node, it also acts as the node itself. For example, print the first paragraph of chapter ``Ch1'':

    ${doc["book/chapter[title='Ch1']/para[1]"]}

which prints the same as:

    ${doc["book/chapter[title='Ch1']/para[1]"][0]}

The context node of the XPath expression is the node (or sequence of nodes) whose hash subvariable is used to issue the XPath expression. Thus, this prints the same as the previous example:

    ${doc.book["chapter[title='Ch1']/para[1]"]}

Note that currently you can use a sequence of 0 or multiple (more than 1) nodes as context only if the programmer has set up FreeMarker to use Jaxen instead of Xalan.

Also note that XPath indexes sequence items from 1, while FTL indexes sequence items from 0. Thus, to select the first chapter, the XPath expression is `"/book/chapter[1]"`, while the FTL expression is `book.chapter[0]`.

If the programmer has set up FreeMarker to use Jaxen instead of Xalan, then FreeMarker variables are visible with XPath variable references:

    <#assign currentTitle = "Ch1">
    <#list doc["book/chapter[title=$currentTitle]/para"] as p>
    ...

Note that `$currentTitle` is not a FreeMarker interpolation, as there are no `{` and `}` there. That's an XPath expression.

The result of some XPath expressions is not a node-set, but a string, a number, or a boolean. For those XPath expressions, the result is an FTL string, number, or boolean variable respectively. For example, the following will count the total number of `para` elements in the XML document, so the result is a number:

    ${x["count(//para)"]}

The output will be:

    5

## XML namespaces

Be default, when you write something like `doc.book`, then it will select the element with name `book` that does not belongs to any XML namespace (similarly to XPath). If you want to select an element that is inside an XML namespace, you must register a prefix and use that. For example, if element `book` is in XML namespace `http://example.com/ebook`, then you have to associate a prefix with it at the top of the template with the `ns_prefixes` parameter of the `ftl` directive:

    <#ftl ns_prefixes={"e":"http://example.com/ebook"}>

And now you can write expressions as `doc["e:book"]`. (The usage of square bracket syntax was required because the colon would confuse FreeMarker otherwise.)

As the value of `ns_prefixes` is a hash, you can register multiple prefixes:

    <#ftl ns_prefixes={
        "e":"http://example.com/ebook",
        "f":"http://example.com/form",
        "vg":"http://example.com/vectorGraphics"}
    >

The `ns_prefixes` parameter affects the whole FTL namespace. This means in practice that the prefixes you have registered in the main page template will be visible in all `<#include ...>`-d templates, but not in `<#imported ...>`-d templates (often referred as FTL libraries). Or from another point of view, an FTL library can register XML namespace prefixes for it's own use, without interfering with the prefix registrations of the main template and other libraries.

Note that, if an input document is dominated by a given XML namespace, you can set that as the default namespace for convenience. This means that if you don't use prefix, as in `doc.book`, then it selects element that belongs to the default namespace. The setting of the default namespace happens with reserved prefix `D`, for example:

    <#ftl ns_prefixes={"D":"http://example.com/ebook"}>

Now expression `doc.book` select the `book` element that belongs to XML namespace `http://example.com/ebook`. Unfortunately, XPath does not support this idea of a default namespace. Thus, in XPath expressions, element names without prefixes always select the elements that does not belong to any XML namespace. However, to access elements in the default namespace you can directly use prefix `D`, for example: `doc["D:book/D:chapter[title='Ch1']"]`.

Note that when you use a default namespace, then you can select elements that does not belong to any node namespace with reserved prefix `N`, for example `doc.book["N:foo"]`. It doesn't go for XPath expressions, where the above can be witten as `doc["D:book/foo"]`.

## Don't forget escaping!

We have made a big mistake in all examples. We generate output of HTML format, and HTML format reserves characters as `<`, `&`, etc. So when we print plain text (as the titles and paragraphs), we have to escape it. Thus, the correct version of the example is:

    <#escape x as x?html>
    <#assign book = doc.book>
    <h1>${book.title}</h1>
    <#list book.chapter as ch>
      <h2>${ch.title}</h2>
      <#list ch.para as p>
        <p>${p}
      </#list>
    </#list>
    </#escape>

So if the book title is "Romeo & Julia", the resulting HTML output will be correctly:

    ...
    <h1>Romeo &amp; Julia</h1>
    ...

Previous Next