Apr 7 2008

Pretty-printing formatted XML in ColdFusion via JDOM

Posted by Joe Rinehart at 12:49 PM
6 comments
- Categories: ColdFusion MX

Over the weekend I was working on parts of MG3 that generate some XML. When I used ColdFusion's toString(xmlDocument) to print back out the application's main ModelGlue.xml file, I completely forgot that doing so strips it of all comments and formatting. Yikes!

I dug around for a bit and found that the JDOM library shipped with ColdFusion provides a utility for pretty-printing XML, and wrapped it up in the following UDF:

<cffunction name="prettyXML" output="false">
   <cfargument name="filename" type="string" hint="Filename of XML document to pretty-print." />
   <cfargument name="destination" type="string" hint="Filename for output." default="#arguments.filename#" />
   
   <cfset var fileObj = "" />
   <cfset var builder = "" />
   <cfset var format = "" />
   <cfset var out = "" />
   <cfset var document = "" />
   <cfset var fileInStream = "" />
   <cfset var fileOutStream = "" />
   
   <cfset fileObj = createObject("java", "java.io.File").init(filename) />
   <cfset builder = createObject("java", "org.jdom.input.SAXBuilder").init() />
   <cfset format = createObject("java", "org.jdom.output.Format").getPrettyFormat() />
   <!--- Use tabs instead of two spaces --->
   <cfset format.setIndent("   ") />
   <cfset out = createObject("java", "org.jdom.output.XMLOutputter").init(format) />
   <cfset fileInStream = createObject("java", "java.io.FileInputStream").init(fileObj) />
   
   <cfset document = builder.build(fileInStream) />
   
   <cfset fileInStream.close() />
   
   <cfset fileObj = createObject("java", "java.io.File").init(destination) />

   <cfset fileOutStream = createObject("java", "java.io.FileOutputStream").init(fileObj) />
   
   <cfset out.output(document, fileOutStream) />

   <cfset fileOutStream.close() />
</cffunction>

Below is an example of its input and output:

Input

<!-- Ugly XML --><root><child attrib="value"></child></root>

Output

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ugly XML -->
<root>
   <child attrib="value" />
</root>

Comments

John Allen

John Allen wrote on 04/07/08 1:26 PM

Ohhhhhhhh I wish i had that code 4 months ago.

That is SLICK.
Joe Rinehart

Joe Rinehart wrote on 04/07/08 2:47 PM

Thanks John!

Scott (Stroz) and I figured out one drawback: it requires the jdom JAR version that's in CF8. Guess I'll be CF8-only for this feature for the MG3 alpha...
Don L

Don L wrote on 04/10/08 4:45 PM

I figured out how to make this work with MX 7. Seems the jdom that ships with 7 is 1.0 beta 9 and the format object was either missing or incomplete. The solution is to modify the UDF in the following manner :

1. get rid of the format object and change call for XMLOutputter.init() to NOT pass anything in.

2. Add the following lines after you create your 'out' object :

&lt;cfset out.setTextTrim(true) /&gt;
    &lt;cfset out.setIndent(&quot; &quot;) /&gt;
    &lt;cfset out.setNewLines(true) /&gt;

That's it, everything else should remain unchanged...
Kevin K

Kevin K wrote on 04/16/08 12:20 PM

Is there a way to use this just with memory variables for screen display?

Let's say I have a CF XML object in memory and just want to have it nicely formatted as indented XML on screen.
Jay McEntire

Jay McEntire wrote on 05/06/08 6:13 PM

Side note: The now openBD (http://openbluedragon.org) doesn't have the jdom included. You can download it from http://www.jdom.org/ and build the package and stick it in you lob directory. Works great.
Kevin Hoyt

Kevin Hoyt wrote on 12/17/08 4:40 PM

Using the underlying Java objects that are included with CF makes for a real treat. Earlier in the week I ran across Ben Nadel's POI wrapper for Excel documents (POI is included with CF8). Now using JDOM for pretty formatting! Life is good.

To Kevin K who wanted to format just a string, I had the same desire, so I changed the reader to be a StringReader. The XMLOutputter object then has an outputString() method that takes the document object and returns a string all pretty formatted.

Not sure the comments will hold the code, but worth a try:

   <cfset builder = CreateObject( "java", "org.jdom.input.SAXBuilder" ).init() />
   <cfset reader = CreateObject( "java", "java.io.StringReader" ).init( JavaCast( "string", xml ) ) />
   <cfset document = builder.build( reader ) />

   <cfset format = CreateObject( "java", "org.jdom.output.Format" ).getPrettyFormat() />
   <cfset out = CreateObject( "java", "org.jdom.output.XMLOutputter" ).init( format ) />

   <cfreturn out.outputString( document ) />

Write your comment



(it will not be displayed)