Apr 7 2008

Pretty-printing formatted XML in ColdFusion via JDOM

Posted by Joe Rinehart at 12:49 PM
7 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.
chala

chala wrote on 09/29/08 2:13 AM

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 :
http://www.batteryfast.co.uk/dell/312-0079-2.php NEW Battery fit Dell Inspiron 5150 5160 1100 1150 5100 laptop battery,
http://www.batteryfast.co.uk/dell/e1505.php NEW DELL INSPIRON 6400 E1505 1501 85 WHr 9 BATTERY laptop battery,
http://www.batteryfast.co.uk/dell/6400.php NEW DELL INSPIRON 6400 E1505 1501 85 WHr 9 BATTERY laptop battery,
http://www.batteryfast.co.uk/dell/312-0335.php New GENUINE 8-Cell Dell Inspiron 1000 1200 2200 Battery laptop battery,
http://www.batteryfast.co.uk/dell/312-0451.php New Dell Inspiron M140 640m 630m E1405 laptop battery,
http://www.batteryfast.co.uk/dell/d820.php New Dell Precision m65 D820 Battery HICAPACITY 312-039 laptop battery,

http://www.batteryfast.co.uk/dell/w1605.php Battery for DELL Latitude D500 D600 Inspiron 500m 600m laptop battery,
http://www.batteryfast.co.uk/dell/312-0009.php DELL INSPIRON 8000 8100 8200 BATTERY 75UYF 66WHR 1691P laptop battery,
http://www.batteryfast.co.uk/dell/0u003.php NEW Laptop Battery For Dell Latitude D400 9T119 312-009 laptop battery,
http://www.batteryfast.co.uk/hp/dv9000.php New OEM HP HSTNN-LB33 dv9000 DV9000 dv9600 laptop battery,
http://www.batteryfast.co.uk/hp/f2024.php Battery For HP XE3 XE3B XE3C XE3L F2024 F2024B laptop battery,
http://www.batteryfast.co.uk/hp/hstnn-c16c.php Battery fits HP Pavilion DV8000 DV8100 DV8200 laptop battery,

http://www.batteryfast.co.uk/hp/364602-001.php New Battery For Compaq NX6120 NC6100 NC6120 NX6100 NC6200 laptop battery,
http://www.batteryfast.co.uk/hp/320912-001.php HP Compaq Battery for NC8200 nc8230 7400 laptop battery,
http://www.batteryfast.co.uk/hp/nc6000.php battery for Compaq/HP NX5000 NC6000 NC8000 DG105A 4.4A laptop battery,
http://www.batteryfast.co.uk/hp/b1800.php CAOMPQA HP B1800 Series W22044LB laptop battery,
http://www.batteryfast.co.uk/hp/b2000.php compaq hp Presario B2000 HSTNN-B071 Batteries laptop battery,
http://www.batteryfast.co.uk/hp/dv6000.php New OEM HP HSTNN-DB42 DV2000 DV6000 V3000 V6000 laptop battery,
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)