On this page, we'll show how to create XML documents using the frameworks special XML template engine. You are certainly free to use the standard Groovy XML template engine instead. However, in this case you should follow the instructions on plain text templates, because it's much the same, apart from the fact that your text document contains XML tags.
Again, let's start with an example:
<registryObjects xmlns:gsp='http://namespaces.csutils.sf.net/groovy/xml/XmlTemplateEngine' xmlns='http://namespaces.csutils.sf.net/groovy/demo'> <gsp:scriptlet> queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o").eachWithIndex{ it, i -> </gsp:scriptlet> <row> <number>${i}</number> <columns> <gsp:scriptlet> it.eachWithIndex{ jt, j -> </gsp:scriptlet> <column> <number>${j}</number> <class>${jt.objectType().value()}</class> <name>${jt.name()}</name> <gsp:scriptlet> if (jt.objectType().value() == "{SomeNamespace}ROUser") { </gsp:scriptlet> <responsibleFor>${jt.ResponsibleFor.name()}</responsibleFor> <gsp:scriptlet> } </gsp:scriptlet> </column> <gsp:scriptlet> } </gsp:scriptlet> </columns> </row> <gsp:scriptlet> } </gsp:scriptlet> </registryObjects>
If you have read the example from the page on plain text templates, this is basically much the same - apart from the fact, that this is well formed XML. In particular, you should be able to use any XML editor for creating the template. Here's how the output could look like:
<registryObjects xmlns="http://namespaces.csutils.sf.net/groovy/demo"> <row> <number>0</number> <columns> <column> <number>0</number> <class>{SomeNamespace}ROUser</class> <name>SomeUser</name> <responsibleFor>SomeOrg</responsibleFor> </column> <column> <number>1</number> <class>{SomeNamespace}ROOrg</class> <name>SomeOrg</name> </column> </columns> </row> </registryObjects>
Have a look at the following snippet from the template:
<gsp:scriptlet> queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o") </gsp:scriptlet>
This is a so-called scriptlet. A scriptlet contains embedded Groovy source code. Basically, the template engine iterates over the template contents. Simple XML tags or text is just copied, but scriptlets are executed when they are encountered by the template engine.
The example runs a query, which performs a JOIN over multiple object types. Keep in mind, that such queries are returning a list of rows: Each of the rows contains an array of registry objects. This is why we use the method queryEngine.queryArray: Otherwise, we'd use queryEngine.query.
As you might have noticed, we have intentionally shortened the scriptlet in the previous section. Actually, the scriptlet was
<gsp:scriptlet> queryEngine.queryArray("FROM ROUser u JOIN u.ResponsibleFor o").eachWithIndex{ it, i -> </gsp:scriptlet>
Recall, that the query returns a list of rows. The Groovy instruction eachWithIndex iterates over these rows. For any iteration, it assigns the row to the variable it, and the row number to the variable i. We are using the latter variable in the following snippet:
<row> <number>${i}</number> <columns> ... </columns> </row>
If you look into the output, then you should notice that the query returned a single row with number 0.
But there's another loop: The rows returned by the queries are in fact arrays of registry object. We iterate over these registry objects in the inner loop.
<gsp:scriptlet> it.eachWithIndex{ jt, j -> </gsp:scriptlet> ... <gsp:scriptlet> } </gsp:scriptlet>
For any registry object in the row, a variable jt, and a variable j are created, and the following snippet is entered:
<column> <number>${j}</number> <class>${jt.objectType().value()}</class> <name>${jt.name()}</name> ... </column>
The snippets output would look like this:
<column> <number>0</number> <class>{SomeNamespace}ROUser</class> <name>SomeUser</name> ... </column>
In other words, the initial sample output shows you, that row number 0 contained two registry objects.
We have already noticed simple examples of interpolation: The snippets ${i}, and ${\j} have been used to emit the row, and column number, respectively. But interpolation can be quite complex, as the next snippet shows us: ${jt.objectType().value()} would invoke the method objectType() on the registry object jt, then the method value() on the object type.
It is more than likely, that you'd sooner or later like to enable or disable certain parts of the template. Conditional evaluation allows you to do just that:
<gsp:scriptlet> if (jt.objectType().value() == "{SomeNamespace}ROUser") { </gsp:scriptlet> <responsibleFor>${jt.ResponsibleFor.name()}</responsibleFor> <gsp:scriptlet> } </gsp:scriptlet>
As you can see in the output, the text snippet is enabled for Object #0, because it is an instance of {SomeNamespace}ROUser, but not for Object #1, which is an instance of {SomeNamespace}ROUser.
To create an element dynamically, use something like the following:
<gsp:scriptlet> if (b == 'xyz') { c = 'p:x1' } else { c = 'p:x2 } </gsp:scriptlet> <gsp:element gsp:name="${c}" xmlns:p='SomeNamespace' name="MyName" value="MyValue"> ... </gsp:element>
Assuming that the value of b is xyz, this would produce output like the following:
<p:x1 xmlns:p='SomeNamespace' name="MyName" value="MyValue"> ... </p:x1>
Attributes can be created quite similarly:
<column> <gsp:attribute name="foo" value="bar"/> </column>
The output would be:
<column foo="bar"> </column>
Note: Dynamic attributes can only be created immediately after the start of an element. (White space, comments, or scriptlets are allowed in between.) In other words, the following example would be invalid:
<column> Some Text <gsp:attribute name="foo" value="bar"/> </column>
The template engine provides a number of predefined variables:
Variable name | Description |
---|---|
groovyMetaModel | The frameworks meta model, an instance of GroovyMetaModel. |
queryEngine | The query engine, an instance of QueryEngine. |
registryFacade | The registry facade, an instance of RegistryFacade. |
registryMetaModel | The registry meta model, an instance of ROMetaModel. |