我一直在尝试为客户发票生成PDF文件很长一段时间。发票保存为xml文件。客户可以拥有自己的xslt文件,以便拥有自己的发票视图(如果不是默认的,则用作xslt)。
我的问题是将XML /(X)HTML文件转换为pdf文件。我已经阅读了几乎所有的库来做这件事,并试图几乎改变所有库。
1)Apache FOP
http://www.javaworld.com/article/2071749/java-app-dev/convert-html-content-to-pdf-format.html
我使用默认的xslt和jtidy将发票xml转换为xhtml。然后我尝试使用Antenna House提供的XSL-FO将生成的xhtml转换为pdf.I设法生成一个只有标题的pdf文件。也没有成功。下面这样做的代码。
TransformerFactory factory = TransformerFactory.newInstance();
Source xslt = new StreamSource(getClass().getResourceAsStream("/xslts/general.xslt"));
// xslt.setSystemId("/xslts/general.xslt");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
Transformer transformer = factory.newTransformer(xslt);
DOMSource domSource = new DOMSource(document);
transformer.transform(domSource, result);
String strResult = writer.toString();
Tidy tidy = new Tidy();
// tidy.setDropEmptyParas(true);
// tidy.setJoinStyles(true);
tidy.setInputEncoding("UTF-8");
tidy.setOutputEncoding("UTF-8");
tidy.setXHTML(true);
tidy.setMakeClean(true);
tidy.setForceOutput(true);
ByteArrayInputStream boas = new ByteArrayInputStream(strResult.getBytes("UTF-8"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileOutputStream baoOut = new FileOutputStream(new File("C:\\Users\\xxx\\out.pdf"));
Document tiedDoc = tidy.parseDOM(boas, bos);
DOMSource tiedDocDomSource = new DOMSource(tiedDoc);
StringWriter writer2 = new StringWriter();
StreamResult result2 = new StreamResult(writer2);
Transformer xsl2foTrans = factory.newTransformer(new StreamSource(getClass().getResourceAsStream("/xslt/xhtml2fo.xsl")));
xsl2foTrans.transform(tiedDocDomSource, result2);
// // ab hier
final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
File userConfig = new File("C:\\Users\\xxx\\Desktop\\pdfWork\\fop.xconf");
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup output stream. Note: Using BufferedOutputStream
// for performance reasons (helpful with FileOutputStreams).
OutputStream out = baoOut;
out = new BufferedOutputStream(out);
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup JAXP using identity transformer
transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(new StringReader(writer2.toString()));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
out.close();
2)IText
据我所知,我们应该为IText提供有效的xhtml来生成PDF文件。所以我使用default.xslt将invoice xml转换为html,然后使用带有setXhtml选项的jtidy将xhtml转换为xhtml。我设法从给定的xhtml生成pdf文件。但pdf渲染效果不佳。不知何故,样式标签中的css无法识别。没有成功。在下面执行此操作的代码
StreamSource xslt = new StreamSource(getClass().getResourceAsStream("/xslt/general.xslt"));
// StreamSource xslt = new StreamSource(new FileInputStream(new File("C:\\Users\\XXX\\Desktop\\pdfWork\\firm.xslt")));
TransformerFactory factory = TransformerFactory.newInstance();
// Source xslt = new StreamSource(getClass().getResourceAsStream("/xslts/general.xslt"));
// xslt.setSystemId("/xslts/general.xslt");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
Transformer transformer = factory.newTransformer(xslt);
DOMSource domSource = new DOMSource(document);
transformer.transform(domSource, result);
String strResult = writer.toString();
Tidy tidy = new Tidy();
// tidy.setDropEmptyParas(true);
tidy.setJoinStyles(true);
tidy.setInputEncoding("UTF-8");
tidy.setOutputEncoding("UTF-8");
tidy.setXHTML(true);
tidy.setMakeClean(true);
tidy.setForceOutput(true);
ByteArrayInputStream boas = new ByteArrayInputStream(strResult.getBytes("UTF-8"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileOutputStream baoOut = new FileOutputStream(new File("C:\\Users\\XXX\\Desktop\\pdfWork\\out.pdf"));
tidy.parseDOM(boas, bos);
com.itextpdf.text.Document documentText = new com.itextpdf.text.Document(PageSize.LETTER); // PageSize.A4, 10.0F, 10.0F, 10.0F, 0.0F
PdfWriter pdfWriter = PdfWriter.getInstance(documentText, new FileOutputStream(new File("C:\\Users\\Onur\\Desktop\\pdfWork\\out.pdf")));
documentText.open();
// documentText.open();
// HTMLWorker htmlWorker = new HTMLWorker(documentText);
// htmlWorker.parse(new StringReader(IOUtils.toString(new ByteArrayInputStream(bos.toByteArray()), "UTF-8")));
// documentText.close();
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
worker.parseXHtml(pdfWriter, documentText, new StringReader(IOUtils.toString(new ByteArrayInputStream(bos.toByteArray()))));
documentText.close();
3)飞碟
我做了几乎与IText相同的步骤。我设法用公认的css样式标签生成PDF。我遇到的单个问题是表和一些元素溢出。它们不适合页面。我用
中建议的页面规则解决了这个问题How can i make my html page to be fit in the pdf using Flying Saucer
Document document = // invoice as document
StreamSource xslt = new StreamSource(getClass().getResourceAsStream("/xslt/general.xslt"));
TransformerFactory factory = TransformerFactory.newInstance();
// Source xslt = new StreamSource(getClass().getResourceAsStream("/xslts/general.xslt"));
// xslt.setSystemId("/xslts/general.xslt");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
Transformer transformer = factory.newTransformer(xslt);
DOMSource domSource = new DOMSource(document);
transformer.transform(domSource, result);
String strResult = writer.toString();
Tidy tidy = new Tidy();
tidy.setInputEncoding("UTF-8");
tidy.setOutputEncoding("UTF-8");
tidy.setXHTML(true);
tidy.setMakeClean(true);
tidy.setForceOutput(true);
ByteArrayInputStream boas = new ByteArrayInputStream(strResult.getBytes("UTF-8"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileOutputStream baoOut = new FileOutputStream(new File("C:\\Users\\XXX\\Desktop\\pdfWork\\out2.pdf"));
tidy.parseDOM(boas, bos);
System.out.println(bos.toString("UTF-8"));
ITextRenderer renderer = new ITextRenderer();
renderer.getFontResolver().addFont("/unicode/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// renderer.setDocument();
renderer.setDocumentFromString(IOUtils.toString(new ByteArrayInputStream(bos.toByteArray())));
// renderer.setPDFVersion('');
renderer.layout();
renderer.createPDF(baoOut);
renderer.finishPDF();
baoOut.flush();
baoOut.close();
正如我所说,我设法使用飞碟从xhtml生成PDF文件。但是我必须在general.xslt中添加页面规则和一些内联样式来执行此操作。但问题是每个客户都可以拥有自己的xslt用于发票视图。所以我不想触摸和更改xslt。 general.xslt可以从下面的链接下载。我怎样才能实现这一目标?可能吗 ?或者我做错了什么?在此先感谢!
http://www.efatura.gov.tr/dosyalar/kilavuzlar/UBL-TR1.2_Paketi.zip