http://www.developer.com/

Back to article

Developing an Eclipse BIRT XML Report Rendering Extension


March 6, 2008

BIRT Report Engine provides report rendering extensions that render a report in HTML, PDF, XLS, PostScript, and Microsoft Word and PowerPoint. In BIRT release 2.2.1, the BIRT report rendering extension API supports rendering a report in a customized format, such as XML.

This article describes a sample implementation of customized XML report rendering extension, org.eclipse.birt.report.engine.emitter.xml. The sample code creates a plug-in that writes the data contents of a report to a file in the specified format.

A rendering extension adds an emitter to the BIRT Report Engine framework by implementing the extension point, org.eclipse.birt.report.engine.emitters. The XML schema file, org.eclipse.birt.report.engine/schema/emitters.exsd, describes this extension point.

The extension point enables support for a new output format in the presentation engine. The BIRT plug-in registry uses this extension point to discover all supported output formats specified for the report engine environment.

Developing an XML Report Rendering Extension



Click here for a larger image.

Figure 1: XML report rendering extension project

The sample XML report rendering extension is a plug-in that can export BIRT report data in XML format. Typically, report developers render BIRT report data to XML to enable sharing data with another application.

The sample XML report rendering extension contains the following features:

  • Exports BIRT report data in XML format
  • The XML report rendering plug-in renders each report element and writes to the output file, <report_name>.xml.
  • Defines a public API for rendering BIRT reports in XML format

    The plug-in extends the functionality defined by the org.eclipse.birt.report.engine.emitter extension point defined in the org.eclipse.birt.report.engine plug-in.

  • Allows the user to specify an XML schema for formatting output

    During the rendering process, the sample plug-in processes all the elements in the report design, exporting XML properties and related data to the output file. Optionally, the plug-in supports mapping the report elements to an XML schema to provide additional formatting for output.

    The plug-in defines these mappings in the property file, <report_name>.xmlemitter. The plug-in reads the property file at run time and loads the custom tags.

Creating a XML Report Rendering Plug-In Project

Create a new plug-in project for the XML report rendering extension using the Eclipse PDE.

How to create the XML report rendering plug-in project

  1. From the Eclipse PDE menu, choose File→New→Project.
  2. On New Project, select Plug-in Project.
  3. In Plug-in Project, modify the settings, as shown in Table 1.
  4. Table 1: Values for Plug-in Project fields

    Section Option Value
    Plug-in Project Project name org.eclipse.birt.report.engine.emitter.xml
      Use default location Selected
      Location Not available when you select Use default location
    Project Settings Create a Java project Selected
      Source folder src
      Output folder bin
    Target Platform Eclipse version 3.3
      an OSGi framework Not selected
  5. In Plug-in Content, modify the settings, as shown in Table 2.
  6. Table 2: Values for Plug-in Content fields

    Section Option Value
    Plug-in Properties Plug-in ID org.eclipse.birt.report .engine.emitter.xml
      Plug-in Version 1.0.0
      Plug-in Name BIRT XML Emitter
      Plug-in Provider yourCompany.com or leave blank
      Classpath xmlEmitter.jar or leave blank
    Plug-in Options Generate an activator, a Java class that controls the plug-in's life cycle Selected
      Activator org.eclipse.birt.report .engine.emitter.xml.XmlPlugin
      This plug-in will make contributions to the UI Not selected
    Rich Client Application Would you like to create a rich client application? No
  7. Choose Finish.

The XML report rendering extension project appears in the Eclipse PDE workbench, as shown in Figure 1.

Defining the dependencies for the XML report rendering extension

To compile and run the XML report rendering example, you specify the org.eclipse.birt.report.engine plug-in, which must be available on the classpath for the XML rendering extension.

Declaring the emitters extension point

To implement the XML report rendering extension, specify the org.eclipse.birt.report.engine.emitters extension point and add the extension element details.

How to specify the extension point
  1. On PDE Manifest Editor, choose Extensions.
  2. In All Extensions, choose Add. New Extension—Extension Point Selection appears.
  3. In Available extension points, select the following plug-in:
  4. org.eclipse.birt.report.engine.emitters
  5. Choose Finish.
  6. In All Extensions, right-click the extension point, org.eclipse.birt.report.engine.emitters, and choose the extension element, emitter.
  7. In Extension Element Details, specify the properties for the emitter extension element, emitter, as shown in Table 3.
  8. Table 3: Property values for the emitter extension element

    Property Value
    class org.eclipse.birt.report.engine.emitter.xml. XMLReportEmitter
    format xml
    mimeType xml
    id org.eclipse.birt.report.engine.emitter.xml

