Wiki Spaces


Get Help from Others

Q&A: Ask OpenMRS
Discussion: OpenMRS Talk
Real-Time: IRC Chat | Slack


Page tree
Skip to end of metadata
Go to start of metadata


This documentation refers to a deprecated feature in the reportingcompatibility module. The ?replacement for this feature would be creating a Period Indicator report in the Reporting Module. See the screencast tutorials for documentation.


The Report Template Module allows the indicators for reports to be calculated in OpenMRS using data extracted by custom Cohort Builder (provided by the ?ReportingCompatibility Module) searches as defined by an xml document. These indicators can be viewed in list form by a web viewer. With an additional module, fully formatted reports can be exported from OpenMRS in multiple formats.

The entire process of building a report requires multiple steps:

  1. Write a report schema xml file which uses macros to describe the report indicators
  2. Define the macros in a java properties file which utilizes generic OpenMRS searches
  3. Define the generic searches in the OpenMRS Cohort Builder
  4. If exporting a formatted report using the add on module, create a report template in the desired format

All of the different elements created in these steps are very interrelated and the boundaries between their functions are flexible. Building a report requires a thorough understanding of the different elements and an overall plan for how they go together.

Below we’ll create a simple example report that breaks down a patient population by age and gender. We'll walk through the process of creating the different elements step by step and at the end we’ll explain our recommendations for best practice in terms of how to draw lines between the functionality of the different elements. Here is the sample report

Report Schema XML

The xml file is a high level outline which sets report parameters and lists the report's indicators. To define the indicators, we use cohort builder searches or custom macros which we will define later.

The report parameters are the first thing we need to set. In the sample report, the parameters are report start date and end date. The syntax for defining these is as follows:

&nbsp;<parameter clazz="java.util.Date">
&nbsp;&nbsp;&nbsp; <name>report.startDate</name>
&nbsp; &nbsp; <label>When does the report period start?</label>
&nbsp; </parameter>
&nbsp; <parameter clazz="java.util.Date">
&nbsp;&nbsp;&nbsp; <name>report.endDate</name>
&nbsp; &nbsp; <label>When does the report period end?</label>
&nbsp; </parameter>

The first indicator we want to define is the total number of male patients. Each indicator requires a unique name. We'll call this indicator “male_total". The syntax for this is shown below. [male] is the name of a simple saved cohort builder search that we’ll create later.


More complex indicators can be met by using macros. To create an indicator for all patients who are children at the end of the reporting period, we can create a macro called [ChildAtEnd]. We will be creating all of our macros later.


Boolean expressions within the XML

Searches can be combined with boolean expressions as shown below.

<specification>[male] and [ChildAtEnd]</specification>

Note: When creating complex boolean expressions in your xml document with both 'ands' and 'ors', it's very important to use proper parenthesis to make sure you get the result you're looking for. (i.e. A and (B or C) can be very different from (A and B) or C))



Macros define complex report indicators by combining multiple cohort builder searches with multiple conditions. It’s important to note at this point that the xml file does not necessarily need to use macros. The macros will be exploded into the final xml final anyway, so we could conceivably just write everything out using the full syntax of the cohort builder searches.

Macros, however, offer the distinct advantage of taking the complexity out of the xml file making it a lot shorter and more understandable. The macros can be used many times in a single report or conceivably in multiple different reports. So, if you decide you want to change the way you determine a particular indicator, you only have to change the macro definition once.

The macros are defined in a document within the reporting framework (/openmrs/admin/reports/reportMacros.form).

At the start of the macro document, define the macro suffix and prefix:


The syntax to create the macro  (ChildAtEnd) is as follows:


ChildOnDate is a Cohort Builder search which looks for all patients under the age of 15 without a specified date. We define the timespan we’re looking for by assigning the endDate parameter to the search variable “effectiveDate” and passing it to the search. We will create all of our searches later.

For more complex searches with multiple parameters, simply delineate the parameters with vertical slashes. Here is an alternative macro for ChildOnDate which uses a search called CertainAgeOnDate which has multiple parameters.


You must use the defined prefix and suffix to refer to your macros in the schema (in this example @@ instead of []):

