当前位置: 首页 > 工具软件 > FOP > 使用案例 >

简单地利用FOP工具把XML文件转换PDF

桑鸿志
2023-12-01
package com.cisetech.put.utils.fop;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.avalon.framework.logger.Logger;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

/**
 * FopReport
 * @author bin.yin 2012/12/23
 */
public class FopReport {
    private static Logger log = new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG);
    // Step 1: Construct a FopFactory
    private static final FopFactory fopFactory = FopFactory.newInstance();

    /**
     * 根据xsl模板及xml数据文件生成pdf
     * @param xsltFile xsl模板
     * @param xmlFile xml数据文件
     * @return ReportData
     * @throws Exception
     * @author bin.yin 2012/12/25
     */
    public static ReportData createReport(String xsltFile, String xmlFile) throws Exception {
        ReportData reportData = new ReportData();
        reportData.setContentType("application/pdf");
        fopFactory.setUserConfig("conf/fop.xml");

        // Step 2: Set up output stream.
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            // Step 3: Construct fop with desired output format
            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);

            // Step 4: Setup XSLT using identity transformer
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(new StreamSource(new File(xsltFile)));

            // Step 5: Setup input and output for XSLT transformation
            Source src = new StreamSource(new File(xmlFile));
            // Source src = new StreamSource(new StringReader(myString));

            // Step 6: Resulting SAX events (the generated FO) must be piped through to FOP
            Result res = new SAXResult(fop.getDefaultHandler());

            // Step 7: Start XSLT transformation and FOP processing
            transformer.transform(src, res);

            reportData.setData(out.toByteArray());
        } catch(Exception e) {
            throw e;
        } finally {
            out.close();
        }
        return reportData;
    }

    /**
     * 根据xsl模板及xml字节数组生成pdf
     * @param xsltFile xsl模板
     * @param bXmlData xml字节数组 eg. StringBuffer buf = new StringBuffer(); buf.getBytes("UTF-8");
     * @return ReportData
     * @throws Exception
     * @author bin.yin 2012/12/25
     */
    public static ReportData createReport(String xsltFile, byte[] bXmlData) throws Exception {
        ReportData reportData = new ReportData();
        try {
            // convert xml bytes to a temp file
            File xmlFile = File.createTempFile("FOP", ".tmp");
            FileOutputStream fos = new FileOutputStream(xmlFile);
            fos.write(bXmlData);
            fos.close();

            reportData = createReport(xsltFile, xmlFile.getAbsolutePath());
            // delete temp file
            xmlFile.delete();
        } catch (Exception e) {
            throw e;
        }
        return reportData;
    }

    public static void main(String[] args) {
        long t0 = System.currentTimeMillis();
        try {
//          StringBuffer buf = new StringBuffer();
//          buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
//          buf.append("<ItemListReport>");
//          buf.append("    <ReportHeader>");
//          buf.append("        <Title>附加条款</Title>");
//          buf.append("        <PartyA>上海信息技术有限公司B</PartyA>");
//          buf.append("        <PartyB>上海信息技术有限公司B</PartyB>");
//          buf.append("    </ReportHeader>");
//          buf.append("    <ReportBody>");
//          buf.append("        <Table>");
//          buf.append("            <TableRow>");
//          buf.append("                <ItemName>附加条款1</ItemName>");
//          buf.append("                <ItemTime>2012-12-23 09:03</ItemTime>");
//          buf.append("            </TableRow>");
//          buf.append("            <TableRow>");
//          buf.append("                <ItemName>上海信息技术有限公司附加条款1</ItemName>");
//          buf.append("                <ItemTime>2012-12-23 09:03</ItemTime>");
//          buf.append("            </TableRow>");
//          buf.append("        </Table>");
//          buf.append("    </ReportBody>");
//          buf.append("    <ReportFooter>");
//          buf.append("        <PrintDate>2012-12-12</PrintDate>");
//          buf.append("        <ReportNo>010123456789</ReportNo>");
//          buf.append("    </ReportFooter>");
//          buf.append("</ItemListReport>");
//          
            long t = System.currentTimeMillis();
            //ReportData data = FopReport.createReport("report\\sample\\Sample.xsl", buf.toString().getBytes("UTF-8"));
            ReportData data = FopReport.createReport("report\\sample\\Sample.xsl", "report\\sample\\Sample.xml");
            long t1 = System.currentTimeMillis();
            log.debug("time:" + (t1 - t));
            FileOutputStream fos = new FileOutputStream("G:/sample.pdf");
            fos.write(data.getData());
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.debug("use time:" + (System.currentTimeMillis() - t0));
    }
}
package com.cisetech.put.utils.fop;