Understanding the sample XML report rendering extension

The XML report rendering extension extends the report emitter interfaces and XML writer in org.eclipse.birt.report.engine.emitter. The extension example creates the XML output file in the same folder as the exported report. The output file name is the name of the report with an .XML extension. The extension example provides only limited error checking.

The following section provides a general description of the code-based extensions a developer must make to develop an XML report rendering extension after defining the plug-in framework in the Eclipse PDE.

Understanding the XML report rendering extension package

The implementation package for the XML report rendering extension example, org.eclipse.birt.report.engine.emitter.xml, contains the following classes:

  • XMLPlugin: The plug-in run-time class for the report item extension example.
  • XMLReportEmitter: Handles the start and end processing that renders the report container.
  • XMLRenderOption: Integrates the plug-in with BIRT Report Engine, specifying configuration information, including the output format as XML.
  • XMLTags.java: Defines the controls and associated property lists used when writing to the XML file.
  • XMLFileWriter: XMLWriter writes the XML version, text, image, data, label, and report tag content of the report to the XML output file.
  • LoadExportSchema: Loads the XML Schema file, if one exists, to replace the default values specified for the XML version, text, image, data, label, and report tags. An accessor method for each tag returns the value to XMLReportEmitter for output to the export file.

The following section contains more specific information about the implementation details for the classes in the XML report rendering extension package.

Understanding XMLReportEmitter

XMLReportEmitter writes the contents of the report to an XML file. XMLReportEmitter instantiates the writer and emitter objects and handles the start and end processing that renders the report container. XMLReportEmitter exports the XML version, text, image, data, label, and report tag content of the report to the XML output file.

XMLReportEmitter implements the following methods:

  • XMLReportEmitter( ) instantiates the XML report emitter class as an org.eclipse.birt.report.engine.presentation. ContentEmitterVisitor object to perform emitter operations.
  • initialize( ) performs the following operations required to create an output stream that writes the report contents to the XML file:
    • Obtains a reference to the IEmitterServices interface
    • Instantiates the file and output stream objects, using the specified settings
    • Instantiates the XML writer object
  • start( ) performs the following operations:
    • Obtains a reference to the IReportContent interface, containing accessor methods that get the interfaces to the report content emitters
    • Sets the start emitter logging level and writes to the log file
    • If an optional XML Schema file exists:
      • Locates the XML Schema file for the report
      • Instantiates a LoadExportSchema object to read the XML Schema file
    • Opens the output file, specifying the encoding scheme as UTF-8
    • Starts the XML writer
    • Writes the start tag, which specifies the <xml> tag, including the version and encoding schema, to the output file
    • Writes the <report> tag, which specifies the report name and other properties in the report property list to the output file

    Listing 1 shows the start( ) method.

    Listing 1: The start( ) method

    public void start( IReportContent report )
    {
       logger.log( Level.FINE,
          "[XMLReportEmitter] Start emitter." );
       String fileName =
          report.getDesign( ).getReportDesign( )
          .getFileName( );
       int pos = fileName.indexOf("/");
       String fn =
          fileName.substring(pos+1,fileName.length( ));
       fileName = fn;
       if (fileName.length( ) > 0) {
          pos =  fileName.lastIndexOf(".");
       if ( pos > 0 )
          fileName = fileName.substring(0, pos);
    
          fileName = fileName + ".xmlemitter";
          pos = fileName.lastIndexOf("/");
          String propFileName =
             fileName.substring( pos+1 ,
                fileName.length( ) );
          String resourceFolder =
             report.getDesign().getReportDesign( )
                .getResourceFolder( );
          if ( fileExists(resourceFolder + "/"
                + propFileName))
             exportSchema = new LoadExportSchema(
                resourceFolder + "/" + propFileName );
          else
             if ( fileExists(fileName))
             exportSchema =
                new LoadExportSchema( fileName );
          else exportSchema =
             new LoadExportSchema( "" );
       }
       this.report = report;
       writer.open( out, "UTF-8" );
       writer.startWriter( );
    
       writer.closeTag( exportSchema.getExportStartTag( ));
       writer.closeTag( XMLTags.TAG_CR );
    
       String rp = exportSchema.getExportReportTag( );
       for (int i = 0;i < XMLTags.rPropList.length;i++)
       {
          if (exportSchema.isPropertyRequired(
             XMLTags.rPropList[i], rp))
          {
             String propValue = getReportPropValue(i,report);
             rp = replaceTag( rp, "??"
                +XMLTags.rPropList[i], propValue );
          }
       }
       writer.writeCode( rp );
       writer.closeTag( XMLTags.TAG_CR );
    }
    

    end( ) performs the following operations, similar to the CSV rendering extension:

    • Sets the end report logging level and writes to the log file
    • Ends the write process and closes the XML writer
    • Closes the output file

