I'm developing a jrxml template for generate job candidate's resume. The candidates are in my database.
I need to generate a Word file (.docx) for 1 record (by job candidate), as the image below:
How can I make Jasper generate one file for each record of my SQL query? And export these files to Word?
I saw there is a parameter called PAGE_INDEX exporter. But I did not find how to use it ...
Can someone help me please?
Note 1: My reports are not generated by JasperServer. I developed a Java program to generate them and send reports by email.
Note 2: The number of pages for each candidate may be different.
Updating status
I managed to generate one record per file. But I could only generate the file to the first record.
I need to generate other files for the remaining records.
I'm still with the another problem too: how to separate into separate files when the number of pages for each record (candidate entity) can change?
final JRDocxExporter exporter = new JRDocxExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(new java.io.File("/home/admin/resume candidate.docx")));
SimpleDocxReportConfiguration configuration = new SimpleDocxReportConfiguration();
configuration.setPageIndex(0);
exporter.setConfiguration(configuration);
exporter.exportReport();
PROBLEM SOLUTION
I solved the problem by inserting a variable in the footer of each page with the expression: $V{REPORT_COUNT}, which have record count that is in the Detail Band:
After that, the Java program do loop between the pages of JasperPrint object.
So, i locate that element that tells me what page belongs to candidate.
Based on this information and storing candidate index data and its pages (in a HashMap > mapCandPage), I can determine the page that starts and the page ends for each candidate. And that way I can export one document for each candidate record.
public static void main(String args[]) throws Exception {
File relJasperArqFile = new File("Candidate Resume Template.jasper");
Connection conn = ConnectionFactory.getNewConnectionSQLDRIVER();
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(relJasperArqFile);
JasperPrint jasperPrint
= JasperFillManager.fillReport(jasperReport,
null,
conn);
final JRDocxExporter exporter = new JRDocxExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
List<JRPrintPage> listPrintPage = jasperPrint.getPages();
int candIdx = 0;
int fileIdx = 0;
int lastCandIdx = 0;
HashMap<Integer, List<Integer>> mapCandPage = new HashMap<>();
for (int pageIdx = 0; pageIdx < listPrintPage.size(); pageIdx++) {
JRPrintPage page = listPrintPage.get(pageIdx);
candIdx = getCandIdx(page);
if (!mapCandPage.containsKey(candIdx)) {
mapCandPage.put(candIdx, (new ArrayList<>()));
}
mapCandPage.get(candIdx).add(pageIdx);
if (pageIdx > 0 && candIdx != lastCandIdx) {
fileIdx++;
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(new File(String.format("Candidate Resume %d.docx", fileIdx))));
SimpleDocxReportConfiguration configuration = new SimpleDocxReportConfiguration();
configuration.setStartPageIndex(mapCandPage.get(lastCandIdx).get(0));
configuration.setEndPageIndex(mapCandPage.get(lastCandIdx).get(mapCandPage.get(lastCandIdx).size() - 1));
exporter.setConfiguration(configuration);
exporter.exportReport();
}
lastCandIdx = candIdx;
}
fileIdx++;
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(new File(String.format("Candidate Resume %d.docx", fileIdx))));
SimpleDocxReportConfiguration configuration = new SimpleDocxReportConfiguration();
configuration.setStartPageIndex(mapCandPage.get(lastCandIdx).get(0));
configuration.setEndPageIndex(mapCandPage.get(lastCandIdx).get(mapCandPage.get(lastCandIdx).size() - 1));
exporter.setConfiguration(configuration);
exporter.exportReport();
}
public static Integer getCandIdx(JRPrintPage page) {
JRPrintElement lastRowNumber = page.getElements().get(page.getElements().size() - 1);
return Integer.parseInt(((JRTemplatePrintText) lastRowNumber).getFullText());
}
This is a test and my code is not optimized. If anyone has suggestions or a better idea, please post here. Thank you.
Related
I am trying to merge multiple documents into a single one by following examples as posted in this other post.
I am using AltChunk altChunk = new AltChunk(). When documents are merged, it does not seem to retain seperate hearders of each document. The merged document will contain the headers of the first document during the merging. If the first document being merged contains no hearders, then all the rest of the newly merged document will contain no headers, and vise versa.
My question is, how can I preserve different headers of the documents being merged?
Merge multiple word documents into one Open Xml
using System;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace WordMergeProject
{
public class Program
{
private static void Main(string[] args)
{
byte[] word1 = File.ReadAllBytes(#"..\..\word1.docx");
byte[] word2 = File.ReadAllBytes(#"..\..\word2.docx");
byte[] result = Merge(word1, word2);
File.WriteAllBytes(#"..\..\word3.docx", result);
}
private static byte[] Merge(byte[] dest, byte[] src)
{
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString();
var memoryStreamDest = new MemoryStream();
memoryStreamDest.Write(dest, 0, dest.Length);
memoryStreamDest.Seek(0, SeekOrigin.Begin);
var memoryStreamSrc = new MemoryStream(src);
using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStreamDest, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
AlternativeFormatImportPart altPart =
mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
altPart.FeedData(memoryStreamSrc);
var altChunk = new AltChunk();
altChunk.Id = altChunkId;
OpenXmlElement lastElem = mainPart.Document.Body.Elements<AltChunk>().LastOrDefault();
if(lastElem == null)
{
lastElem = mainPart.Document.Body.Elements<Paragraph>().Last();
}
//Page Brake einfügen
Paragraph pageBreakP = new Paragraph();
Run pageBreakR = new Run();
Break pageBreakBr = new Break() { Type = BreakValues.Page };
pageBreakP.Append(pageBreakR);
pageBreakR.Append(pageBreakBr);
return memoryStreamDest.ToArray();
}
}
}
I encountered this question a few years ago and spent quite some time on it; I eventually wrote a blog article that links to a sample file. Achieving integrating files with headers and footers using Alt-Chunk is not straight-forward. I'll try to cover the essentials, here. Depending on what kinds of content the headers and footers contain (and assuming Microsoft has not addressed any of the problems I originally ran into) it may not be possible to rely soley on AltChunk.
(Note also that there may be Tools/APIs that can handle this - I don't know and asking that on this site would be off-topic.)
Background
Before attacking the problem, it helps to understand how Word handles different headers and footers. To get a feel for it, start Word...
Section Breaks / Unlinking headers/footers
Type some text on the page and insert a header
Move the focus to the end of the page and go to the Page Layout tab in the Ribbon
Page Setup/Breaks/Next Page section break
Go into the Header area for this page and note the information in the blue "tags": you'll see a section identifier on the left and "Same as previous" on the right. "Same as Previous" is the default, to create a different Header click the "Link to Previous" button in the Header
So, the rule is:
a section break is required, with unlinked headers (and/or footers),
in order to have different header/footer content within a document.
Master/Sub-documents
Word has an (in)famous functionality called "Master Document" that enables linking outside ("sub") documents into a "master" document. Doing so automatically adds the necessary section breaks and unlinks the headers/footers so that the originals are retained.
Go to Word's Outline view
Click "Show Document"
Use "Insert" to insert other files
Notice that two section breaks are inserted, one of the type "Next page" and the other "Continuous". The first is inserted in the file coming in; the second in the "master" file.
Two section breaks are necessary when inserting a file because the last paragraph mark (which contains the section break for the end of the document) is not carried over to the target document. The section break in the target document carries the information to unlink the in-coming header from those already in the target document.
When the master is saved, closed and re-opened the sub documents are in a "collapsed" state (file names as hyperlinks instead of the content). They can be expanded by going back to the Outline view and clicking the "Expand" button. To fully incorporate a sub-document into the document click on the icon at the top left next to a sub-document then clicking "Unlink".
Merging Word Open XML files
This, then, is the type of environment the Open XML SDK needs to create when merging files whose headers and footers need to be retained. Theoretically, either approach should work. Practically, I had problems with using only section breaks; I've never tested using the Master Document feature in Word Open XML.
Inserting section breaks
Here's the basic code for inserting a section break and unlinking headers before bringing in a file using AltChunk. Looking at my old posts and articles, as long as there's no complex page numbering involved, it works:
private void btnMergeWordDocs_Click(object sender, EventArgs e)
{
string sourceFolder = #"C:\Test\MergeDocs\";
string targetFolder = #"C:\Test\";
string altChunkIdBase = "acID";
int altChunkCounter = 1;
string altChunkId = altChunkIdBase + altChunkCounter.ToString();
MainDocumentPart wdDocTargetMainPart = null;
Document docTarget = null;
AlternativeFormatImportPartType afType;
AlternativeFormatImportPart chunk = null;
AltChunk ac = null;
using (WordprocessingDocument wdPkgTarget = WordprocessingDocument.Create(targetFolder + "mergedDoc.docx", DocumentFormat.OpenXml.WordprocessingDocumentType.Document, true))
{
//Will create document in 2007 Compatibility Mode.
//In order to make it 2010 a Settings part must be created and a CompatMode element for the Office version set.
wdDocTargetMainPart = wdPkgTarget.MainDocumentPart;
if (wdDocTargetMainPart == null)
{
wdDocTargetMainPart = wdPkgTarget.AddMainDocumentPart();
Document wdDoc = new Document(
new Body(
new Paragraph(
new Run(new Text() { Text = "First Para" })),
new Paragraph(new Run(new Text() { Text = "Second para" })),
new SectionProperties(
new SectionType() { Val = SectionMarkValues.NextPage },
new PageSize() { Code = 9 },
new PageMargin() { Gutter = 0, Bottom = 1134, Top = 1134, Left = 1318, Right = 1318, Footer = 709, Header = 709 },
new Columns() { Space = "708" },
new TitlePage())));
wdDocTargetMainPart.Document = wdDoc;
}
docTarget = wdDocTargetMainPart.Document;
SectionProperties secPropLast = docTarget.Body.Descendants<SectionProperties>().Last();
SectionProperties secPropNew = (SectionProperties)secPropLast.CloneNode(true);
//A section break must be in a ParagraphProperty
Paragraph lastParaTarget = (Paragraph)docTarget.Body.Descendants<Paragraph>().Last();
ParagraphProperties paraPropTarget = lastParaTarget.ParagraphProperties;
if (paraPropTarget == null)
{
paraPropTarget = new ParagraphProperties();
}
paraPropTarget.Append(secPropNew);
Run paraRun = lastParaTarget.Descendants<Run>().FirstOrDefault();
//lastParaTarget.InsertBefore(paraPropTarget, paraRun);
lastParaTarget.InsertAt(paraPropTarget, 0);
//Process the individual files in the source folder.
//Note that this process will permanently change the files by adding a section break.
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(sourceFolder);
IEnumerable<System.IO.FileInfo> docFiles = di.EnumerateFiles();
foreach (System.IO.FileInfo fi in docFiles)
{
using (WordprocessingDocument pkgSourceDoc = WordprocessingDocument.Open(fi.FullName, true))
{
IEnumerable<HeaderPart> partsHeader = pkgSourceDoc.MainDocumentPart.GetPartsOfType<HeaderPart>();
IEnumerable<FooterPart> partsFooter = pkgSourceDoc.MainDocumentPart.GetPartsOfType<FooterPart>();
//If the source document has headers or footers we want to retain them.
//This requires inserting a section break at the end of the document.
if (partsHeader.Count() > 0 || partsFooter.Count() > 0)
{
Body sourceBody = pkgSourceDoc.MainDocumentPart.Document.Body;
SectionProperties docSectionBreak = sourceBody.Descendants<SectionProperties>().Last();
//Make a copy of the document section break as this won't be imported into the target document.
//It needs to be appended to the last paragraph of the document
SectionProperties copySectionBreak = (SectionProperties)docSectionBreak.CloneNode(true);
Paragraph lastpara = sourceBody.Descendants<Paragraph>().Last();
ParagraphProperties paraProps = lastpara.ParagraphProperties;
if (paraProps == null)
{
paraProps = new ParagraphProperties();
lastpara.Append(paraProps);
}
paraProps.Append(copySectionBreak);
}
pkgSourceDoc.MainDocumentPart.Document.Save();
}
//Insert the source file into the target file using AltChunk
afType = AlternativeFormatImportPartType.WordprocessingML;
chunk = wdDocTargetMainPart.AddAlternativeFormatImportPart(afType, altChunkId);
System.IO.FileStream fsSourceDocument = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open);
chunk.FeedData(fsSourceDocument);
//Create the chunk
ac = new AltChunk();
//Link it to the part
ac.Id = altChunkId;
docTarget.Body.InsertAfter(ac, docTarget.Body.Descendants<Paragraph>().Last());
docTarget.Save();
altChunkCounter += 1;
altChunkId = altChunkIdBase + altChunkCounter.ToString();
chunk = null;
ac = null;
}
}
}
If there's complex page numbering (quoted from my blog article):
Unfortunately, there’s a bug in the Word application when integrating
Word document “chunks” into the main document. The process has the
nasty habit of not retaining a number of SectionProperties, among them
the one that sets whether a section has a Different First Page
() and the one to restart Page Numbering () in a section. As long as your documents don’t need to
manage these kinds of headers and footers you can probably use the
“altChunk” approach.
But if you do need to handle complex headers and footers the only
method currently available to you is to copy in the each document in
its entirety, part-by-part. This is a non-trivial undertaking, as
there are numerous possible types of Parts that can be associated not
only with the main document body, but also with each header and footer
part.
...or try the Master/Sub Document approach.
Master/Sub Document
This approach will certainly maintain all information, it will open as a Master document, however, and the Word API (either the user or automation code) is required to "unlink" the sub-documents to turn it into a single, integrated document.
Opening a Master Document file in the Open XML SDK Productivity Tool shows that inserting sub documents into the master document is a fairly straight-forward procedure:
The underlying Word Open XML for the document with one sub-document:
<w:body xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:p>
<w:pPr>
<w:pStyle w:val="Heading1" />
</w:pPr>
<w:subDoc r:id="rId6" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
</w:p>
<w:sectPr>
<w:headerReference w:type="default" r:id="rId7" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
<w:type w:val="continuous" />
<w:pgSz w:w="11906" w:h="16838" />
<w:pgMar w:top="1417" w:right="1417" w:bottom="1134" w:left="1417" w:header="708" w:footer="708" w:gutter="0" />
<w:cols w:space="708" />
<w:docGrid w:linePitch="360" />
</w:sectPr>
</w:body>
and the code:
public class GeneratedClass
{
// Creates an Body instance and adds its children.
public Body GenerateBody()
{
Body body1 = new Body();
Paragraph paragraph1 = new Paragraph();
ParagraphProperties paragraphProperties1 = new ParagraphProperties();
ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId(){ Val = "Heading1" };
paragraphProperties1.Append(paragraphStyleId1);
SubDocumentReference subDocumentReference1 = new SubDocumentReference(){ Id = "rId6" };
paragraph1.Append(paragraphProperties1);
paragraph1.Append(subDocumentReference1);
SectionProperties sectionProperties1 = new SectionProperties();
HeaderReference headerReference1 = new HeaderReference(){ Type = HeaderFooterValues.Default, Id = "rId7" };
SectionType sectionType1 = new SectionType(){ Val = SectionMarkValues.Continuous };
PageSize pageSize1 = new PageSize(){ Width = (UInt32Value)11906U, Height = (UInt32Value)16838U };
PageMargin pageMargin1 = new PageMargin(){ Top = 1417, Right = (UInt32Value)1417U, Bottom = 1134, Left = (UInt32Value)1417U, Header = (UInt32Value)708U, Footer = (UInt32Value)708U, Gutter = (UInt32Value)0U };
Columns columns1 = new Columns(){ Space = "708" };
DocGrid docGrid1 = new DocGrid(){ LinePitch = 360 };
sectionProperties1.Append(headerReference1);
sectionProperties1.Append(sectionType1);
sectionProperties1.Append(pageSize1);
sectionProperties1.Append(pageMargin1);
sectionProperties1.Append(columns1);
sectionProperties1.Append(docGrid1);
body1.Append(paragraph1);
body1.Append(sectionProperties1);
return body1;
}
}
I currently use iTextSharp to read in some PDF files and parse them by using the string I receive. I have encountered a strange behavior with some PDF files. When getting the string back of a for example 4 page PDF, the string is filled with the pages in the following order:
1 2 1 3 1 4
My code for reading the files is as follows:
using (PdfReader reader = new PdfReader(fileStream))
{
StringBuilder sb = new StringBuilder();
ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
for (int page = 0; page < reader.NumberOfPages; page++)
{
string text = PdfTextExtractor.GetTextFromPage(reader, page + 1, strategy);
if (!string.IsNullOrWhiteSpace(text))
sb.Append(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(text))));
}
Debug.WriteLine(sb.ToString());
}
Here is a link to a file with which this behaviour occurs:
https://onedrive.live.com/redir?resid=D9FEFF3BF45E05FD!1536&authkey=!AFLRlskAvlg89yY&ithint=file%2cpdf
Hope you guys can help me out!
Thanks to Chris Haas I found out was going wrong. The samples found online on how to use iTextSharp.Pdf are incorrect or incorrect for my implementation.
The SimpleTextExtractionStrategy needs to be instantiated for every page you try to read. Not doing this will multiply each previous page in the resulting string.
Also the line where the StringBuilder is being appended can be changed from:
sb.Append(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(text))));
to
sb.Append(text);
Thus the following code gives the correct result:
using (PdfReader reader = new PdfReader(fileStream))
{
StringBuilder sb = new StringBuilder();
for (int page = 0; page < reader.NumberOfPages; page++)
{
string text = PdfTextExtractor.GetTextFromPage(reader, page + 1, new SimpleTextExtractionStrategy());
if (!string.IsNullOrWhiteSpace(text))
sb.Append(text);
}
Debug.WriteLine(sb.ToString());
}
I am trying to use the iText library with c# to capture the text portion of pdf files.
I created a pdf from excel 2013 (exported) and then copied the sample from the web of how to use itext (added the lib ref to the project).
It reads perfectly the first page but it gets garbled info after that. It is keeping part of the first page and merging the info with the next page. The commented lines is when I was trying to solve the problem, the string "thePage" is recreated inside the for loop.
Here is the code. I can email the pdf to whoever can help with this issue.
Thanks in advance
public static string ExtractTextFromPdf(string path)
{
ITextExtractionStrategy its = new iTextSharp.text.pdf.parser.LocationTextExtractionStrategy();
using (PdfReader reader = new PdfReader(path))
{
StringBuilder text = new StringBuilder();
//string[] theLines;
//theLines = new string[COLUMNS];
//string thePage;
for (int i = 1; i <= reader.NumberOfPages; i++)
{
string thePage = "";
thePage = PdfTextExtractor.GetTextFromPage(reader, i, its);
string [] theLines = thePage.Split('\n');
foreach (var theLine in theLines)
{
text.AppendLine(theLine);
}
// text.AppendLine(" ");
// Array.Clear(theLines, 0, theLines.Length);
// thePage = "";
}
return text.ToString();
}
}
A strategy object collects text data and does not know if a new page has started or not.
Thus, use a new strategy object for each page.
I am new to JasperReports. I can create a simple PDF document with Javabean datasource. In my project I have created two separate pdf document with separate javabean datasource. Now I want to merge both documents into a single document. Can anyone tell me how to merge both documents into single document using JasperReports?
unfortunately the solution is build a sub report and use the 2 different DataSource or what ever connection you used
but there is an easy way to get over with this question :D
just simple no new reports ..... Voilà
ok lets do it
JasperPrint jp1 = JasperFillManager.fillReport(url.openStream(), parameters,
new JRBeanCollectionDataSource(inspBean));
JasperPrint jp2 = JasperFillManager.fillReport(url.openStream(), parameters,
new JRBeanCollectionDataSource(inspBean));
ok we have over 2 records ..lets take our first record jp1 and add jp2 content into it
List pages = jp2 .getPages();
for (int j = 0; j < pages.size(); j++) {
JRPrintPage object = (JRPrintPage)pages.get(j);
jp1.addPage(object);
}
JasperViewer.viewReport(jp1,false);
This work like a charm .. with couple of loops you can merge any number of report together .. without creating new reports
http://lnhomez.blogspot.com/2011/11/merge-multiple-jasper-reports-in-to.html
You can use subreports for this. You dont have to recreate your current reports.
Create a master report, with 0 margins. Add all your reports to this as subreport and put condition that if datasource is available for this, only then print this report.
Now put all your individual datasources into one map data source and pass this datasource to master report.
Configute all subreports to the key in the map.
You can use use a list of JasperPrint like this:
List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
jasperPrintList.add(JasperFillManager.fillReport("Report_file1.jasper", getReportMap(1), new JREmptyDataSource()));
jasperPrintList.add(JasperFillManager.fillReport("Report_file2.jasper", getReportMap(2), new JREmptyDataSource()));
jasperPrintList.add(JasperFillManager.fillReport("Report_file3.jasper", getReportMap(3), new JREmptyDataSource()));
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("Report_PDF.pdf"));
SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
configuration.setCreatingBatchModeBookmarks(true);
exporter.setConfiguration(configuration);
exporter.exportReport();
Multiple Pages in one JasperPrint
Sample Code:
DefaultTableModel dtm = new DefaultTableModel(new Object[0][3], new String[]{"Id","Name","Family"});
String[] fields= new String[3];
boolean firstFlag=true;
JasperPrint jp1 =null;
JasperPrint jp2 =null;
for (int i=0 ; i<=pagesCount ; i++)
{
fields[0]= "id";
fields[1]= "name";
fields[2]= "family";
dtm.insertRow(0, fields);
try
{
Map<String, Object> params = new HashMap<String, Object>();
if (firstFlag)
{
jp1 = JasperFillManager.fillReport(getClass().getResourceAsStream(reportsource), params, new JRTableModelDataSource(dtm));
firstFlag=false;
}else
{
jp2 = JasperFillManager.fillReport(getClass().getResourceAsStream(reportsource), params, new JRTableModelDataSource(dtm));
jp1.addPage(jp2.getPages().get(0));
}
}catch (Exception e)
{
System.out.println(e.fillInStackTrace().getMessage());
}
}
JasperViewer.viewReport(jp1,false);
Lahiru Nirmal's answer was simple and to the point. Here's a somewhat expanded version that also copies styles and other things (not all of which I'm positive are crucial).
Note that all of the pages are of the same size.
public static JasperPrint createJasperReport(String name, JasperPrint pattern)
{
JasperPrint newPrint = new JasperPrint();
newPrint.setBottomMargin(pattern.getBottomMargin());
newPrint.setLeftMargin(pattern.getLeftMargin());
newPrint.setTopMargin(pattern.getTopMargin());
newPrint.setRightMargin(pattern.getRightMargin());
newPrint.setLocaleCode(pattern.getLocaleCode());
newPrint.setName(name);
newPrint.setOrientation(pattern.getOrientationValue());
newPrint.setPageHeight(pattern.getPageHeight());
newPrint.setPageWidth(pattern.getPageWidth());
newPrint.setTimeZoneId(pattern.getTimeZoneId());
return newPrint;
}
public static void addJasperPrint(JasperPrint base, JasperPrint add)
{
for (JRStyle style : add.getStyles())
{
String styleName = style.getName();
if (!base.getStylesMap().containsKey(styleName))
{
try
{
base.addStyle(style);
}
catch (JRException e)
{
logger.log(Level.WARNING, "Couldn't add a style", e);
}
}
else
logger.log(Level.FINE, "Dropping duplicate style: " + styleName);
}
for (JRPrintPage page : add.getPages())
base.addPage(page);
if (add.hasProperties())
{
JRPropertiesMap propMap = add.getPropertiesMap();
for (String propName : propMap.getPropertyNames())
{
String propValue = propMap.getProperty(propName);
base.setProperty(propName, propValue);
}
}
if (add.hasParts())
{
PrintParts parts = add.getParts();
Iterator<Entry<Integer, PrintPart>> partsIterator = parts.partsIterator();
while (partsIterator.hasNext())
{
Entry<Integer, PrintPart> partsEntry = partsIterator.next();
base.addPart(partsEntry.getKey(), partsEntry.getValue());
}
}
List<PrintBookmark> bookmarks = add.getBookmarks();
if (bookmarks != null)
for (PrintBookmark bookmark : bookmarks)
base.addBookmark(bookmark);
}
Then, to use it:
JasperPrint combinedPrint = createJasperReport("Multiple Reports",
print1);
for (JasperPrint addPrint : new JasperPrint[] { print1, print2, print3 })
addJasperPrint(combinedPrint, addPrint);
// Now do whatever it was you'd do with the JasperPrint.
String combinedXml = JasperExportManager.exportReportToXml(combinedPrint);
I see JasperReports now has a newer "Report Book" feature that might be a better solution, but I haven't used one yet.
I have a crystal report which gives me undefined error when opening document, does any one come across this type of error, below is the coding:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
///create instance of class first
ReportDocument rpDoc = new ReportDocument();
///load the report
rpDoc.Load(#"TicketingBasic.rpt");////------->>>problem is here
///pass the report to method for dataInfo
getDBInfo(rpDoc);
/// et the source for report to be displayed
CrystalReportViewer1.ReportSource = rpDoc;
}
protected static void getDBInfo(ReportDocument rpDoc)
{
///Connection Onject
ConnectionInfo cn = new ConnectionInfo();
///DataBase,Table, and Table Logon Info
Database db;
Tables tbl;
TableLogOnInfo tblLOI;
///Connection Declaration
cn.ServerName = "???????????";
cn.DatabaseName = "??????????";
cn.UserID = "?????????";
cn.Password = "????????????";
//table info getting from report
db = rpDoc.Database;
tbl = db.Tables;
///for loop for all tables to be applied the connection info to
foreach (Table table in tbl)
{
tblLOI = table.LogOnInfo;
tblLOI.ConnectionInfo = cn;
table.ApplyLogOnInfo(tblLOI);
table.Location = "DBO." + table.Location.Substring(table.Location.LastIndexOf(".") + 1);
}
db.Dispose();
tbl.Dispose();
}
}
Final code snippet is:
rpDoc.Load(Server.MapPath(#"TicketingBasic.rpt"));
Thank you all for the help.
The problem I am having now is report not printing or exporting to other types like .pdf,.xsl, .doc etc, any clue
so the error is literally "undefined error"? never seen that one before.
First guess is that you need the full physical path to the report.
rpDoc.Load(Server.MapPath(#"TicketingBasic.rpt"));
HttpServerUtility.MapPath
How are you handling the report outout?
When we do reports we set the file name:
ReportSource.Report.FileName = FileName;
Where filename is a string that is the name of the file (obviously). Then we select the report tables and export in whatever format. Try this.