How to create sub-reports using XML DataSources in JasperReports? - jasper-reports

I'm using iReport and I need to create a sub-report using a XML DataSource.
I will have only one XML for the hole report. Something like this:
<question>
<text>What do you think about SO?</text>
<options>
<option>Like it</option>
<option>Really like it</option>
<option>Love it</option>
</options>
</question>
The main report will have it's detail linked to the questions, each question will have many options. Each sub-report must be linked to the options for the question... Well master-detail.
All that I could find with some googling was using SQL, I want to use XPath.

Take a look at the JRXmlDataSource JavaDoc. There are example that show how it's done.

Create your subreport as a report first using the xpath. Then create a subreport element in the parent report and link the subreport to the parent report.
below is a sample subreport element:
<subreport>
<reportElement x="0" y="20" width="555" height="100"/>
<subreportParameter name="XML_DATE_PATTERN">
<subreportParameterExpression><![CDATA[$P{XML_DATE_PATTERN}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="XML_DATA_DOCUMENT">
<subreportParameterExpression><![CDATA[$P{XML_DATA_DOCUMENT}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="XML_LOCALE">
<subreportParameterExpression><![CDATA[$P{XML_LOCALE}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="XML_NUMBER_PATTERN">
<subreportParameterExpression><![CDATA[$P{XML_NUMBER_PATTERN}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="XML_TIME_ZONE">
<expressionistic><![CDATA[$P{XML_TIME_ZONE}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression class="java.lang.String"><![CDATA[$P{SUBREPORT_DIRECTORY} + "PS_Product_Match.jasper"]]></subreportExpression>
</subreport>

Related

JasperServer dynamic Band Height as Subreports have different heights

I have a jrmxl report that uses different subreports with different heights, one is 421 and the other one is 600.
Is it possible for the report to dynamically set the band height on each page of the PDF that it generates?
<detail>
<band height="421">
<subreport>
<reportElement x="0" y="0" width="297" height="421" uuid="a23ff576-6d38-4582-a7ea-18e18926136c"/>
<subreportParameter name="NUMBER">
<subreportParameterExpression><![CDATA[$F{number}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression><![CDATA[$F{report}.trim()]]></subreportExpression>
</subreport>
</band>
</detail>
If your subreports need to produce pages of different sizes in the same resulting PDF document, then you need to use your subreport templates as parts in a part-based JRXML, AKA book report, as opposed to the usual band-based JRXML.
You can find a book report sample in our project distro under the /demo/samples/book folder.
Make sure you use JR Lib version 6.0.0 or newer.

Jasper sub-reports of sub-reports - programmatically

There are many examples of running sub-reports in Jasper on the web, but nobody seems to have had the problem that I have, when running a sub-report that contains another sub-report.
We store our report definitions in a Relational Database, and generate and run the reports out of a java service. We only use the GUI to design and test each report, to start with.
The reports are compiled and filled at runtime, and I can cause a sub-report to run, by using the well documented feature of adding the compiled sub-report to the main report at fill time using the report expression to use a sub-report as a parameter.
That is all fine. However, how can I fill the first sub-report with the compile output of the next sub-report down the tree?
To explain a little further, in JasperStudio, I can do this in the main report:
<subreport>
<reportElement x="4" y="100" width="547" height="310" uuid="f9364882-a530-475d-97af-8d6d2d47ae57"/>
<subreportParameter name="INSP_ID">
<subreportParameterExpression><![CDATA[$F{jobid}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression><![CDATA["InspectionFrogSubReport.jasper"]]></subreportExpression>
</subreport>
Then in the first sub report, to refer to the next one, I can do this:
<subreport>
<reportElement x="280" y="56" width="270" height="294" uuid="b4cbe376-1b54-471c-a6d4-0d45afeab2c8"/>
<subreportParameter name="FROG_ID">
<subreportParameterExpression><![CDATA[$F{frog_id}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression><![CDATA["InspectionDamageSubReport.jasper"]]></subreportExpression>
</subreport>
So, when I preview the mian, it fills the first sub, and then the next sub, no problem.
However, to fill from Java method, I change the main sub-report expression to:
<subreport>
<reportElement x="4" y="100" width="547" height="310" uuid="f9364882-a530-475d-97af-8d6d2d47ae57"/>
<subreportParameter name="INSP_ID">
<subreportParameterExpression><![CDATA[$F{jobid}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression><![CDATA["$P!{SUB1}"]]></subreportExpression>
</subreport>
Then in my code:
// Compile sub report
InputStream childStream = new ByteArrayInputStream(subReport.getChildXml().getBytes());
JasperReport compiledChild = JasperCompileManager.compileReport(childStream);
// Compile Main report
InputStream xmlStream = new ByteArrayInputStream(report.getXml().getBytes());
JasperReport compiledReport = JasperCompileManager.compileReport(xmlStream);
// Build report parameter map
Map<String, Object> params = new HashMap<>();
params.put("SUB1", compiledChild);
// Fill main report
JasperPrint jasperPrint = JasperFillManager.fillReport(compiledReport, params, conn);
so far, so good. However, how do I pass the sub-sub-report into the sub-report. I cannot use 'fillReport' as the sub report will have no master record to work on until the main report runs.
Pass subSubReport as a param to supReport.
in java code:
params.put("SUB_SUB_REPORT", compiledSubSubreport);
in main report template xml:
<subreportParameter name="SUB_SUB_REPORT">
<subreportParameterExpression><![CDATA[$P{SUB_SUB_REPORT}]]></subreportParameterExpression>
</subreportParameter>
this is what you want?

Grouping by parameter value in jasper

Well, I don't know, maybe I'm missing something, but I've been trying to group data in a jasper report, but so far the grouping appears only if the group expression is a field. Is it possible to group data by parameter value instead of field value? i.e., something like
<groupExpression><[!CDATA[$P{some_param}]]></groupExpression>
instead of
<groupExpression><[!CDATA[$F{some_field}]]></groupExpression>
in the .jrxml file?
Is it possible to group data by parameter value instead of field value?
Yes, it is, just like you mentioned. You would have no syntax errors and the report would be generated.
The problem is that it may not bring what you're expecting. The group bands are usually printed every time the "groupExpression" changes. So basically this parameter needs to be associated with something that will change during the report generation (for example, filling a parameter of a subreport with a field in way that this subreport uses this paramater as a group expression). And of course, it needs to be associated with something that makes sense and bring you the desirable behavior.
You can have something like this in your subreport:
...
<parameter name="START" class="java.util.Date"/>
<parameter name="END" class="java.util.Date"/>
...
And something like this in a detail band of your "super" report:
<subreport>
<reportElement x="0" y="10" width="555" height="200" uuid="ac2c99da-f595-4498-a518-2bfb1f31b73c"/>
<subreportParameter name="START">
<subreportParameterExpression><![CDATA[$F{start}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="END">
<subreportParameterExpression><![CDATA[$F{end}]]></subreportParameterExpression>
</subreportParameter>
...
</subreport>
Just notice I'm assuming the fields $F{end} and $F{start} are also "java.util.Date" objects.

JasperReports: How to remove new page blank in subreport

I have create one report and put subreport into summary. I have problem to remove the new page blank in subreport because i have put clicks "run to bottom" in subreport's properties. After that, i run my report properly. The data appear correctly but problem comes when one new page blank appear after page. I don't know how to remove the blank page. Anyone know about this?
i know my mistakes is not put sub report by size band. Size band and sub ​​report must be the same size so that no blank page will come out.
I solve this adding the attribute isRemoveLineWhenBlank="true" for the reportElement tag:
<reportElement mode="Opaque" x="0" y="0" width="802" height="60" isRemoveLineWhenBlank="true" ...
And the band height, reportElement height and the subreport height must be equals:
<detail>
<band height="60" splitType="Stretch">
<subreport>
<reportElement mode="Opaque" x="0" y="0" width="802" height="60" ...

How to create a multi language report?

I want to create a document, which prints in more than one language, based on the Locale.
I have created 2 resource bundles, one in English and one in Chinese, but I am not sure how to use them.
Here is the sample of how to implement internationalization support for JasperReports.
The main idea is to use special expression $R{} for localizing text and images.
The sample for images:
<image scaleImage="Clip">
<reportElement positionType="Float" x="20" y="20" width="100" height="50"/>
<imageExpression class="java.lang.String"><![CDATA[$R{image.flag}]]></imageExpression>
</image>
The samples for text (the $R{} syntax):
<textField isBlankWhenNull="true">
<reportElement x="20" y="100" width="530" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$R{sampleString}]]></textFieldExpression>
</textField>
or (the msg() method):
text.message=The program picked up {0} as a random number.
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
<reportElement x="20" y="210" width="530" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[msg($R{text.message}, $P{number})]]></textFieldExpression>
</textField>
Since the document generator may be part of your application, you should somewhere have a language selector menu-item, check-box or combo-box which is already preselected.
So, why don't you just add an if statement that reads the Locale, or the needed language before the report generation, and load the appropriate report accordingly to the locale.
This way you will need to keep one jrxml file for every language. It will be fairly easy to just translate the headers and labels manually.
Your data should be already translated in your database, where you have to keep the relevant attribute values multilingual anyway.
You will need to modify the SQL query for the appropriate language, but since the Query is part of your jrxml it will be executed automatically.