Understanding the other XMLReportEmitter methods

The XMLReportEmitter class defines the following additional methods, called at different phases of the report generation process, that provide access to the report container, pages, tables, rows, cells text, labels, data, images, hyperlinks, and other contents. The following examples show the processing for a label.

  • startLabel( ) performs the following operations:
    • Calls LoadExportSchema.getExportLabelTag( ) to get the pattern for the <label> tag specified in the <report_name>.xmlemitter property file. If the property file does not exist, the plug-in uses the following default pattern specified in the LoadExportSchema class:
    • <label>??value</label>
    • Iterates through the following label properties list defined in XMLTags to determine the properties required by the report:
    • static String[ ] lPropList =
      {"Bookmark","Height","Hyperlink","InlineStyle",
         "Name","TOC","Width","X","Y"
      };
      
    • Calls getLabelPropValue( ) to obtain each required property value and substitute the value in the <label> tag expression.
    • Calls startText( ) and XMLFileWriter.closeTag( ) to write the <label> tag to the output file.

    Listing 2 shows the startLabel( ) method code.

    Listing 2: The startLabel( ) method

    public void startLabel( ILabelContent label )
    {
       String lbl = exportSchema.getExportLabelTag();
       int len =  XMLTags.lPropList.length;
       for (int i = 0;i < XMLTags.lPropList.length;i++)
       {
          if (exportSchema.isPropertyRequired(
             XMLTags.lPropList[i], lbl))
          {
             String propValue = getLabelPropValue(i,label);
             lbl = replaceTag( lbl, "??"+XMLTags.lPropList[i],
                propValue );
          }
       }
       startText( label, lbl );
       writer.closeTag( XMLTags.TAG_CR );
    }
    
  • startText( ) performs the following operations:
    • Sets the start text logging level and writes to the log file
    • Uses ITextContent. getText( ) to get the label text value
    • Writes the <label> tag to the output file

    Listing 3 shows the startText( ) method code.

    Listing 3: The startText( ) method

    public void startText( ITextContent text,
                           String exportTag )
    {
       logger.log( Level.FINE,
          "[XMLReportEmitter] Start text" );
       String textValue = text.getText( );
       writer.writeCode( replaceTag( exportTag,
          XMLTags.valueTag, textValue ) );
    }
    
  • getLabelPropValue( ) performs the following operations:
    • Calls the appropriate IContent accessor method to obtain the property value
    • Returns the value to startLabel( ) for substitution in the <label> tag and writing the tag to the XML output file

    Listing 4 shows the getLabelPropValue( ) method code.

    Listing 4: The getLabelPropValue( ) method

    private String getLabelPropValue( int property,
       ILabelContent label)
    {
       String propValue;
    
       switch (property) {
          case 0: // "Bookmark":
             propValue = label.getBookmark( );
             break;
          case 1: // "Height":
             if ( label.getHeight( ) != null )
                propValue
             else
                propValue = "";
             break;
          case 2: //"Hyperlink":
             if ( label.getHyperlinkAction( ) != null )
                propValue =
                   label.getHyperlinkAction( ).getHyperlink( );
             else propValue = "";
             break;
          ...
             case 8: //"Y":
                if ( label.getY( ) != null )
                   propValue = label.getY( ).toString( );
                else
                   propValue = "";
                break;
          default: propValue = "";
             break;
       }
       if ( propValue == null )
          propValue = "";
             return propValue;
    }
    

Understanding XMLTags

The XMLTags class defines the controls and associated property lists used in analyzing the report contents, substituting the tag values, and writing the tag to the XML output file, as shown in Listing 5.

Listing 5: The XMLTags class

public class XMLTags
{
   public static final String TAG_CR = "\n" ;
   static String labelControl = "label";
   static String textControl = "text";
   static String imageControl = "image";
   static String dataControl = "data";
   static String reportControl = "report";
   static String startControl = "start";
   static String endControl = "end";