import java.io.Serializable;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * @author bin.yin 2012/12/22
 * @version 1.0
 */
public class ReportData implements Serializable {
    private static final long serialVersionUID = -2722248902864797698L;

    private byte[] mbData = null;
    private String msContentType = null;

    public byte[] getData() {
        return mbData;
    }
    public void setData(byte[] pData) {
        mbData = pData;
    }
    public String getContentType() {
        return msContentType;
    }
    public void setContentType(String pContentType) {
        msContentType = pContentType;
    }
}

FOP.XML文件内容

<?xml version="1.0"?>
<!-- $Id: fop.xml 901793 2012-12-21 bin.yin $ -->
<!-- NOTE: This is the version of the configuration -->
<fop version="1.0">

  <!-- Base URL for resolving relative URLs -->
  <base>.</base>

  <!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
  <source-resolution>72</source-resolution>
  <!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
  <target-resolution>72</target-resolution>

  <!-- Default page-height and page-width, in case value is specified as auto -->
  <default-page-settings height="29.7cm" width="21cm"/>

  <!-- Information for specific renderers -->
  <!-- Uses renderer mime type for renderers -->
  <renderers>
    <renderer mime="application/pdf">
      <filterList>
        <!-- provides compression using zlib flate (default is on) -->
        <value>flate</value>
      </filterList>

      <fonts>
        <!-- embedded fonts -->
        <!--
        This information must exactly match the font specified
        in the fo file. Otherwise it will use a default font.

        For example,
        <fo:inline font-family="Arial" font-weight="bold" font-style="normal">
            Arial-normal-normal font
        </fo:inline>
        for the font triplet specified by:
        <font-triplet name="Arial" style="normal" weight="bold"/>

        If you do not want to embed the font in the pdf document
        then do not include the "embed-url" attribute.
        The font will be needed where the document is viewed
        for it to be displayed properly.

        possible styles: normal | italic | oblique | backslant
        possible weights: normal | bold | 100 | 200 | 300 | 400
                          | 500 | 600 | 700 | 800 | 900
        (normal = 400, bold = 700)
        -->

        <font metrics-url="conf/fonts/arial.xml" kerning="yes" embed-url="conf/fonts/arial.ttf">
          <font-triplet name="Arial" style="normal" weight="normal"/>
          <font-triplet name="Arial" style="italic" weight="normal"/>
        </font>
        <font metrics-url="conf/fonts/arialb.xml" kerning="yes" embed-url="conf/fonts/arialb.ttf">
          <font-triplet name="Arial" style="normal" weight="bold"/>
          <font-triplet name="Arial" style="italic" weight="bold"/>
        </font>
        <font metrics-url="conf/fonts/SimHei.xml" kerning="yes" embed-url="conf/fonts/SimHei.ttf">
          <font-triplet name="SimHei" style="normal" weight="normal"/>
          <font-triplet name="SimHei" style="normal" weight="bold"/>
          <font-triplet name="SimHei" style="italic" weight="normal"/>
          <font-triplet name="SimHei" style="italic" weight="bold"/>
        </font>
        <font metrics-url="conf/fonts/SimSun.xml" kerning="yes" embed-url="conf/fonts/SimSun.ttc">
          <font-triplet name="SimSun" style="normal" weight="normal" />
          <font-triplet name="SimSun" style="normal" weight="bold" />
          <font-triplet name="SimSun" style="italic" weight="normal" />
          <font-triplet name="SimSun" style="italic" weight="bold" />
        </font>
        <!--新宋体//-->
        <font metrics-url="conf/fonts/NSimSun.xml" kerning="yes" embed-url="conf/fonts/SimSun.ttc">
          <font-triplet name="NSimSun" style="normal" weight="normal" />
          <font-triplet name="NSimSun" style="normal" weight="bold" />
          <font-triplet name="NSimSun" style="italic" weight="normal" />
          <font-triplet name="NSimSun" style="italic" weight="bold" />
        </font>
        <font metrics-url="conf/fonts/Code39Seven.xml" kerning="yes" embed-url="conf/fonts/Code39Seven.ttf">
          <font-triplet name="Code39Seven" style="normal" weight="normal" />
        </font>
      </fonts>

      <!-- This option lets you specify additional options on an XML handler -->
      <!--xml-handler namespace="http://www.w3.org/2000/svg">
        <stroke-text>false</stroke-text>
      </xml-handler-->

    </renderer>

    <renderer mime="application/postscript">
      <!-- This option forces the PS renderer to rotate landscape pages -->
      <!--auto-rotate-landscape>true</auto-rotate-landscape-->

      <!-- This option lets you specify additional options on an XML handler -->
      <!--xml-handler namespace="http://www.w3.org/2000/svg">
        <stroke-text>false</stroke-text>
      </xml-handler-->
    </renderer>

    <renderer mime="image/png">
      <!--transparent-page-background>true</transparent-page-background-->
    </renderer>

    <renderer mime="image/tiff">
      <!--transparent-page-background>true</transparent-page-background-->
      <!--compression>CCITT T.6</compression-->
    </renderer>

    <renderer mime="text/xml">
    </renderer>

    <!-- RTF does not have a renderer
    <renderer mime="text/rtf">
    </renderer>
    -->

  </renderers>

