Archive

Posts Tagged ‘JRXmlDataSource’

Reporte maestro-detalle usando JRXMLDatasource de JasperReports 3.1.2

March 26th, 2009
Comments Off

Introducción

Este es un ejemplo de como realizar un reporte maestro detalle usando JasperReports.
Vamos a generar un simple pdf con el detalle de una factura(Invoice).
También pueden ver Como usar el JRXmlDataSource de JasperReports 3.1.2, para una introducción al JRXmlDataSource.

Archivo XML de datos

bueno, esta es la parte mas simple. :)

(invoice.xml)

<?xml version="1.0" encoding="UTF-8"?>
 
<invoice>
    <invoiceNumber>BP-0123</invoiceNumber>
    <invoiceDate>03/01/2009</invoiceDate>
    <clientName>ACME INC</clientName>
    <clientId>BP102USA</clientId>
    <products>
        <product>
            <name>Iphone 6000G</name>
            <quantity>12</quantity>
            <amout>4000</amout>
        </product>
        <product>
            <name>Lenovo T61P</name>
            <quantity>5</quantity>
            <amout>7000</amout>
        </product>
        <product>
            <name>Xbox 123</name>
            <quantity>2</quantity>
            <amout>1000</amout>
        </product>
        <product>
            <name>GOLDPATH 1</name>
            <quantity>4</quantity>
            <amout>400</amout>
        </product>
    </products>
</invoice>

Como verán, solo definimos datos como, nombre del cliente y el detalle de los productos.

Creación de diseños invoice.jrxml y invoice-detail.jrxml

Tanto los diseños del reporte maestro y detalle son los mismos. Como el de detalle es el mas simple lo listare primero y luego el maestro.

(invoice-detail.jrxml)

<?xml version="1.0" encoding="UTF-8"  ?>
<!-- Created with iReport - A designer for JasperReports -->
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="invoice-detail">
	<property name="ireport.scriptlethandling" value="0" />
	<property name="ireport.encoding" value="UTF-8" />
 
	<field name="name" class="java.lang.String">
		<fieldDescription><![CDATA[name]]></fieldDescription>
	</field>
	<field name="quantity" class="java.lang.String">
		<fieldDescription><![CDATA[quantity]]></fieldDescription>
	</field>
	<field name="amout" class="java.lang.Integer">
		<fieldDescription><![CDATA[amout]]></fieldDescription>
	</field>
 
	<variable name="totalAmount" class="java.lang.Integer" resetType="Report" calculation="Sum">
		<variableExpression><![CDATA[$F{amout}]]></variableExpression>
	</variable>
		<background>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</background>
		<title>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</title>
		<pageHeader>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</pageHeader>
		<columnHeader>
			<band height="32"  isSplitAllowed="true" >
				<staticText>
					<reportElement
						x="15"
						y="8"
						width="192"
						height="18"
						key="staticText-1"/>
					<box></box>
					<textElement>
						<font isBold="true"/>
					</textElement>
				<text><![CDATA[Product Name]]></text>
				</staticText>
				<staticText>
					<reportElement
						x="228"
						y="8"
						width="131"
						height="18"
						key="staticText-2"/>
					<box></box>
					<textElement>
						<font isBold="true"/>
					</textElement>
				<text><![CDATA[Quantity]]></text>
				</staticText>
				<staticText>
					<reportElement
						x="381"
						y="8"
						width="108"
						height="18"
						key="staticText-3"/>
					<box></box>
					<textElement textAlignment="Right">
						<font isBold="true"/>
					</textElement>
				<text><![CDATA[Amout]]></text>
				</staticText>
			</band>
		</columnHeader>
		<detail>
			<band height="38"  isSplitAllowed="true" >
				<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="15"
						y="11"
						width="192"
						height="18"
						key="textField"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
				</textField>
				<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="228"
						y="11"
						width="131"
						height="18"
						key="textField"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.String"><![CDATA[$F{quantity}]]></textFieldExpression>
				</textField>
				<textField isStretchWithOverflow="false" pattern="¤ #,##0.00" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="381"
						y="11"
						width="108"
						height="18"
						key="textField"/>
					<box></box>
					<textElement textAlignment="Right">
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.Integer"><![CDATA[$F{amout}]]></textFieldExpression>
				</textField>
				<staticText>
					<reportElement
						x="492"
						y="14"
						width="31"
						height="14"
						key="staticText-4"/>
					<box></box>
					<textElement>
						<font size="8"/>
					</textElement>
				<text><![CDATA[USD]]></text>
				</staticText>
			</band>
		</detail>
		<columnFooter>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</columnFooter>
		<pageFooter>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</pageFooter>
		<summary>
			<band height="33"  isSplitAllowed="true" >
				<textField isStretchWithOverflow="false" pattern="¤ #,##0.00" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="364"
						y="7"
						width="125"
						height="26"
						key="textField"/>
					<box></box>
					<textElement textAlignment="Right">
						<font size="14"/>
					</textElement>
				<textFieldExpression   class="java.lang.Integer"><![CDATA[$V{totalAmount}]]></textFieldExpression>
				</textField>
				<staticText>
					<reportElement
						x="492"
						y="9"
						width="26"
						height="14"
						key="staticText-5"/>
					<box></box>
					<textElement>
						<font size="8"/>
					</textElement>
				<text><![CDATA[USD]]></text>
				</staticText>
				<staticText>
					<reportElement
						x="15"
						y="7"
						width="112"
						height="26"
						key="staticText-6"/>
					<box></box>
					<textElement>
						<font size="14" isBold="true"/>
					</textElement>
				<text><![CDATA[TOTAL]]></text>
				</staticText>
			</band>
		</summary>