   static String[] iPropList =
      {"Bookmark","Height","Hyperlink","ImageMap",
         "InlineStyle","MIMEType","Name","Style","TOC","URI",
         "Width","X","Y"};
   static String[] dPropList =
      {"Bookmark","Height","Hyperlink","InlineStyle","Name",
         "Style","TOC","Width","X","Y"};
   static String[] lPropList =
      {"Bookmark","Height","Hyperlink","InlineStyle","Name",
         "TOC","Width","X","Y"};
   static String[] tPropList =
      {"Bookmark","Height","Hyperlink","InlineStyle","Name",
         "Style","Text","TOC","Width","X","Y"}
   static String[] rPropList =
      {"TotalPages", "TOCTree", "Name"};
}

Understanding XMLFileWriter

TheXMLFileWriter class writes the closing tag, as shown in Listing 6.

Listing 6: The XMLFileWriter class

package org.eclipse.birt.report.engine.emitter.xml;

import org.eclipse.birt.report.engine.emitter.XMLWriter;

public class XMLFileWriter extends XMLWriter {

   public XMLFileWriter( )
   {
   }

   public void writeCode( String code )
   {

      super.printWriter.print( code );
   }

   public void startWriter( )
   {
   }

   public void closeTag( String tagName )
   {
      super.printWriter.print( tagName );
   }
}

Understanding XMLRenderOption

The org.eclipse.birt.report.engine.emitter.xml.XMLRenderOption class adds the XML rendering option to the BIRT Report Engine run time, as shown in Listing 7.

Listing 7: The XMLRenderOption class

package org.eclipse.birt.report.engine.emitter.xml;

import org.eclipse.birt.report.engine.api.RenderOption;

public class XMLRenderOption extends RenderOption{

   public static final String XML = "XML";
   protected  String configPath= "";

   public XMLRenderOption( ) {

   }

   public void setExportConfigFile( String config )
   {
      this.configPath = config;
   }

   public String getExportConfigFile()
   {
      return configPath;
   }
}

Understanding LoadExportSchema

The org.eclipse.birt.report.engine.emitter.xml.LoadExportSchema class optionally loads an XML Schema by performing the following operations:

  • Specifies the default substitution patterns for the XML tags
  • Calls the readSchemaFile( ) method
  • Specifies an accessor method for each tag that returns a value to XMLReportEmitter for output to the export file

Listing 8 shows the specification of the default substitution patterns for the XML tags and the constructor, which calls the readSchemaFile( ) method.

Listing 8: The LoadExportSchema class

package org.eclipse.birt.report.engine.emitter.xml;
...
public class LoadExportSchema{

   protected String fileName = "";

   protected String startTag = "<?xml version=\"1.0\"
                    encoding=\"UTF-8\"?>";
   protected String textTag = "<text>??value</text>";
   protected String imageTag = "<image>??value</image>";
   protected String dataTag = "<data>??value</data>";
   protected String labelTag = "<label>??value</label>";
   protected String endTag = "</report>";
   protected String reportTag = "<report:??name>";