</fop>

Sample.xml文件内容

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Sample.xsl" ?>
<ItemListReport>
    <ReportHeader>
        <Title>附加条款</Title>
        <PartyA>中国科技</PartyA>
        <PartyB>上海信息技术有限公司</PartyB>
    </ReportHeader>
    <ReportBody>
        <Table>
            <TableRow>
                <ItemName>附加条款1</ItemName>
                <ItemTime>2012-12-23 09:03</ItemTime>
            </TableRow>
            <TableRow>
                <ItemName>上海信息技术有限公司附加条款1</ItemName>
                <ItemTime>2012-12-23 09:03</ItemTime>
            </TableRow>
            <TableRow>
                <ItemName>上海信息技术有限公司附加条款1</ItemName>
                <ItemTime>2012-12-23 09:03</ItemTime>
            </TableRow>
            <TableRow>
                <ItemName>上海信息技术有限公司附加条款1</ItemName>
                <ItemTime>2012-12-23 09:03</ItemTime>
            </TableRow>
            <TableRow>
                <ItemName>上海信息技术有限公司附加条款1</ItemName>
                <ItemTime>2012-12-23 09:03</ItemTime>
            </TableRow>
        </Table>
    </ReportBody>
    <ReportFooter>
        <PrintDate>2012-12-12</PrintDate>
        <ReportNo>010123456789</ReportNo>
    </ReportFooter>
</ItemListReport>