</jasperReport>

Como veran, se definen tres campos para los productos: name, quantity y amount, luego estos campos son desplegados en el área de detalle del reporte.

Ademas tambien estamos declarando una variable llamada totalAmount, que nos sirve calcular el total de la factura.

(invoice.jrxml)

<?xml version="1.0" encoding="UTF-8"  ?>
<!-- Created with iReport - A designer for JasperReports -->
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="invoice">
	<property name="ireport.scriptlethandling" value="0" />
	<property name="ireport.encoding" value="UTF-8" />
 
	<parameter name="detailPath" isForPrompting="false" class="java.lang.String"/>
 
	<field name="clientName" class="java.lang.String">
		<fieldDescription><![CDATA[clientName]]></fieldDescription>
	</field>
	<field name="clientId" class="java.lang.String">
		<fieldDescription><![CDATA[clientId]]></fieldDescription>
	</field>
	<field name="invoiceNumber" class="java.lang.String">
		<fieldDescription><![CDATA[invoiceNumber]]></fieldDescription>
	</field>
	<field name="invoiceDate" class="java.lang.String">
		<fieldDescription><![CDATA[invoiceDate]]></fieldDescription>
	</field>
 
		<background>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</background>
		<title>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</title>
		<pageHeader>
			<band height="50"  isSplitAllowed="true" >
				<staticText>
					<reportElement
						x="5"
						y="6"
						width="227"
						height="35"
						key="staticText-2"/>
					<box></box>
					<textElement>
						<font fontName="FreeSerif" size="24"/>
					</textElement>
				<text><![CDATA[SomeCompany co.]]></text>
				</staticText>
			</band>
		</pageHeader>
		<columnHeader>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</columnHeader>
		<detail>
			<band height="136"  isSplitAllowed="true" >
				<staticText>
					<reportElement
						x="460"
						y="43"
						width="0"
						height="0"
						key="staticText-1"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<text><![CDATA[Static Text]]></text>
				</staticText>
				<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="95"
						y="30"
						width="173"
						height="18"
						key="textField"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.String"><![CDATA[$F{clientName}+ "  - " + $F{clientId}]]></textFieldExpression>
				</textField>
				<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="94"
						y="7"
						width="100"
						height="18"
						key="textField"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.String"><![CDATA[$F{invoiceNumber}]]></textFieldExpression>
				</textField>
				<staticText>
					<reportElement
						x="4"
						y="30"
						width="26"
						height="18"
						key="staticText-3"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<text><![CDATA[To:]]></text>
				</staticText>
				<staticText>
					<reportElement
						x="4"
						y="7"
						width="81"
						height="18"
						key="staticText-4"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<text><![CDATA[Invoice Number:]]></text>
				</staticText>
				<staticText>
					<reportElement
						x="5"
						y="53"
						width="82"
						height="18"
						key="staticText-5"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<text><![CDATA[Date:]]></text>
				</staticText>
				<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
					<reportElement
						x="96"
						y="53"
						width="78"
						height="18"
						key="textField"/>
					<box></box>
					<textElement>
						<font/>
					</textElement>
				<textFieldExpression   class="java.lang.String"><![CDATA[$F{invoiceDate}]]></textFieldExpression>
				</textField>
				<subreport  isUsingCache="true">
					<reportElement
						x="8"
						y="90"
						width="521"
						height="29"
						key="subreport-1"/>
					<dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JRXmlDataSource)$P{REPORT_DATA_SOURCE}).subDataSource($P{detailPath})]]></dataSourceExpression>
                    <subreportExpression  class="java.lang.String"><![CDATA["./invoice-detail.jasper"]]></subreportExpression>
				</subreport>
			</band>
		</detail>
		<columnFooter>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</columnFooter>
		<pageFooter>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</pageFooter>
		<summary>
			<band height="0"  isSplitAllowed="true" >
			</band>
		</summary>
