Java 从FOP1.0升级到FOP2.4后遇到异常

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

使用相同的XML和XSL-FOP1.0可以很好地工作。但是升级到FOP2.4之后

在将xml转换为打印文档以便在TCP/IP打印机上打印时,我可以看到以下警告和异常

警告:第1页上fo:region after的内容超出块行进方向上的可用区域13483毫秒。(没有上下文信息可用) 例外情况:

 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中可能需要一些模式更改。但我不是