   public LoadExportSchema(String fileName)
   {
      if ( fileName.length() > 0 )
      {
         this.fileName = fileName;
         readSchemaFile();
      }
   }

The readSchemaFile( ) method reads the XML Schema file, one line at a time, replacing the default values for the patterns of the XML version, text, image, data, label, and report tags with the values specified in the XML Schema file.

Listing 9 shows the code for the readSchemaFile( ) method.

Listing 9: The readSchemaFile( ) method

private void readSchemaFile()
{
   BufferedReader input = null;
   try
   {
      input = new BufferedReader(
         new FileReader(fileName) );
      String line = null; //not declared within while loop
      while (( line = input.readLine()) != null){
         int pos = line.indexOf("=");
         if ( pos > 0 )
         {
            String index = line.substring(0, pos );
            String indexTag = line.substring(pos + 1,
               line.length());
            if ( index.equalsIgnoreCase(
               XMLTags.labelControl ) )
            {
               labelTag = indexTag;
         }
         if ( index.equalsIgnoreCase( XMLTags.imageControl ) )
         {
            imageTag = indexTag;
         }
         if ( index.equalsIgnoreCase( XMLTags.dataControl ) )
         {
            dataTag = indexTag;
         }
         if ( index.equalsIgnoreCase( XMLTags.startControl ) )
         {
            startTag = indexTag;
         }
         if ( index.equalsIgnoreCase( XMLTags.endControl ) )
         {
            endTag = indexTag;
         }
         if ( index.equalsIgnoreCase( XMLTags.reportControl ) )
         {
            reportTag = indexTag;
         }
      }
      catch (FileNotFoundException ex)
      {
         ex.printStackTrace( );
      }
      catch (IOException ex)
      {
         ex.printStackTrace( );
      }
      finally
      {
         try
         {
            if (input!= null)
            {
               input.close( );
            }
         }
         catch (IOException ex)
         {
            ex.printStackTrace( );
         }
      }
}

Listing 10 shows the values of the patterns for the XML version, text, image, data, label, and report tags specified in the XML Schema file.

Listing 10: The XML Schema file

start=<?xml version="1.0" encoding="UTF-8"?>
report=<report name=??name>
label=<label name=??name hyperlink=??hyperlink>??value</label>
text=<text name=??name>??value</text>
image=<image name=??name>??value</image>
data=<data>??value</data>
end=</report>

Testing the XML report rendering plug-in

To test the XML report rendering example, create a Java application that runs a report design in an installation of the BIRT run-time engine, similar to application created to run the CSV report rendering example.

To test the XML report rendering plug-in, perform the following tasks:

  • Build the org.eclipse.birt.report.engine.emitter.xml plug-in.
  • Deploy the plug-in to the BIRT run-time engine directory.
  • Launch a run-time instance of the Eclipse PDE.
  • Create a Java application that runs the report design and writes the report's data to an XML file.
  • Create a report design containing a table that maps to a data source and data set.
  • Run the application and examine the XML in the output file.

Figure 2 shows the report design used in the XML report rendering example.

Figure 2: Report design for the XML report rendering example

Listing 11 shows the contents of the XML output file, containing XML version, text, image, data, label, and report tags for an executed report.

Listing 11: Contents of the XML output file

<?xml version="1.0" encoding="UTF-8"?>
<report name=
   C:/IANA/2007/runtime-XMLEmitter/ExecuteXMLReport/reports/
   xmlReport.rptdesign>
   <image name=>
      /9j/4AAQSkZJRgABAgEBLAEsAAD
      /4RVaRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA
      ...
      7PMv9I9nVo5cj8b7MV9zB/gh8cf/2Q==
   </image>
   <label
      name= hyperlink=http://www.actuate.com>Company Name
   </label>
   <label name= hyperlink=>Report</label>
   <label name= hyperlink=>PRODUCTNAME</label>
   <label name= hyperlink=>QUANTITYINSTOCK</label>
   <label name= hyperlink=>MSRP</label>
   <data>1969 Harley Davidson Ultimate Chopper</data>
   <data>7933</data>
   <data>95.7</data>
   <data>1952 Alpine Renault 1300</data>
   <data>7305</data>
   <data>214.3</data>
   <data>1996 Moto Guzzi 1100i</data>
   <data>6625</data>
   <data>118.94</data>
   <data>2003 Harley-Davidson Eagle Drag Bike</data>
   <data>5582</data>
   <data>193.66</data>
   ...
   <data>American Airlines: MD-11S</data>
   <data>8820</data>
   <data>74.03</data>
   <data>Boeing X-32A JSF</data>
   <data>4857</data>
   <data>49.66</data>
   <data>Pont Yacht</data>
   <data>414</data>
   <data>54.6</data>
</report>

About the Book Excerpt

This article is an excerpt from the book, Integrating and Extending BIRT, by Jason Weathersby, Don French, Tom Bondur, Jane Tatchell, and Iana Chatalbasheva, published by Addison-Wesley. The book is the second volume in a two-book series about business intelligence and reporting technology. The book introduces programmers to BIRT architecture and the reporting framework. It shows programmers how to build and deploy customized reports using scripting and BIRT APIs. It also describes how to use key extension points to create customized report items, rendering extensions for generating output other than HTML or PDF, and Open Data Access (ODA) drivers for new data sources.

About the Authors

The authors, Jason Weathersby, Iana Chatalbasheva, and Tom Bondur, are members of the extended BIRT development team and all have backgrounds in both computer science and technical writing. Collectively, they have many years experience in technical consulting, training, writing, and publishing about reporting, business intelligence tools, and database technologies.

About BIRT Exchange

Additional helpful resources related to BIRT are avaliable at BIRT Exchange http://www.birt-exchange.com, a community site for developers who need to build reporting into applications. BIRT Exchange offers downloads, online documentation, forums, and other resources that let developers share technical tips, code snippets, and ideas.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date