<specification> (ChildAndEnd) and [MaybeSomeNormalParameter]</specification>



Complex Macros

Macros can contain boolean expressions. For instance, instead of having two searches for [Male] and [ChildAtEnd], they could be combined in a macro:
MaleChildAtEnd=([Male] and [CertainAgeOnDate|effectiveDate=${report.endDate}| MaxAge=14]) |

Macros can also be written to refer to other macros. At the start of the macro file, call out the macro suffix and prefix:


MaleChildAtEnd=(  (Male) and   (ChildAtEnd))

Then, within a macro, you can call out another macro:

Note: It's very important to surround each macro expression utilizing booleans with parenthesis. This is because the macros will be brought into the Report Schema XML and may be again combined with booleans.

Cohort Builder Search

Cohort builder searches can be created directly in the Cohort Builder (link is the main gutter on top of every OpenMRS page). Simply define the search you want and name it whatever you’ve called out in the macro & xml files.

(screen shots)

Best Practice

Even from this simple example, it should be clear that there is a lot of flexibility in how the xml file, the macro file and the cohort builder searches are constructed.

What we think makes the most sense is to write both the xml file and the cohort searches as generically as possible and to put all of the complexity into the macros. This way, if different health programs use common reports, the report templates and xml files can potentially be shared even if different indicators are used to create the data.

Also, by making cohort searches more generic, they can be reused for multiple macros in multiple reports. This will limit the number of different searches and help eliminate duplication.

So why aren’t we following our recommended best practice in our example?? We’re using the search [ChildOnDate] which has a fixed parameter of maxAge=14. This is not as generic as [CertainAgeOnDate] which has no fixed parameters. If we were to use [CertainAgeOnDate], we could pass both the date and the age as variable parameters and then use this same search for both children and adults.

The reason we did not do it this way in the example is because you cannot create a completely parameter-free search with cohort builder through the OpenMRS interface. You need to take the extra step of writing a java file which creates this search. Here is an example of the syntax needed for this kind of file:

if (Context.getReportService().getPatientSearch("CertainAgeOnDate") == null) {
  System.out.println("Creating CertainAgeOnDate...");
  PatientSearch ps = PatientSearch.createFilterSearch(PatientCharacteristicFilter.class);
  ps.addArgument("minAge", "$(age)", Integer.class);
  ps.addArgument("maxAge", "$(age)", Integer.class);
  ps.addArgument("effectiveDate", "${date}", Date.class);
  Context.getReportService().createReportObject(new PatientSearchReportObject("CertainAgeOnDate", ps));

Although the creation of this example report has been presented sequentially, obviously you can’t write the xml or the macros without being very familiar with what searches you want to use and what parameters need to be passed to these searches. Realistically, there will need to be a lot of back and forth and the xml, macros and searches. You will most likely need to create all three elements simultaneously.

Report Template

Now that the indicators are completed, the last step towards creating an actual report is to export the data in the desired format. This is not part of the OpenMRS core - it requires an additional reporting module. Right now, this module can export the data as a text file, a pdf or an excel file.

Create the titles and outlines of the report in the desired format. Insert the uniquely named indicator numbers where the data should be with an expression prefix and postfix that does not appear elsewhere in the report. In this case we’re making and excel template and using an expression prefix and postfix of “#”.


Adding the Report to OpenMRS

Go to the Administration page. Under the "Hackathon Report Refactoring" section, select the “Manager Reports" link.

From there, select the “Add a New Report Schema XML” link. In the text box, paste your report schema XML, scroll down and hit save.

Now select the "Manage Report Macros" link. In the text box, paste your macros, scroll down and hit save.

Next, select “Upload new Template File” and upload your template file.

(feature and screen shot to come)

Since we’re using an Excel Template, from the next dropdown box select org.openmrs.module.reporttemplate.renderer.ExcelTemplateRenderer. Other options include text and pdf exports. For and expression prefix & postfix, enter the expression prefix and postfixes you used in your report template (# in our example).

To run the report, select the "Run Reports" link.

More Examples

Here are the files for the HAHPCO report used in Lesotho (a much more complicated example).