</jasperReport>

Acá es donde se pone un poco confuso :) Donde tenemos que poner nuestra atención es en el elemento subreport. Este elemento también puede ser creado usando el iReport.

reportElement, define la posición donde se encontrara el subreporte.

dataSourceExpression, en la expresion estamos indicando que vamos a usar el un sub data source, del data source principal del reporte.
“detailPath”, es una xpath que indicara la fuente de datos del subreporte.

subreportExpression, contiene la localización del diseño compilado del reporte de detalle, en consecuencia este es el path de un archivo .jasper.

Java

package bo.sumasoftware.hellojasperreports;
 
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.data.JRXmlDataSource;
 
import java.util.HashMap;
 
/**
 * @author renan
 */
public class WriteInvoiceBasic {
    public static void main(String[] args) throws JRException {
        JasperCompileManager.
                compileReportToFile( "src/main/jrxml/invoice.jrxml","invoice.jasper");
        JasperCompileManager.
                compileReportToFile( "src/main/jrxml/invoice-detail.jrxml","invoice-detail.jasper");
 
        JasperReport master = (JasperReport)JRLoader.loadObject("invoice.jasper");
        JRXmlDataSource xmlDataSource = new JRXmlDataSource("src/main/xml/invoice.xml", "/invoice");
        HashMap hashMap = new HashMap();
        hashMap.put("detailPath","/invoice/products/product");
        JasperPrint jasperPrint = JasperFillManager.fillReport(master, hashMap, xmlDataSource);
        JasperExportManager.exportReportToPdfFile(jasperPrint, "invoice-basic.pdf");
    }
}

Compilación de los reportes. Como veran lo primero que hacemos es compilar los reportes maestro y detalle. al compilar estamos creando los respectivos archivos .jasper de cada reporte.
Hacemos esto, ya que en el reporte maestro se necesita pasar un archivo .jasper.

Cargando reporte maestro. Para realizar esto estamos usando la clase JRLoader y su método loadObject para leer el reporte maestro cmpilado invoice.jasper.

Creacion de JRXMLDataSource. Al crear este objeto, le pasamos como parámetro el archivo xml de datos y también una expresión xpath que indica el nodo raiz de datos para el reporte principal.

Definición de parámetros. En un HashMap estamos definiendo un parámetro llamado “detailPath”. detailPath indica contiene una expresión xpath que indica el data source del subreporte.
Esta es la parte importe. Si nos equivocamos en definir este parámetro el subreporte simplemente no mostrar información.
También tenemos que hacer notar que este es un parámetro definido en el diseño del reporte maestro y se hace referencia a este en el elemento dataSourceExpression.

Impresión del reporte. Acá ya solo se llena el reporte y luego se lo imprime en un archivo pdf.

:) bueno, hasta aquí por hoy. :)
pueden bajar el código fuente. Este es un poco diferente pero tiene dos ejemplos, uno básico y otro mas completo.

Renan Huanca JasperReports ,

Como usar el JRXmlDataSource de JasperReports 3.1.2 (Hola Mundo JRXmlDataSource)

March 12th, 2009

Introducción

Este articulo muestra como usar utilizar el JRXmlDataSource de jasperReports.
Como fuente de datos usaremos un archivo XML y la salida sera un archivo PDF.
Para los que quieren una introducción acerca del archivo de definición de reporte, pueden ver: Comenzando con JasperReports (de David R. Heffelfinger) - Traducción

Definiendo el archivo de datos.

Lo nombraremos data.xml y tendrá el siguiente contendido.

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user>
        <firstName>Carlos</firstName>
        <lastName>Rodrigues</lastName>
        <age>34</age>
        <id>12345678</id>
    </user>
    <user>
        <firstName>Esteban</firstName>
        <lastName>Arce</lastName>
        <age>21</age>
        <id>00000001</id>
    </user>
    <user>
        <firstName>Milton</firstName>
        <lastName>Laura</lastName>
        <age>50</age>
        <id>12003001</id>
    </user>
    <user>
        <firstName>Luis</firstName>
        <lastName>Pimentel</lastName>
        <age>45</age>
        <id>11004011</id>
    </user>
</users>

Creamos el archivo de definición del reporte.(helloJasperReportXML.jrxml)

