Java 从FOP1.0升级到FOP2.4后遇到异常
使用相同的XML和XSL-FOP1.0可以很好地工作。但是升级到FOP2.4之后 在将xml转换为打印文档以便在TCP/IP打印机上打印时,我可以看到以下警告和异常 警告:第1页上fo:region after的内容超出块行进方向上的可用区域13483毫秒。(没有上下文信息可用) 例外情况:Java 从FOP1.0升级到FOP2.4后遇到异常,java,xml,xsl-fo,apache-fop,Java,Xml,Xsl Fo,Apache Fop,使用相同的XML和XSL-FOP1.0可以很好地工作。但是升级到FOP2.4之后 在将xml转换为打印文档以便在TCP/IP打印机上打印时,我可以看到以下警告和异常 警告:第1页上fo:region after的内容超出块行进方向上的可用区域13483毫秒。(没有上下文信息可用) 例外情况: java.lang.NullPointerException at org.apache.fop.render.AbstractRenderer.renderMainReference(A
java.lang.NullPointerException
at org.apache.fop.render.AbstractRenderer.renderMainReference(AbstractRenderer.java:527)
at org.apache.fop.render.AbstractRenderer.renderBodyRegion(AbstractRenderer.java:433)
at org.apache.fop.render.AbstractRenderer.renderRegionViewport(AbstractRenderer.java:380)
at org.apache.fop.render.AbstractRenderer.renderPageAreas(AbstractRenderer.java:345)
at org.apache.fop.render.java2d.Java2DRenderer.print(Java2DRenderer.java:1008)
at sun.print.RasterPrinterJob.printPage(RasterPrinterJob.java:2166)
at sun.print.RasterPrinterJob.print(RasterPrinterJob.java:1548)
at sun.print.Win32PrintJob.pageableJob(Win32PrintJob.java:576)
at sun.print.Win32PrintJob.print(Win32PrintJob.java:393)
at PrinterHandler.print(PrinterHandler.java:65)
at Test.main(Test.java:734)
使用FOP1.0时,不存在此问题。升级到FOP2.0后,我开始观察到这个异常,因此文档无法打印。请参阅我使用的以下代码
此外,我还下载了FOP2.4源代码,并查看以下代码片段。因此,任何人都可以建议我需要在代码或XSL-FO模式中进行哪些更改才能使这项工作正常进行。下面的API来自FOP2.4。我确实与FOP1.0进行了比较,并看到了许多与pageindex相关的更改
从AbstractRenderer.java:
'''
protected void renderMainReference(MainReference mainReference) {
//Few sample code snippets from FOP where exception seen
if (flow != null) {
// if direction is right to left, then end is left edge,
// else end is right edge (for top-bottom/bottom-top block
// progression directions)
// binding edge is on left edge for odd pages and
// on right edge for even pages
** int pageIndex = currentPageViewport.getPageIndex(); **
//Crashes as currentPageViewport is null
//More codes are below
}
下面的示例取自apache fop-2.4-bin\fop-2.4\fop\examples\embedding\java\embedding\。该程序是ExampleXML2FO.java和ExampleFO2JPSPrint.java的组合。我正在尝试将文档打印到打印机上,但上面出现了nullpointerexception。下面是复制此问题的完整代码
projectteam.xml
<?xml version="1.0" encoding="UTF-8"?>
<projectteam>
<projectname>The Killer Application</projectname>
<member>
<name>John Doe</name>
<function>lead</function>
<email>jon.doe@killerapp.fun</email>
</member>
</projectteam>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="versionParam" select="'1.0'"/>
<!-- ========================= -->
<!-- root element: projectteam -->
<!-- ========================= -->
<xsl:template match="projectteam">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt" font-weight="bold" space-after="5mm">Project: <xsl:value-of select="projectname"/>
</fo:block>
<fo:block font-size="12pt" space-after="5mm">Version <xsl:value-of select="$versionParam"/>
</fo:block>
<fo:block font-size="10pt">
<fo:table table-layout="fixed" width="100%" border-collapse="separate">
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="5cm"/>
<fo:table-body>
<xsl:apply-templates select="member"/>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- ========================= -->
<!-- child element: member -->
<!-- ========================= -->
<xsl:template match="member">
<fo:table-row>
<xsl:if test="function = 'lead'">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:if>
<fo:table-cell>
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
PrintHandler.java
//Java
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
//JAXP
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.TransformerException;
import javax.xml.transform.Source;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.render.print.PageableRenderer;
/**
* This class demonstrates the conversion of an XML file to an XSL-FO file
* using JAXP (XSLT).
*/
public class Test {
/**
* Converts an XML file to an XSL-FO file using JAXP (XSLT).
* @param xml the XML file
* @param xslt the stylesheet file
* @param fo the target XSL-FO file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
*/
public void convertXML2FO(File xml, File xslt, File fo)
throws IOException, TransformerException {
//Setup output
OutputStream out = new java.io.FileOutputStream(fo);
try {
//Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xslt));
//Setup input for XSLT transformation
Source src = new StreamSource(xml);
//Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new StreamResult(out);
//Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
}
public static void printFO(File fo)
throws IOException, FOPException, TransformerException, PrintException {
// configure fopFactory as desired
final FopFactory FOP_FACTORY = FopFactory.newInstance(new File(".").toURI());
//Set up a custom user agent so we can supply our own renderer instance
FOUserAgent userAgent = FOP_FACTORY.newFOUserAgent();
PageableRenderer renderer = new PageableRenderer(userAgent);
userAgent.setRendererOverride(renderer);
// Construct FOP with desired output format
Fop fop = FOP_FACTORY.newFop(userAgent);
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// 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);
Doc doc = new SimpleDoc(renderer, DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
final PrintService printer = PrintServiceLookup.lookupDefaultPrintService();
final DocPrintJob printJob = printer.createPrintJob();
printJob.addPrintJobListener(null);
new PrinterHandler().print(doc);
}
/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleXML2FO\n");
System.out.println("Preparing...");
//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();
//Setup input and output files
File xmlfile = new File(baseDir, "xml/xml/projectteam.xml");
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File fofile = new File(outDir, "ResultXML2FO.fo");
System.out.println("Input: XML (" + xmlfile + ")");
System.out.println("Stylesheet: " + xsltfile);
System.out.println("Output: XSL-FO (" + fofile + ")");
System.out.println();
System.out.println("Transforming...");
Test app = new Test();
app.convertXML2FO(xmlfile, xsltfile, fofile);
printFO(fofile);
System.out.println(fofile);
System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}
}
/**
* PrinterHandler.java
*/
import javax.print.Doc;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.event.PrintJobEvent;
import javax.print.event.PrintJobListener;
import java.util.logging.Logger;
/**
* Class PrinterHandler sends a print job to the default printer and observes the printer register
* itself to the printer to inspect the state of the printer.
*
*/
public final class PrinterHandler implements PrintJobListener {
/** Logger. */
private final Logger mLogger = Logger.getLogger(PrinterHandler.class.getName());
/**
* Constructor.
*/
public PrinterHandler() {
}
/**
* Print the data contained in the Doc object.
* <p>
* The default printer configured in the operating system is used. If no default printer is
* found, the first printer in the list of configured printers is used.
*
* @param doc is a Doc object which contains the printable data.
* @return true if successfully printed.
*/
public boolean print( Doc doc) {
boolean success = true;
PrintService printer = PrintServiceLookup.lookupDefaultPrintService();
if (printer == null) {
final PrintService[] allPrinters =
PrintServiceLookup.lookupPrintServices(doc.getDocFlavor(), null);
if (allPrinters.length > 0) {
printer = allPrinters[0];
mLogger.info(printer.getName());
}
}
if (printer == null) {
mLogger.info( "no Printer");
} else {
final DocPrintJob printJob = printer.createPrintJob();
try {
mLogger.info("Printing document on " + printer.getName() + ".");
printJob.addPrintJobListener(this);
printJob.print(doc, null);
} catch (final Exception e) {
success = false;
System.out.println(e.getMessage());
mLogger.info("Detailed Print Problem");
e.printStackTrace();
System.out.println(e);
} finally {
printJob.removePrintJobListener(this);
}
}
return success;
}
/**
* Called to notify the client that data has been successfully transferred to the print
* service, and the client may free local resources allocated for that data.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printDataTransferCompleted(final PrintJobEvent pje) {
mLogger.info("Print Data Transfer Completed: " + pje.getPrintJob());
}
/**
* Called to notify the client that the job was canceled by a user or a program.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobCanceled(final PrintJobEvent pje) {
mLogger.info("Print Job Canceled : " + pje.getPrintJob());
}
/**
* Called to notify the client that the job completed successfully.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobCompleted(final PrintJobEvent pje) {
mLogger.info( "Print Job Completed : " + pje.getPrintJob());
}
/**
* Called to notify the client that the job failed to complete successfully and
* will have to be resubmitted.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobFailed(final PrintJobEvent pje) {
mLogger.info( "Print Job Failed : " + pje.getPrintJob());
}
/**
* Called to notify the client that no more events will be delivered.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobNoMoreEvents(final PrintJobEvent pje) {
mLogger.info( "Print Job No More Events: " + pje.getPrintJob());
}
/**
* Called to notify the client that an error has occurred that the user might be able to fix.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobRequiresAttention(final PrintJobEvent pje) {
mLogger.info("Print Job Requires Attention : " + pje.getPrintJob());
}
}
/**
*PrinterHandler.java
*/
导入javax.print.Doc;
导入javax.print.DocPrintJob;
导入javax.print.PrintService;
导入javax.print.PrintServiceLookup;
导入javax.print.event.PrintJobEvent;
导入javax.print.event.PrintJobListener;
导入java.util.logging.Logger;
/**
*类PrinterHandler将打印作业发送到默认打印机并观察打印机寄存器
*将其自身发送到打印机,以检查打印机的状态。
*
*/
公共最终类PrinterHandler实现了PrintJobListener{
/**记录器*/
私有最终记录器mLogger=Logger.getLogger(PrinterHandler.class.getName());
/**
*构造器。
*/
公共印刷商(){
}
/**
*打印文档对象中包含的数据。
*
*将使用操作系统中配置的默认打印机。如果未使用默认打印机
*找到时,将使用已配置打印机列表中的第一台打印机。
*
*@param doc是包含可打印数据的doc对象。
*@如果打印成功,返回true。
*/
公共布尔打印(Doc){
布尔成功=真;
PrintService printer=PrintServiceLookup.lookupDefaultPrintService();
如果(打印机==null){
最终打印服务[]所有打印机=
PrintServiceLookup.lookupPrintServices(doc.getDocFlavor(),null);
如果(allPrinters.length>0){
打印机=所有打印机[0];
mLogger.info(printer.getName());
}
}
如果(打印机==null){
mLogger.info(“无打印机”);
}否则{
final DocPrintJob printJob=printer.createPrintJob();
试一试{
mLogger.info(“在“+printer.getName()+”上打印文档”);
addPrintJobListener(这个);
printJob.print(单据,空);
}捕获(最终异常e){
成功=错误;
System.out.println(e.getMessage());
mLogger.info(“详细打印问题”);
e、 printStackTrace();
系统输出打印ln(e);
}最后{
removePrintJobListener(这个);
}
}
回归成功;
}
/**
*调用以通知客户端数据已成功传输到打印
*服务,客户端可以释放为该数据分配的本地资源。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
公共作废打印数据传输完成(最终打印作业事件pje){
mLogger.info(“打印数据传输完成:+pje.getPrintJob());
}
/**
*调用以通知客户端作业已被用户或程序取消。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
公共作废打印作业已取消(最终打印作业事件pje){
mLogger.info(“打印作业已取消:+pje.getPrintJob());
}
/**
*调用以通知客户端作业已成功完成。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
公共作废打印作业已完成(最终打印作业事件pje){
mLogger.info(“打印作业已完成:+pje.getPrintJob());
}
/**
*调用以通知客户端作业未能成功完成,并且
*必须重新提交。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
public void printJobFailed(最终PrintJobEvent pje){
mLogger.info(“打印作业失败:+pje.getPrintJob());
}
/**
*调用以通知客户端不再传递事件。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
公共作废printJobNoMoreEvents(最终PrintJobEvent pje){
mLogger.info(“打印作业无更多事件:+pje.getPrintJob());
}
/**
*调用以通知客户端发生了用户可以修复的错误。
*
*@param pje生成此事件的作业。
*@see javax.print.event.PrintJobListener
*/
@凌驾
公共作废打印作业要求注意事项(最终打印作业事件pje){
mLogger.info(“打印作业需要注意:+pje.getPrintJob());
}
}
我怀疑XSL-FO中可能需要一些模式更改。但我不是