Use FreeMarker and parse an XML document with the
NodeModel
class. A NodeModel
is
an object that allows access to an XML document as a hierarchy of
named elements and attributes from a FreeMarker template.
NodeModel
has a public
static
method parse( )
, which
parses an XML document and returns a NodeModel
to
be added to your context Map
. The following code
parses an XML document and passes a NodeModel
to a
template:
import freemarker.template.Configuration; import freemarker.cache.ClassTemplateLoader; import freemarker.template.ObjectWrapper; import freemarker.template.Template; import freemarker.ext.dom.NodeModel; // Create a File Object for our XML data File composers = new File("composers.xml"); NodeModel nodeModel = NodeModel.parse( composers ); Map root = new HashMap( ); root.put("doc", nodeModel); // A template is processed with a Map and output is sent to a Writer. Template template = cfg.getTemplate("composerTable.ftl"); template.process(root, writer); System.out.println("output: " + writer.toString( ));
A File
object refers to an XML document, and
NodeModel.parse( )
is used to parse this document
to a NodeModel
object, which is then placed in the
root
Map
—the context with
which the FreeMarker template will be merged. The XML document
contains information about the lives of great classical composers,
and the structure of this document is shown here:
<?xml version="1.0"?> <composers> <composer> <name>Bach, Johann Sebastian</name> <born date="3/21/1685"> <location>Eisenbach</location> </born> <notes>Bach wrote intense and complex fugues.</notes> <link>http://www.bachfaq.org/</link> </composer> <composer> <name>Mozart, Wolfgang Amadeus</name> <born date="1/27/1756"> <location>Salzburg</location> </born> <notes>Wrote first symphony at age 8.</notes> <link>http://www.mozartproject.org/</link> </composer> <composer> <name>Hendrix, Jimi</name> <born date="11/27/1942"> <location>Seattle</location> </born> <notes>Hendrix set his guitar on fire in Monterey</notes> <link>http://www.jimihendrix.com/</link> </composer> </composers>
The NodeModel
object is exposed to the template as doc
, and the
#list
directive is used to iterate through each
composer
element. A reference to a child element
link
of the composer
element is
${composer.link}
, and a reference to the date
attribute of the born element is preceded by
@--${composer.born.@date}
. The FreeMarker
template, which references elements and attributes through a
NodeModel
, is:
<#list doc.composers.composer as composer> <p> <a href="${composer.link}">${composer.name}</a><br/> Born on ${composer.born.@date} in ${composer.born.location}<br/> Notes: ${composer.notes} </p> </#list>
In addition to simple access to elements and attributes, FreeMarker
also allows you to use XPath expressions if
Apache Xalan is
available on the classpath. If you have
Xalan, you can use
XPath with the same syntax you would use if you were trying to access
a map. Instead of someMap["key"]
, you would use
someElement["<XPath>"]
. Here is a quick
example, which uses an XPath expression to iterate through every
composer’s “born”
element:
<#list doc["composers/composer/born"] as birth> <p>Born: ${birth.date}, ${birth.location} ${birth?parent.name}</p> </#list>
FreeMarker also includes a number of built-ins for
NodeModel
objects; in the previous template,
?parent
returns the parent element of the element
represented by the birth
node. Table 9-4 lists a number of built-ins for XML nodes;
?children
returns all of the child nodes of a
given node, and ?ancestors
gives every node above
this node in an XML document.
Table 9-4. FreeMarker built-ins for NodeModel objects
Expression |
Evaluates to |
---|---|
|
A sequence of all child nodes. This example would return 3
|
|
If called on a |
|
This would return the |
|
If this corresponded to the link element for Jimi Hendrix, this would
return a sequence of |
|
This would return “link.” This returns the name of the element or attribute in question. |
|
This would return “element.” It
could return “attribute,”
“element,”
“text,”
“comment,”
“entity,” and a few other types
corresponding to |
For more detail about referencing XML elements through
NodeModel
and the use of XPath expressions in
FreeMarker, see the “Learning by
Example” section of Imperative XML Processing
(http://www.freemarker.org/docs/xgui_imperative_learn.html).
FreeMarker also offers syntax for declarative processing of XML—assigning macros to handle elements in an XML document. For more information about FreeMarker declarative XML processing, see the FreeMarker online documentation (http://www.freemarker.org/docs/xgui_declarative_basics.html).
18.191.60.249