Formal description
Every variable that corresponds to a single node in the DOM tree is a multi-type variable of type node and type hash (for programmers: implements both TemplateNodeModel and TemplateHashModel). Thus, you can use the node built-ins with them. Hash keys are interpreted as XPath expressions, except the special keys shown in the table below. Some of the node variables also have string type, so you can use them as string variables (for programmers: they implement TemplateScalarModel).
Node type (?node_type) | Node name (?node_name) | String value (e.g. <p>${node}) | Special hash keys |
---|---|---|---|
"document" | "@document" | No string value. (Error when you try to use it as string.) | "elementName", "prefix:elementName", "*", "**", "@@markup", "@@nested_markup", "@@text" |
"element" | "name": the name of the element. This is the local name (i.e. name without namespace prefix). | If it has no element children, the text of all text node children concatenated together. Error otherwise, when you try to use it as string. | "elementName", "prefix:elementName", "*", "**", "@attrName", "@prefix:attrName", "@@", "@*", "@@start_tag", "@@end_tag", "@@attributes_markup", "@@markup", "@@nested_markup", "@@text", "@@qname" |
"text" | "@text" | The text itself. | "@@markup", "@@nested_markup", "@@text" |
"pi" | "@pi$target" | The part between the target name and the ?>. | "@@markup", "@@nested_markup", "@@text" |
"comment" | "@comment" | The text of the comment, without the delimiters <!-- and -->. | "@@markup", "@@nested_markup", "@@text" |
"attribute" | "name": the name of the attribute. This is the local name (i.e. name without namespace prefix). | The value of the attribute. | "@@markup", "@@nested_markup", "@@text", "@@qname" |
"document_type" | "@document_type$name": name is the name of the document element. | No string value. (Error when you try to use it as string.) | "@@markup", "@@nested_markup", "@@text" |
Notes:
-
There is no CDATA type. CDATA nodes are transparently considered as text nodes.
-
Variables do not support ?keys and ?values.
-
Element and attribute node names are local names, that is, they do not contain the namespace prefix. The URI of the namespace the node belongs to can be queried with the ?node_namespace built-in.
-
XPath expression needs Jaxen (recommended, but please use 1.1-beta-8 or later; download it here) or Apache Xalan classes available, or an error will stop template execution. Note, however, that as some special hash keys hide the XPath expressions of the same meaning, those XPath expressions will work even if there is no XPath implementation available. If both Xalan and Jaxen is available, FreeMarker will use Xalan, unless you choose Jaxen by calling freemarker.ext.dom.NodeModel.useJaxenXPathSupport() from Java.
-
If Jaxen is used for the XPath support (not Xalan), then FreeMarker variables are visible with XPath variable references (e.g. doc["book/chapter[title=$currentTitle]"]).
Meaning of special hash keys:
-
"elementName", "prefix:elementName": Returns the sequence of child nodes that are elements of name elementName. (Note that the term ``child'' means immediate descendant.) The selection is XML name-space aware, unless the XML document was persed with an XML parser that was not in namespace aware mode. In XML name-space aware mode, names without prefix (elementName) selects only elements that doesn't belong to any XML name-space (unless you have registered a default XML namespace), and names with prefix (prefix:elementName) selects only elements that are belonging to the XML namespace denoted by the prefix. The registration of prefixes and the setting of the default XML namespace is done with the ns_prefixes parameter of the ftl directive.
-
"*": Returns the sequence of all child (direct descedant) element nodes. The sequence will contain the elements in the ``document order'', that is, in the order in which the first character of the XML representation of each node occurs (after expansion of general entities).
-
"**": Returns the sequence of all descendant element nodes. The sequence will contain the elements in the document order.
-
"@attName", "@prefix:attrName": Returns the attribute attName of the element as a sequence of size 1 that contains the attribute node, or as an empty sequence if the attribute does not exist (so to check if an attribute exists use foo.@attName[0]??, not foo.@attName??). As with special key "elementName", if the length of the sequence is 1, then it also acts as its first subvariable. If no prefix is used, then it returns only attribute that does not use XML namespace (even if you have set a default XML namespace). If a prefix is used, it returns only the attribute that belongs to the XML namespace associated with the prefix. The registration of prefixes is done with the ns_prefixes parameter of the ftl directive.
-
"@@" or "@*": Returns the sequence of attribute nodes belonging to the parent element. This is the same as XPath @*.
-
"@@qname": Returns the full-qualified name of the element (such as e:book, in contrast to the local name returned by ?node_name that is book) . The prefix used (as e) is chosen based on the prefix registered in the current namespace with the ns_prefixes parameter of the ftl directive, and not influenced by the prefix used in the source XML document. If you have set a default XML namespace, then for nodes that use that, prefix D will be used. For nodes that does not belong to an XML namespace, no prefix is used (even if you have set a default namespace). If there is no prefix registered for the namespace of the node, the result is a non-existent variable (node.@@qname?? is false).
-
"@@markup": This returns the full XML markup of a node, as a string. (Full XML markup means that it also contains the markup of the child nodes, and the markup of the children of the child nodes, and so on.) The markup you get is not necessary the same as the markup in the source XML file, it's just semantically identical. Especially, note that CDATA sections will become to plain text. Also note that depending on how did you wrapped the original XML document with FreeMarker, comment or processing instruction nodes may were removed, and then they will be missing from the output of course. The first outputted start tag will contain xmlns:prefix attributes for each XML name-spaces used in the outputted XML fragment, and those prefixes will be used in the outputted element and attribute names. These prefixes will be the same as the prefixes registered with the ns_prefixes parameter of the ftl directive (no prefix will be used for D, as it will be registered as the default name-space with an xmlns attribute), or if no prefix was assigned for a XML name-space with that, then an arbitrary chosen unused prefix is used.
-
"@@nested_markup": This is similar to "@@markup", but it returns the XML markup of an element without its opening and closing tags. For the document node, it returns the same as "@@markup". For other node types (text, processing instruction, etc.), it returns an empty string. Unlike with "@@markup", no xmlns:prefix attributes will be placed into the ouput, but regarding the prefixes used in element and attribute names the rules are the same.
-
"@@text": This returns the value of all text nodes that occur within the node (all descendant text nodes, not just direct children), concatenated together into a single string. If the node has no text node children, then the result is an empty string.
-
"@@start_tag": Returns the markup of the start-tag of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that. Regarding the XML name-spaces (xmlns:prefix attributes in the output, etc.) the rules are the same as with "@@markup"
-
"@@end_tag": Returns the markup of the end-tag of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that.
-
@@attributes_markup: Returns the markup of the attributes of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that.
Node sequences
Many of the special hash keys (indicated in the above list), and XPath expressions that result in node-sets (see the XPath recommendation) return a sequence of nodes.
These node sequences, if they store exactly 1 subvariable, will also act as the subvariable itself. For example, ${book.title[0]} will do the same as ${book.title}, if there is only one title element child of element book.
Returning an empty node sequence is a normal situation. For example, if in a concrete XML document, element book has no child element chapter, then book.chapter results in an empty node sequence. Beware! This also means, that book.chaptre (note the typo) will also return empty node sequence, and will not stop with error. Also, book.chaptre?? (note the typo) will return true because the empty sequence exists, so you have to use book.chaptre[0]?? for the check.
Node sequences that store not 1 nodes (but 0 or more than 1 nodes) also support some of the hash keys described above. Namely, the following special keys are supported:
-
"elementName", "prefix:elementName"
-
"@attrName", "@prefix:attrName"
-
"@@markup", "@@nested_markup"
-
"@@text"
-
"*", "**"
-
"@@", "@*"
When you apply one of the above special keys on a node sequence that contains more than 1 or 0 nodes, then for each node in the sequence (where the special key does make sense, e.g. text nodes will be skipped for key * or @foo), the special key will be applied as it was explained for single nodes, and the results will be concatenated to form the final result. The results will be concatenated in the order as the corresponding nodes occur in the node sequence. The concatenation means string or sequence concatenation depending on the type of the results. If the special key would result in a string for a single node, then for multiple nodes the result is a single string too (the results for the single nodes concatenated), and if the special key would return a sequence for a single node, then for multiple nodes the result is a single sequence too. If there are 0 nodes in the sequence you apply the special key on, the string result is an empty string or an empty sequence respectively.
XPath expressions can be used with node sequences. However, for 0 or more than 1 nodes it will work only if you use Jaxen instead of Xalan, because of the limitations of the Xalan XPath implementation.