1. 程式人生 > >簡單地利用FOP工具把XML檔案轉換PDF

簡單地利用FOP工具把XML檔案轉換PDF

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。。。。未完待續