Este archivo lo genere con la herramienta iReport. le quite la mayoría de los tags y lo deje con lo mas esencial para explicarlo.

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport
        name="helloHasperXML"
        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">
    <field name="FIRST_NAME" class="java.lang.String">
        <fieldDescription><![CDATA[firstName]]></fieldDescription>
    </field>
    <field name="LAST_NAME" class="java.lang.String">
        <fieldDescription><![CDATA[lastName]]></fieldDescription>
    </field>
    <field name="AGE" class="java.lang.String">
        <fieldDescription><![CDATA[age]]></fieldDescription>
    </field>
    <field name="ID" class="java.lang.String">
        <fieldDescription><![CDATA[id]]></fieldDescription>
    </field>
    <detail>
        <band height="18">
            <textField isBlankWhenNull="false">
                <reportElement key="textField-1" x="10" y="2" width="50" height="15"/>
                <textElement/>
                <textFieldExpression class="java.lang.String"><![CDATA[$F{FIRST_NAME}]]></textFieldExpression>
            </textField>
            <textField isBlankWhenNull="false">
                <reportElement key="textField-2" x="70" y="2" width="50" height="15"/>
                <textElement/>
                <textFieldExpression class="java.lang.String"><![CDATA[$F{LAST_NAME}]]></textFieldExpression>
            </textField>
            <textField isBlankWhenNull="false">
                <reportElement key="textField-3" x="130" y="2" width="50" height="15"/>
                <textElement/>
                <textFieldExpression class="java.lang.String"><![CDATA[$F{AGE}]]></textFieldExpression>
            </textField>
            <textField isBlankWhenNull="false">
                <reportElement key="textField-4" x="190" y="2" width="50" height="15"/>
                <textElement/>
                <textFieldExpression class="java.lang.String"><![CDATA[$F{ID}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

<field>, Define un campo que sera usado en el reporte. En este caso estamos definiendo 4 fields: FIRST_NAME, LAST_NAME, AGE y ID. Como verán, dentro de cada <field> hay un elemento <fieldDescription> este es como un mapa entre el field que sera usado en el reporte y el origen de datos. En Esta caso el origen de datos esta dado por el nombre del tag que corresponde en el archivo data.xml.
Importante: Para obtener los datos estamos usando en este caso XPATH, si quisieremos sacar una propiedad tendriamos que usar algo como @firstName

<textField>, este elemento se usa para, definir en que posición del reporte se desplegara un campo. Como verán tiene tres sub elementos: <reportelement>, que define la posición, <textElement>, que indica es es un campo texto y <textFieldExpression>, que indica de que field viene la informacion.

Creamos la clase HelloXMLJasperReport.

package bo.sumasoftware.hellojasper;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRXmlDataSource;
import java.util.HashMap;
 
/**
 * @author renan
 * @since Mar 11, 2009 4:39:00 PM
 */
public class HelloXMLJasperReport {
    public static void main(String args[]) throws Exception {
        JasperReport jasperReport = JasperCompileManager.compileReport("src/main/resources/helloHasperXML.jrxml");
        JRXmlDataSource xmlDataSource = new JRXmlDataSource("src/main/resources/data.xml","users//user");
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, new HashMap(), xmlDataSource);
        JasperExportManager.exportReportToPdfFile(jasperPrint, "report_from_xml.pdf");
    }
}

JasperCompileManager, nos permite crear una instancia de JasperReport que viene de compila nuestro archivo de definición de reporte, como verán se le pasa la ruta del mencionado archivo. Generalmente si no definiste bien los fields, te dará un error acá.

JRXmlDataSource, al crear la instancia le estamos pasando dos parámetros: path, que es el camino de nuestro archivo de datos y una expresión xpath, que indica de que parte del archivo xml se extraerá la información. En este caso con “users//user”, estamos indicando que recogeremos todos los elementos user que estan dentro del elemento users.

JRXmlDataSource, nos permite pasar pasar el DataSource y algunos parámetros antes de imprimirlo.

JasperExportManager, finalmente nos ayuda a imprimir el reporte en un archivo pdf…. :) fuiiiu fue largo el caminio.

Nota para los usuarios de iReport, si quieres usar esta herramienta para visualizar el reporte, tendrás que adicionar:

<queryString language="xPath">
	<![CDATA[users//user]]>
</queryString>

como primer elemento hijo del tag <jasperReport≶ y una conexión XML referenciando al archivo data.xml. Con querySring, indicamos de donde se obtendrá la información.

También comparto el código fuente :), que también tiene aparte un ejemplo con base de datos.

Hasta la próxima :), si tienes comentarios no duden en hacerlos.

Renan Huanca JasperReports , ,