<XmlGen/>
Code generator Ant task for Velocity
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.XML file elements are referenced by their prefix in the template :
<xmlgen
... >
<xmlprop prefix="dbadmin" file="properties/dbadmin.xml" />
<xmlprop prefix="data" file="properties/data.xml" />
</xmlgen>
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 :Then the prefix references the XML fragment selected by the XPath expression. XPath expressions can also be used inside templates; this is explain later.
<xmlgen
... >
<xmlprop prefix="dbusers" file="properties/users.xml"
xpath="/dbusers/user[@id=1]" />
<xmlprop prefix="data" file="properties/data.xml" />
</xmlgen>
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 callxpath()
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 :
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.
#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>
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 withdom()
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
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 athttp://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.