Saturday, November 8, 2008

Jasper Reports and legacy formats

I'm not sure when exactly or between which versions, but at some point Jasper Report designs moved from being based on legacy DTD to the more modern XSD schema. It turns out that most tools today, i.e. the iReport plugin for NetBeans, are now overwriting the DTD information of legacy designs in favor of XSD information.
This can cause problems if and when you are not able to change the Jasper engine itself that fills out the template designs. It also did not seem possible to simply plug-in another XML parser and I found it rather hard in general to find information about this and support forums to turn to. So I sought another solution.

If you try to run an XSD based design against the Jasper engine that can only deal with DTD, you will get an error along the line of this:

net.sf.jasperreports.engine.JRException: org.xml.sax.SAXParseException: Document root element "jasperReport", must match DOCTYPE root "null".


By using a legacy designer which favors DTD's (iReport 3.0 standalone) and the recent NetBeans plugin which favors XSD's, it becomes apparent what the exact differences are. Obviously the DTD version has a doctype clause:

<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">


Furthermore, the jasperReport root element has the extra attributtes:

xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd


One could just edit the files manually, but seriously, what fun is that. Instead, we can create a decorator to perform this job on-the-fly as we send the design off to the Jasper engine to be compiled. We would need to do the following:
  1. Read the InputStream into a DOM tree
  2. Add the missing DTD doctype
  3. Remove the undesired attributtes
  4. Write the dom back out to an InputStream
The result of doing the above I've placed in LegacyJasperInputStream.java.

An example on how to use it:


JasperDesign design = JRXmlLoader.load(
       
new LegacyJasperInputStream(new FileInputStream("MyXsdBasedDesign.jrxml"))
       
);



Probably I am not the only one facing this issue, which is why I chose to write a small entry about it and hopefully helping others. Be advised, you're going to need the slf4j logging facility, or modify the source slightly to make use of the standard java.util.Logger.

14 comments:

Francisco said...

Wow.. Thx a lot.. your code is so usefull Thx!

Chad R said...

Can you please change this from GPL to LGPL?

Casper Bang said...

Sure Chad, there's no reason for it to be GPL strict. It's now LGPL.

Nathalie Roman said...

Hi Casper,

Thanks a lot for your post, it was very useful and the only answer we could find.

Waseem Raja said...

Hello
I was working in Openbravo using IReports. I have followed all the steps using manual or help in wiki.openbravo etc. I compiled after creation a report but the following error message was found when i tried to run it in Openbravo.....
org.xml.sax.SAXParseException Document root element jasperReport, must match DOCTYPE root null.


Will someone help me plz to get rid of this error....Plz

Regards
Waseem Raja

bmj said...

thx a lot

Anonymous said...

Interesting solution; but there is a solution if you use iReport (at least in version 3.6.0); in the option menu, in the general tab, there a compatibility tab, which you can set it back to an earlier version.

Raza said...

i used your above code but still getting the same error.
any help will be appreciated.
thanx

Casper Bang said...

Sorry Raza, but without more specific information it's hard for me to help. Have you tried what Anonymous suggests, apparenly the later versions of iReport has a compatibility setting to get rid of this issue.

gash said...

I have the same error. I am using creating a report for openbravo. I've been using jasperreports 3.0.0 and the report does not show in openbravo. I used v3.7.1 and saved the report as an earlier version but I still have an error - the page doesn't show. It calls a database error - but there are no erros in my logs.

cud I share the .jrxml? It has to be something on this page.

kazenofairy said...

Thank you so much. I am new to JasperReports and this helped me to solve this problem.

Javier Borja said...

Thank you for your code It helped me a lot. It's really useful.

IKantIK said...

Thx a lot! Saved my day!

Bay said...

thx so match
very helpfulll