Lists in Jaspersoft Studio

Overview

We already saw that, in some cases, a subreport is needed to print particular information of a record (see the tutorial Subreports in Jaspersoft Studio). In general we can say that, in the case where we need to print a record, and a list of information related with that record, we have two options: subreports or lists. Suppose you have an XML data source where you have the tag "Person" with the details of a person (name, surname, address...) and one or more subtags "phone", where the content of every phone tag is a telephone number of that person.

The goal is to print a person and all the telephone numbers associated with him or her.

Datasource Reference

To follow this example, we suggest using the following data source:

<addressbook>
    <lastupdate>2009-10-31</lastupdate>
        <person>
            <name>ETHAN</name>
            <phone type="mobile">+1 (415) 111-1111</phone>
            <phone type="home">+1 (415) 111-1112</phone>
            <phone type="work">+1 (415) 111-1113</phone>
            <phone type="fax">+1 (415) 111-1114</phone>
        </person>
        <person>
            <name>CALEB</name>
            <phone type="mobile">+1 (415) 222-2222</phone>
            <phone type="home">+1 (415) 222-2223</phone>
        </person>
        <person>
            <name>WILLIAM</name>
            <phone type="work">+1 (415) 333-3333</phone>
            <phone type="mobile">+1 (415) 333-3334</phone>
        </person>
</addressbook>

You can copy and paste this text into a text file and save it as "PhoneList.xml" or you can download it directly from HERE.

Create the Report

Start a new report by selecting File > New > Jasper Report, use the template Tree and give it the name PhoneBook. When you are in the data source selection step of the wizard, click the button New, select XML document and click Next. Now you have to configure an XML data adapter. Use these parameters:

And click Finish.

You then return to the step in the wizard where you have to select the data adapter. The new adapter should be selected.

Next, you have to provide a XPath query to locate the fields. Since we want to print the Person, double-click on the item person to generate to following query:

/addressbook/person

And click Next.

In the next step, the fields are listed, but this time it is a little bit different from the previous tutorials: the field name is present but you can have two or four phone fields.

The number of fields depends on the record selected in the previous step, which was used to discover the fields. The first record has four phone numbers and the other records only two. The point is that we can't directly add the phone fields to the report, becasue we don't know how many there are. This is why we need a sub-dataset and a list.

For now, add only the field name to the report by double-clicking on the field name and clicking Next. In the next step, click Next and then Finish. At this point you have a report that prints only the names of the people stored in the XML.

Adding the Phone Numbers

In order to display the list of numbers, we need to create a sub-dataset starting from the person node. The main dataset works on the person nodes, while the sub-dataset processes all the phone tags of a specific person node.

The first step is to create the new list. So drag it from the Palette into the Detail band to launch the wizard. Here you can create a new dataset or use an existing one. In our case, since we don't have any other datasets to use, we must select the first option and then click Next.

Next, provide a name for the new dataset, for example PhonesDataset.

Select the option Create an empty dataset, and click Next. The idea is to use an empty dataset that is filled every time with the phone numbers of the currently printed record in the master report (we can do this using an expression).

In the next step, leave the default option selected, Use the same connection to fill the master report and click Finish.

Now you have created your list and its dataset, and you can see this in the Outline view. The first thing to do now is define how the dataset is filled. Select the list element from the Outline view: in the Property tab, go to the tab Dataset, select the option Use a JRDatasource expression, and then insert this expression:

$P{REPORT_DATA_SOURCE}.subDataSource("/person/phone") ---->It will result errors while compiling. One has to type cast explicitely as follow:

((net.sf.jasperreports.engine.data.JRXmlDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("/person/phone")

This line of code is very important. The syntax $P{} is used to reference a parameter object. In this case it is, REPORT_DATA_SOURCE, which is a built-in parameter that contains the data source used to fill the main dataset.

The data source in this case is an instance of JRXmlDatasource which provides two methods to work with sub-datasets: subDataSource() and dataSource(). Both are arguments in an xpath expression. In our case, the subDataSource method is what we need to explore the XML tree under the person node. In particular, the data source will use all the phone nodes that are children of the person node as the record node.

Now we need to add the fields to the dataset created with the list. Expanding "PhonesDataset", you can see that the item "Fields" hasn't children. This is because, when we created the list, we have used an empty dataset, so it was not possible discover any field.

For this reason we must add them manually. Right-click on the item "Fields" of "PhonesDataset" and select "Create Field". Repeat this twice.

The PhonesDataset now has two fields, "Field_1" and "Field_2". But, we must define how these fields are valorized and insert them in the list. So double click on the list element in the designer and a new tab will be opened.

First, we will set the valorization of the fields. From the outline view, expand "PhoneDataset" and its child "Fields" and you can see the two fields created before.

Select them, one at a time, and you can see that, in the property tab, there is a field "Description" where we can put an XPath expression to extract the tag values:

  1. For the "Field_1" use as Description "@type", to extract the value of the attribute "type" of the current node.
  2. For the "Filed_2" use as Description "child::text()", to extract the text value of the current node.

Now the new fields are ready to be used. Drag them from the outline into the designer. A window appears asking if you want use a calculation function. Since we don't need to, select Nothing and click Finish.

Arrange the layout so it is similar to the following image, then go back to the main report.

Now, arrange the list element and the detail band as in the following image:

Now switch to the Preview tab to compile the report. You should see this result:

note:

the dataset of the list should be "((net.sf.jasperreports.engine.data.JRXmlDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("/person/phone")", other than "$P{REPORT_DATA_SOURCE}.subDataSource("/person/phone")".

notice the ")" before ".subDataSource..."

Feedback
randomness