Monday, January 25, 2010

GroovySql and MarkupBuilder: SQL-to-XML

I blogged previously on the ease of use of GroovySql, which is Groovy's easy-to-use JDBC-based data access approach. In another blog post, I covered the utility of OracleXMLQuery, a class which easily generates XML from an Oracle database query. This class makes it very easy, almost trivial, to convert SQL query results into XML, but a major disadvantage of OracleXMLQuery is that it is a proprietary solution. In this blog post, I demonstrate combining GroovySql with Groovy's MarkupBuilder to easily transform database data to XML.

The following script demonstrates the tremendous benefit achieved from the combination of GroovySql (and specifically the groovy.sql.Sql class) and MarkupBuilder. In this script's case, the MarkupBuilder is instantiated with its no-arguments constructor, implying that its markup output is to be written out via System.out.


#!/usr/bin/env groovy
// Be sure to include appropriate JAR with OracleDataSource class on classpath
// (or use the appropriate datasource class if using different driver)

import groovy.sql.Sql
import java.sql.SQLRecoverableException
Sql sql = null;
try
{
sql = Sql.newInstance(
"jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
}
catch (SQLRecoverableException recoverableEx)
{
println "SQLRecoverableException: ${recoverableEx}"
println "\tError Code: ${recoverableEx.getErrorCode()}"
println "\tSQL Status Code: ${recoverableEx.getSQLState()}"
System.exit(-1)
}

import groovy.xml.MarkupBuilder
def xml = new MarkupBuilder()
xml.Employees
{
sql.eachRow("select employee_id, last_name, first_name, email, phone_number from employees") { row ->
Employee
{
Id(row.employee_id)
LastName(row.last_name)
FirstName(row.first_name)
Email(row.email)
Telephone(row.phone_number)
}
}
}


When the above script is executed, XML is generated with elements featuring names provided above. A portion of the output is displayed next.


<Employees>
<Employee>
<Id>198</Id>
<LastName>OConnell</LastName>
<FirstName>Donald</FirstName>
<Email>DOCONNEL</Email>
<Telephone>650.507.9833</Telephone>
</Employee>
<Employee>
<Id>199</Id>
<LastName>Grant</LastName>
<FirstName>Douglas</FirstName>
<Email>DGRANT</Email>
<Telephone>650.507.9844</Telephone>
</Employee>

. . .

<Employee>
<Id>196</Id>
<LastName>Walsh</LastName>
<FirstName>Alana</FirstName>
<Email>AWALSH</Email>
<Telephone>650.507.9811</Telephone>
</Employee>
<Employee>
<Id>197</Id>
<LastName>Feeney</LastName>
<FirstName>Kevin</FirstName>
<Email>KFEENEY</Email>
<Telephone>650.507.9822</Telephone>
</Employee>
</Employees>


The names of these tags (Employees root tag, Employee row tag, and the individual employee elements) are exactly as specified in the Groovy code.

It is not always preferable to have the generated XML written to standard output. The next Groovy script is a slightly modified version of the above that writes the generated XML to a file whose filename is specified on the command line.


#!/usr/bin/env groovy
// Be sure to include appropriate JAR with OracleDataSource class on classpath
// (or use the appropriate datasource class if using different driver)

import groovy.sql.Sql
import java.sql.SQLRecoverableException
Sql sql = null;
try
{
sql = Sql.newInstance(
"jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
}
catch (SQLRecoverableException recoverableEx)
{
println "SQLRecoverableException: ${recoverableEx}"
println "\tError Code: ${recoverableEx.getErrorCode()}"
println "\tSQL Status Code: ${recoverableEx.getSQLState()}"
System.exit(-1)
}

import groovy.xml.MarkupBuilder
MarkupBuilder xml
if (args.length < 1)
{
xml = new MarkupBuilder() // no-arguments constructor: System.out
}
else
{
xml = new MarkupBuilder(new PrintWriter(new File(args[0])))
}

xml.Employees
{
sql.eachRow("select employee_id, last_name, first_name, email, phone_number from employees") { row ->
Employee
{
Id(row.employee_id)
LastName(row.last_name)
FirstName(row.first_name)
Email(row.email)
Telephone(row.phone_number)
}
}
}


The script immediately above writes the generated XML out to a file with the name passed in as a command-argument. If there is no command-line argument provided, the generated XML is written to System.out as was done in the first script.

The MarkupBuilder class allows the developer to specify customization beyond where the generated XML is written. Two such methods are MarkupBuilder.setOmitEmptyAttributes(boolean) and MarkupBuilder.setOmitNullAttributes(boolean). These specify whether null and empty values in the database should be written to the generated XML.


Conclusion

GroovySql and MarkupBuilder are both simple to use while at the same time being highly useful. They are especially powerful together and provide a general approach to presenting database data as XML without proprietary classes specific to any one database vendor.

No comments: