Using XML Data Adapters

Working with XML Data Adapters

JasperReports supports data adapters for XML documents.

Creating a Node Set for an XML Document

An XML document is typically organized as a tree, and doesn't match the table-like form required by JasperReports. For this reason, you have to use an XPath expression to define a node set. The specifications of the XPath language are available at http://www.w3.org/TR/xpath. Some examples can help you understand how to define the nodes.

The XML file below is an address book in which people are grouped in categories, followed by a second list of favorite objects. In this case, you can define different node set types. First you'll need to decide how you want to organize the data in your report.

Example XML file

<addressbook>
	<category name="home">
		<person id="1">
			<lastname>Davolio</lastname>
			<firstname>Nancy</firstname>
		</person>
		<person id="2">
			<lastname>Fuller</lastname>
			<firstname>Andrew</firstname>
		</person>
		<person id="3">
			<lastname>Leverling</lastname>
		</person>	
       </category>
	<category name="work">
		<person id="4">
			<lastname>Peacock</lastname>
			<firstname>Margaret</firstname>
		</person>
	</category>
	<favorites>    
		<person id="1"/>
		<person id="3"/>
	</favorites>
</addressbook>

To select only the people contained in the categories (that is, all the people in the address book), use the following expression:

/addressbook/category/person

Four nodes are returned as shown in the following table.

Node set with expression /addressbook/category/person

<person id="1">
	<lastname>Davolio</lastname>
	<firstname>Nancy</firstname>
</person>
<person id="2">
	<lastname>Fuller</lastname>
	<firstname>Andrew</firstname>
</person>
<person id="3">
	<lastname>Leverling</lastname>
</person>
<person id="4">
	<lastname>Peacock</lastname>
	<firstname>Margaret</firstname>
</person>

If you want to select the people appearing in the favorites node, the expression to use is

/addressbook/favorites/person

Two nodes are returned.

<person id="1"/>
<person id="3"/>

Here's another expression. It's a bit more complex, but it shows all the power of the Xpath language. The idea is to select the person nodes belonging to the work category. The expression to use is the following:

/addressbook/category[@name = "work"]/person

The expression returns only one node, the one with an ID equal to 4, as shown here:

<person id="4">
	<lastname>Peacock</lastname>
	<firstname>Margaret</firstname>
</person>

Creating an XML Data Adapter

After you've created an expression to select a node set, you can create an XML data adapter.

1. Create the connection globally or locally:
To create the connection globally, right-click Data Adapters in the Repository Explorer and choose Create Data Adapter.
To create the connection local to a project, click , enter a name and location for the data adapter in the DataAdapter File dialog box, and then click Next.

The Data Adapter wizard appears (see Data Adapter Wizard).

2. From the list, select XML document to open the Data Adapter dialog.

Configuring an XML Data Adapter

3. Enter a name for your adapter.
4. XML file is the only required field. Choose an XML file or enter the URL where your XML data is located.
5. (URL only.) If you entered a URL in the XML file field, click the Options button to open the Http Connection Options dialog box.

HTTP Connection Options

In this dialog you can enter the following options:

Username and Password (optional) – The username and password to use if your XML location requires authentication.
Request Type – Select GET (default), POST, or PUT.
To add a parameter to the request URL, click Add in the URL Parameters tab. Enter the name and value of your parameters in the Parameter dialog and click OK. For multiple parameters, add each parameter separately.
For a POST request, to add parameters to the body of the POST, click Add in the POST Parameters tab. Enter the name and value of your parameters in the Parameter dialog and click OK. For multiple parameters, add each parameter separately.

When you have configured your request, click OK.

You can configure an XML data adapter to connect to a REST web service. For an example of connecting to a web service using the JSON adapter, see Connecting to a Web Service Using a JSON Data Adapter.

6. Choose whether to provide a set of nodes using a pre-defined static XPath expression, or set the XPath expression directly in the report.

We recommend using a report-defined XPath expression. This enables you to use parameters inside the XPath expression, which acts like a real query on the supplied XML data.

Optionally, you can specify Java patterns to convert dates and numbers from plain strings to more appropriate Java objects (like Date and Double). For the same purpose, you can define a specific locale and time zone to use when parsing the XML stream.

Registration of Fields for an XML Data Adapter

In addition to the type and name, the definition of a field in a report using an XML data adapter requires an expression inserted as a field description. As the data adapter aims always to be one node of the selected node set, the expressions are relative to the current node.

To select the value of an attribute of the current node, use the following syntax:

@<name attribute>

For example, to define a field that must point to the id attribute of a person (attribute id of the node person), it's sufficient to create a new field, name it, and set the description to:

@id

It's also possible to get to the child nodes of the current node. For example, if you want to refer to the lastname node, child of person, use the following syntax:

lastname

To move to the parent value of the current node (for example, to determine the category to which a person belongs), use a slightly different syntax:

ancestor::category/@name

The ancestor keyword indicates that you're referring to a parent node of the current node. Specifically, the first parent of category type, of which you want to know the value of the name attribute.

Now, let’s see everything in action. Prepare a simple report with the registered fields shown here:

Field name

Description

Type

id

@id

Integer

lastname

lastname

String

firstname

firstname

String

name of category

ancestor::category/@name

String

Jaspersoft Studio provides a visual tool to map XML nodes to report fields; to use it, open the query window and select XPath as the query language. If the active connection is a valid XML data adapter, the associated XML document is shown in a tree view. To register the fields, set the record node by right-clicking a Person node and selecting the menu item Set record node. The record nodes are displayed in bold.

Then one by one, select the nodes or attributes and select the pop-up menu item Add node as field to map them to report fields. Jaspersoft Studio determines the correct XPath expression to use and creates the fields for you. You can modify the generated field name and set a more suitable field type after the registration of the field in the report (which happens when you close the query dialog).

Insert the different fields in the Detail band. The XML file used to fill the report is that shown:

The XPath expression for the node set selection specified in the query dialog is:

/addressbook/category/person

XML Data Adapters and Subreports

A node set allows you to identify a series of nodes that represent records from a JRDataSource point of view. However, due to the tree-like nature of an XML document, it may be necessary to see other node sets that are subordinate to the main nodes.

Consider the XML in Complex XML example. This is a slightly modified version of Example XML file. For each person node, a hobbies node is added which contains a series of hobby nodes and one or more e-mail addresses.

Complex XML example

<addressbook>
	<category name="home">
		<person id="1">
			<lastname>Davolio</lastname>
			<firstname>Nancy</firstname>
			<email>davolio1@sf.net</email>
			<email>davolio2@sf.net</email>
			<hobbies> 
							<hobby>Music</hobby>
							<hobby>Sport</hobby>
			</hobbies>
		</person>
		<person id="2">
			<lastname>Fuller</lastname>
			<firstname>Andrew</firstname>
			<email>af@test.net</email>
			<email>afullera@fuller.org</email>
			<hobbies> 
							<hobby>Cinema</hobby>
							<hobby>Sport</hobby>
			</hobbies>  
		</person>
	</category>
	<category name="work">
		<person id="3">
			<lastname>Leverling</lastname>
			<email>leverling@xyz.it</email>
		</person>
		<person id="4">
			<lastname>Peacock</lastname>
			<firstname>Margaret</firstname>
			<email>margaret@foo.org</email>
			<hobbies> 
							<hobby>Food</hobby>
							<hobby>Books</hobby>
			</hobbies> 
		</person>
	</category>
	<favorites>
		<person id="1"/>
		<person id="3"/>
	</favorites>
</addressbook>

What we want to produce is a document that is more elaborate than those you have seen so far. For each person, we want to present their e-mail addresses, hobbies, and favorite people.

You can create this document using subreports. You'll need a subreport for the e-mail address list, one for hobbies, and one for favorite people (that is a set of nodes out of the scope of the XPath query we used). To generate these subreports, you need to understand how to produce new data sources to feed them. In this case, you'll use the JRXmlDataSource, which exposes two extremely useful methods:

public JRXmlDataSource dataSource(String selectExpression)

public JRXmlDataSource subDataSource(String selectExpression)

The first method processes the expression by applying it to the whole document, starting from the actual root. The second assumes the current node is the root.

Both methods can be used in the data source expression of a subreport element to dynamically produce the data source to pass to the element. The most important thing to note is that this mechanism allows you to make both the data source production and the expression of node selection dynamic.

The expression to create the data source that feeds the subreport of the e-mail addresses is:

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

This code returns all the e-mail nodes that descend directly from the present node (person).

The expression for the hobbies subreport is similar, except for the node selection:

((net.sf.jasperreports.engine.data.JRXmlDataSource)

$P{REPORT_DATA_SOURCE}).subDataSource("/person/hobbies/hobby")

Next, declare the master report’s fields. In the subreport, you have to refer to the current node value, so the field expression is simply a dot (.),

Proceed with building your three reports: xml_addressbook.jasper, xml_addresses.jasper, and xml_hobbies.jasper.

In the master report, xml_addressbook.jrxml, insert a group named “Name of category,” in which you associate the expression for the category field ($F{name of category}). In the header band for Name of category, insert a field to display the category name. By doing this, the names of the people are grouped by category (as in the XML file).

In the Detail band, position the id, lastname, and firstname fields. Below these fields, add the two Subreport elements, the first for the e-mail addresses, the second for the hobbies.

The e-mail and hobby subreports are identical except for the name of the field in each one. The two reports should be as large as the Subreport elements in the master report, so remove the margins and set the report width accordingly.

Preview both the subreports just to compile them and generate the relative .jasper files. Jaspersoft Studio returns an error during the fill process, but that's expected. We haven't set an Xpath query, so JasperReports can't get any data. You can resolve the problem by setting a simple Xpath query (it isn't used in the final report), or you can preview the subreport using the empty data adapter (select it from the drop-down in the tool bar).

When the subreports are done, execute the master report. If everything is okay, the report groups people by home and work categories and the subreports associated with each person.

As this example demonstrates, the real power of the XML data adapter is the versatility of XPath, which allows navigation of the node selection in a refined manner.

Version: 
Feedback
randomness