Sample.xls

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">

    <!-- 根元素  -->
    <xsl:template match="/">
        <xsl:apply-templates select="ItemListReport" />
    </xsl:template>

    <!--主模板//-->
    <xsl:template match="ItemListReport">
        <xsl:processing-instruction name="cocoon-format">type="text/xslfo"</xsl:processing-instruction>
        <!--在此可以定义一些全局的风格信息,如字体等-->
        <fo:root font-family="SimSun" xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <!--版面定义//-->
            <fo:layout-master-set>
                <fo:simple-page-master master-name="main" margin-top="1cm" margin-bottom="1cm" margin-left="1cm" margin-right="1cm">
                    <!--主体//-->
                    <fo:region-body margin-top="1cm" margin-bottom="1cm" />
                    <!--页眉//-->
                    <fo:region-before extent="1cm" />
                    <!--页脚//-->
                    <fo:region-after extent="1cm" />
                </fo:simple-page-master>
            </fo:layout-master-set>

            <fo:page-sequence master-reference="main">
                <!--页眉显示内容-->
                <fo:static-content flow-name="xsl-region-before">
                    <fo:block font-size="10pt" text-align="end" line-height="12pt">PDF 报表样例</fo:block>
                    <!-- <fo:block text-align="end">
                        <fo:external-graphic src="report/sample/title.jpg"/>
                    </fo:block> -->
                </fo:static-content>
                <!--页脚显示内容-->
                <fo:static-content flow-name="xsl-region-after">
                    <fo:block line-height="10pt" font-size="10pt" text-align="center">
                        共<fo:page-number-citation ref-id="endofdoc"/>页<xsl:text>       </xsl:text>第<fo:page-number/>页
                    </fo:block>
                </fo:static-content>
                <!--页面主体内容-->
                <fo:flow flow-name="xsl-region-body">
                    <!--报表头-->
                    <xsl:apply-templates select="ReportHeader" />
                    <!--报表体(若有多个部分内容,参照下面一行重复)-->
                    <xsl:apply-templates select="ReportBody" />
                    <!--报表尾-->
                    <xsl:apply-templates select="ReportFooter" />
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>

    <!--报表头//-->
    <xsl:template match="ReportHeader">
        <!--标题-->
        <fo:block font-size="24pt" font-weight="bold" line-height="30pt" vertical-align="top"
            text-align-last="center" space-before.optimum="12pt">
            <xsl:value-of select="Title" />
        </fo:block>
        <!--用一个表格来格式化显示其余信息-->
        <fo:block font-size="12pt">
            <fo:table table-layout="fixed" width="100%" border-collapse="separate">
                <fo:table-column column-width="1.3cm" />
                <fo:table-column column-width="17.7cm" />
                <fo:table-body>
                    <fo:table-row>
                        <fo:table-cell text-align="start">
                            <fo:block><xsl:text>甲方:</xsl:text></fo:block>
                        </fo:table-cell>
                        <fo:table-cell text-align="start">
                            <fo:block><xsl:value-of select="PartyA" /></fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                    <fo:table-row>
                        <fo:table-cell text-align="start">
                            <fo:block><xsl:text>乙方:</xsl:text></fo:block>
                        </fo:table-cell>
                        <fo:table-cell text-align="start">
                            <fo:block><xsl:value-of select="PartyB" /></fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                </fo:table-body>
            </fo:table>
        </fo:block>
    </xsl:template>

    <!--报表主体(一般只有一个表格)//-->
    <xsl:template match="ReportBody">
        <xsl:apply-templates select="Table" />
    </xsl:template>

    <!--报表尾//-->
    <xsl:template match="ReportFooter">
        <fo:block font-size="12pt" line-height="15pt" text-align="start" space-before.optimum="12pt">
            <xsl:text>签订时间:</xsl:text>
            <xsl:value-of select="PrintDate" />
        </fo:block>
        <fo:block id="endofdoc"></fo:block>
        <fo:block font-family="Code39Seven" font-size="14pt" line-height="18pt">*<xsl:value-of select="ReportNo" />*</fo:block>
    </xsl:template>

    <!--表格数据//-->
    <xsl:template match="Table">
        <fo:block font-size="12pt">
            <fo:table table-layout="fixed" width="100%" border-collapse="separate"
                text-align="center" border-width="0.5pt" border-style="solid" space-before.optimum="12pt">
                <!-- 定义列(与实际列数严格一致) //-->
                <fo:table-column column-width="13cm" />
                <fo:table-column column-width="6cm" />
                <!-- 定义表头 //-->
                <fo:table-header>
                    <fo:table-row font-weight="bold" font-size="13pt" border-width="0.5pt" border-style="solid">
                        <fo:table-cell border-color="black" border-width="0.2pt" border-style="solid">
                            <fo:block>条款名称</fo:block>
                        </fo:table-cell>
                        <fo:table-cell border-color="black" border-width="0.2pt" border-style="solid">
                            <fo:block>录入时间</fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                </fo:table-header>
                <!-- 表格数据 //-->
                <fo:table-body>
                    <xsl:apply-templates select="TableRow" />
                </fo:table-body>
            </fo:table>
        </fo:block>
        <fo:block space-before.optimum="12pt">注:显示表格每一行的模板</fo:block>
    </xsl:template>

    <!--显示表格每一行的模板//-->
    <xsl:template match="TableRow">
        <fo:table-row space-before.optimum="3pt">
            <fo:table-cell border-color="black" border-width="0.2pt" border-style="solid">
                <fo:block><xsl:value-of select="ItemName" /></fo:block>
            </fo:table-cell>
            <fo:table-cell border-color="black" border-width="0.2pt" border-style="solid">
                <fo:block><xsl:value-of select="ItemTime" /></fo:block>
            </fo:table-cell>
        </fo:table-row>
    </xsl:template>
</xsl:stylesheet>

需要额外导入font。。。。未完待续

 类似资料: