Legacy XML wrapper implementation - FreeMarker Manual

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# Legacy XML wrapper implementation

Note:

The legacy XML wrapper is deprecated. FreeMarker 2.3 has introduced support for a new XML processing model. To support this, a new XML wrapper package was introduced, `freemarker.ext.dom`. For new usage, we encourage you to use that. It is documented in the part XML Processing Guide.

The class `freemarker.ext.xml.NodeListModel` provides a template model for wrapping XML documents represented as node trees. Every node list can contain zero or more XML nodes (documents, elements, texts, processing instructions, comments, entity references, CDATA sections, etc.). The node list implements the following template model interfaces with the following semantics:

## TemplateScalarModel

When used as a scalar, the node list will render the XML fragment that represents its contained nodes. This makes it handy for use in XML-to-XML transforming templates.

## TemplateCollectionModel

When used as a collection with `list` directive, it will simply enumerate its nodes. Every node will be returned as a new node list consisting of a single node.

## TemplateSequenceModel

When used as a sequence, it will return the i-th node as a new node list consisting of the single requested node. I.e. to return the 3rd `<chapter>` element of the `<book>` element, you'd use the following (note indexes are zero-based):

    <#assign thirdChapter = xmldoc.book.chapter[2]>

## TemplateHashModel

When used as a hash, it is basically used to traverse children. That is, if you have a node list named `book` that wraps an element node with several chapters, then the `book.chapter` will yield a node list with all chapter elements of that book element. The at sign is used to refer to attributes: `book.@title` yields a node list with a single attribute node, that is the title attribute of the book element.

It is important to realize the consequence that, for example, if `book` has no `chapter`-s then `book.chapter` is an empty sequence, so `xmldoc.book.chapter??` will not be `false`, it will be always `true`! Similarly, `xmldoc.book.somethingTotallyNonsense??` will not be `false` either. To check if there was no children found, use `xmldoc.book.chapter?size == 0`.

The hash defines several "magic keys" as well. All these keys start with an underscore. The most notable is the `_text` key which retrieves the text of the node: `${book.@title._text}` will render the value of the attribute into the template. Similarly, `_name` will retrieve the name of the element or attribute. `*` or `_allChildren` returns all direct children elements of all elements in the node list, while `@*` or `_allAttributes` returns all attributes of the elements in the node list. There are many more such keys; here's a detailed summary of all the hash keys:

Key name | Evaluates to
--- | ---
`*` or `_children` | all direct element children of current nodes (non-recursive). Applicable to element and document nodes.
`@*` or `_attributes` | all attributes of current nodes. Applicable to elements only.
`@attributeName` | named attributes of current nodes. Applicable to elements, doctypes and processing instructions. On doctypes it supports attributes `publicId`, `systemId` and `elementName`. On processing instructions, it supports attributes `target` and `data`, as well as any other attribute name specified in data as `name="value"` pair. The attribute nodes for doctype and processing instruction are synthetic, and as such have no parent. Note, however that `@*` does NOT operate on doctypes or processing instructions.
`_ancestor` | all ancestors up to root element (recursive) of current nodes. Applicable to same node types as `_parent`.
`_ancestorOrSelf` | all ancestors of current nodes plus current nodes. Applicable to same node types as `_parent`.
`_cname` | the canonical names of current nodes (namespace URI + local name), one string per node (non-recursive). Applicable to elements and attributes
`_content` | the complete content of current nodes, including children elements, text, entity references, and processing instructions (non-recursive). Applicable to elements and documents.
`_descendant` | all recursive descendant element children of current nodes. Applicable to document and element nodes.
`_descendantOrSelf` | all recursive descendant element children of current nodes plus current nodes. Applicable to document and element nodes.
`_document` | all documents the current nodes belong to. Applicable to all nodes except text.
`_doctype` | doctypes of the current nodes. Applicable to document nodes only.
`_filterType` | is a filter-by-type template method model. When called, it will yield a node list that contains only those current nodes whose type matches one of types passed as argument. You should pass arbitrary number of strings to this method containing the names of types to keep. Valid type names are: "attribute", "cdata", "comment", "document", "documentType", "element", "entity", "entityReference", "processingInstruction", "text".
`_name` | the names of current nodes, one string per node (non-recursive). Applicable to elements and attributes (returns their local names), entities, processing instructions (returns its target), doctypes (returns its public ID)
`_nsprefix` | the namespace prefixes of current nodes, one string per node (non-recursive). Applicable to elements and attributes
`_nsuri` | the namespace URIs of current nodes, one string per node (non-recursive). Applicable to elements and attributes
`_parent` | parent elements of current nodes. Applicable to element, attribute, comment, entity, processing instruction.
`_qname` | the qualified names of current nodes in `[namespacePrefix:]localName` form, one string per node (non-recursive). Applicable to elements and attributes
`_registerNamespace(prefix, uri)` | register a XML namespace with the specified prefix and URI for the current node list and all node lists that are derived from the current node list. After registering, you can use the `nodelist["prefix:localname"]` or `nodelist["@prefix:localname"]` syntaxes to reach elements and attributes whose names are namespace-scoped. Note that the namespace prefix need not match the actual prefix used by the XML document itself since namespaces are compared solely by their URI.
`_text` | the text of current nodes, one string per node (non-recursive). Applicable to elements, attributes, comments, processing instructions (returns its data) and CDATA sections. The reserved XML characters ('<' and '&') are not escaped.
`_type` | Returns a node list containing one string per node describing the type of the node. Possible node type names are: "attribute", "cdata", "comment", "document", "documentType", "element", "entity", "entityReference", "processingInstruction", "text". If the type of the node is unknown, returns "unknown".
`_unique` | a copy of the current nodes that keeps only the first occurrence of every node, eliminating duplicates. Duplicates can occur in the node list by applying uptree-traversals `_parent`, `_ancestor`, `_ancestorOrSelf`, and `_document`. I.e. `foo._children._parent` will return a node list that has duplicates of nodes in foo - each node will have the number of occurrences equal to the number of its children. In these cases, use `foo._children._parent._unique` to eliminate duplicates. Applicable to all node types.
any other key | element children of current nodes with name matching the key. This allows for convenience child traversal in `book.chapter.title` style syntax. Note that `nodeset.childname` is technically equivalent to `nodeset("childname")`, but is both shorter to write and evaluates faster. Applicable to document and element nodes.

## TemplateMethodModel

When used as a method model, it returns a node list that is the result of evaluating an XPath expression on the current contents of the node list. For this feature to work, you must have the `Jaxen` library in your classpath. For example:

    <#assign firstChapter=xmldoc("//chapter[first()]")>

## Namespace handling

For purposes of traversal of children elements that have namespace-scoped names, you can register namespace prefixes with the node list. You can do it either in Java, calling the

    public void registerNamespace(String prefix, String uri);

method, or inside a template using the

    ${nodelist._registerNamespace(prefix, uri)}

syntax. From there on, you can refer to children elements in the namespace denoted by the particular URI through the syntax

    nodelist["prefix:localName"]

and

    nodelist["@prefix:localName"]

as well as use these namespace prefixes in XPath expressions. Namespaces registered with a node list are propagated to all node lists that are derived from the original node list. Note also that namespaces are matched by their URI only, so you can safely use a prefix for a namespace inside your template that differs from the prefix in the actual XML document - a prefix is just a local alias for the URI both in the template and in the XML document.

Previous Next