About XmlGen

XmlGen is an Ant Task to generate code from XML files and Velocity templates.

XmlGen makes XML nodes available to the Velocity template. You can access XML elements by name, get their attributes value, select some nodes with an XPath expression or loop on a sorted element list ... For more details, see below.

XmlGen is and extension of Velocity Texen Ant Task.

Installation

  • Install Ant http://ant.apache.org/
  • Download Velocity and add velocity libraries to Ant classpath (i.e ANT_HOME/lib)
    http://velocity.apache.org/
    (Copy velocity.jar and velocity-dep-1.5.jar to ANT_HOME/lib)
  • Install Java 1.5 If you use old Java versions you may have to install an XML parser supporting DOM and XPath (saxon,...)
  • Download XmlGen ant add xmlgen.jar to Ant classpath (i.e ANT_HOME/lib).
    http://sourceforge.net/projects/xmlgen/
    (Copy xmlgen.jar to ANT_HOME/lib)
  • Open a console, go to the "examples" directory and run "Ant test-sql" for example

Overview

Let us suppose you want to generate SQL scripts from the following XML file :

<?xml version="1.0"?>
<schema>
<table name="EMPLOYEE">
<column name="ID" type="INTEGER" />
<column name="FIRSTNAME" type="VARCHAR" size="256" />
<column name="LASTNAME" type="VARCHAR" size="256" />
<column name="AGE" type="INTEGER" />
</table>
<table name="PRODUCT">
<column name="ID" type="INTEGER" />
<column name="NAME" type="VARCHAR" size="256" />
<column name="PRICE" type="REAL" />
</table>
</schema>


1. Write the following Velocity template :

#foreach ( $table in $data.schema.tables )
CREATE TABLE $table.name
(
#foreach ( $column in $table.columns )
#if ($velocityCount != 1) , #end
   $column.name $column.type#if ($column.size)($column.size)#end
#end
)
#end

For Velocity template syntax, take a look at Velocity documentation.

2. Call the template with the following Ant task.

<target name="generate-sql">
<xmlgen 
templatePath="template"  
controlTemplate="database.vm" 
outputDirectory="output/sql/" 
outputFile="script.sql" >

<xmlprop 
prefix="data"     
file="properties/data.xml" />

 </xmlgen>

</target>


The XmlGen Ant task adds XML file to the Velocity context. XmlProp tag maps each XML file to a prefix that can be used in the velocity template.

3. The result is the following output :

CREATE TABLE EMPLOYEE
(
   ID INTEGER 
 ,    FIRSTNAME VARCHAR2(256)
 ,    LASTNAME VARCHAR2(256)
 ,    AGE INTEGER 
)
CREATE TABLE PRODUCT
(
   ID INTEGER 
 ,    NAME VARCHAR2(256)
 ,    PRICE REAL 
)

Other more advanced examples are available in the "examples" directory.

Ant build file

Before using XmlGen or XmlProp task, you have to add the xmlgen.jar to Ant classpath (i.e ANT_HOME/lib).

Then add the following typedef :

<project name="CodeGenerator" basedir=".">
<taskdef name="xmlgen"   classname="com.starobject.xmlgen.XgenTask"/>
<taskdef name="xmlprop"  classname="com.starobject.xmlgen.XgenProp"/>

...

</project>

XmlGen task

Here are the main attributes of XmlGen (taken from Texen documention) :

Attribute Description Required
templatePath Set the path where Velocity will look for templates using the file template loader. This is only required if useClasspath is not turned on. Yes
useClasspath Set the use of the classpath in locating templates. true means the classpath will be used. This is only required if templatePath is not set. Yes
useResourceLoaderCache Optional argument used when useClasspath is turned on. No
resourceLoaderModificationCheckInterval Optional argument used when useClasspath is turned on. No
controlTemplate Set the control template for the generating process Yes
outputDirectory Set the output directory. It will be created if it doesn't exist. Yes
outputFile Set the output file for the generation process. Yes
outputEncoding Set the output encoding. No
inputEncoding Set the input encoding  

As XmlGen is and extension of Texen , we invite you to look at Texen documentation to know all available features.

XmlGen contains a nested element XmlProp described here after.
XmlGen can contains multiple XmlProp tags
There is one XmlProp tag for each XML file loaded in the Velocity context.

XmlProp task

Here are the XmlProp attributes :
Attribute Description Required
prefix Prefix that is used in the Velocity template to reference the XML file. Yes
file XML file location. Relative to Ant target base directory. Yes
xpath An XPath expression to filter a part of XML file location. No

Multiple XML files

If you have more that one XML file, you can add them with multiple XmlProp tags.

<xmlgen 
... >

<xmlprop prefix="dbadmin"   file="properties/dbadmin.xml"  />
<xmlprop prefix="data"     file="properties/data.xml" />


 </xmlgen>

XML file elements are referenced by their prefix in the template :

CREATE USER $dbadmin.login.text() IDENTIFIED BY dbadmin.password.text() 
TEMPORARY TABLESPACE temp
...
#foreach ( $table in $data.schema.tables )
CREATE TABLE $table.name
(
...

XPath filters

If you need to select a part or XML file, you can add an XPath expression to the XmlProp tag :

<xmlgen 
... >

<xmlprop prefix="dbusers"   file="properties/users.xml" 
xpath="/dbusers/user[@id=1]" />
<xmlprop prefix="data"     file="properties/data.xml" />


 </xmlgen>

Then the prefix references the XML fragment selected by the XPath expression. XPath expressions can also be used inside templates; this is explain later.

Naming conventions

The XML elements can easily be accessed in the template with trivial naming conventions.

Examples refer to the following file associated to $data prefix:

<?xml version="1.0"?>
<schema>
<info db="oracle">This is a comment</info>
<table name="EMPLOYEE">
<column name="ID" type="INTEGER" />
<column name="FIRSTNAME" type="VARCHAR" size="256" />
<column name="LASTNAME" type="VARCHAR" size="256" />
<column name="AGE" type="INTEGER" />
</table>
<table name="PRODUCT">
<column name="ID" type="INTEGER" />
<column name="NAME" type="VARCHAR" size="256" />
<column name="PRICE" type="REAL" />
</table>
</schema>

  • Element

    Elements are accessed by their name : $data.schema.info

    They can be accessed from the root : $data.schema.info ...
    or in with relative path from existing element : $myschema.info

  • Attributes

    Attributes are accessed by their name : $data.schema.info.db

    They can also be relative to an element : $mycolumn.type

    If a child element has the same name as an attribute, the attribute element is appended by an "_" underscore character.
    For example : $data.schema.info.db_ if info would have a <db/> child element.

  • Element content

    Element text content is accessed with text() function : $data.schema.info.text()

  • Element list

    A list of child element with the same name can be accessed with the name of the element appended with "s" character.

    $data.schema.tables

    They can also be relative to an element : $mytable.columns

    If there is child element named like the previous reference (i.e. <tables/> , the name is appended by an "_" underscore character.
    Fore example : $data.schema.tables_ if schema would have a <tables/> child element.

XPath expressions in Velocity templates

XPath can be used inside Velocity template. You can call xpath() function on any variable refering an XML element.

Imagine you want to create a catalog of fantasy books out of a complete book catalog. That can be achieved with the following template :

#set( $fantasyBooks = $books.xpath("//book[@genre=\'Fantasy\']") )

<html>
<body>
<h1>Fantasy books library</h1>
<ul>
    #foreach ( $book in $fantasyBooks ) 
      <li>
       $book.title.text() ($book.author.text()) 
       [Published by : $book.xpath("../@name")]
      </li>
#end
</ul>
</body>
</html>

A first XPath expression select only fantasy books. A second XPath expression goes up to the publisher element to get the publisher name. See "examples" example directory for more details.

Sorting Element list

Element list can be sorted in the velocity template. By default the list is sorted on element text content but you can sort on any Xpath expression in the element. Use the prefix of the XML file followd by sort function :
  • $prefix.sort($mylist)
  • $prefix.sort($mylist,$myXpathSortCriteria)

#set( $allBooks = $books.xpath("//book") )

$books.sort($allBooks,"author/text()") 

<html>
<body>
<h1>Books library</h1>

<ul>
    #foreach ($book in $allBooks)
          <li>
       $book.title.text() ($book.author.text()) 
       [Published by : $book.xpath("../@name")]
      </li>
#end
</ul>
</body>
</html>

Access to DOM API

You can access DOM element API with dom() function.

For example to get the node name of a variable (for debug purposes for example), use the following syntax :

$table.dom().getNodeName()

Multiple output files

If you need to create multiple output files you either have to :
  • create multiple XmlGen entries in your Ant target.
  • or, use a Velocity controller as proposed in the Texen documentation
See JavaBean generation example in "examples" directory.

Debugging

For any issues, check the velocity.log file.

To know the structure of the XML data in the Velocity context, you can just print the variables. If the variable refers to an XML fragment, the corresponding XML appears in the output. (See examples/output/debug.txt)


schema.tables in data.xml :
---------------------------- 
#foreach ( $table in $data.schema.tables )
element name is : $table.dom().getNodeName()
$table

#end


xpath /dbusers/user[@id=1]  in users.xml  : 
-------------------------------------------
xml fragment is : 
$dbuser

License

This library is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.