Author: Holyfair
E-Mail: Holyfair@sina.com
一. 序
在一些运用中,我们通常会把一些文本和配置信息转换成XML文件进行传输,修改,保存.特别是具有一定模板性质的文档用XML文件来实现其管理就显得相当的方便了.提供对于XML文件的操作的java API很多,诸于DOM,JDOM,Castor,SAX,XMLReader,XPath,XSLT等等. 具体的这些API的用法这里就不多提了. 当使用这些接口实现XML的操作后,对于有些文档而言最终必须呈现给用户看的还是我们通常所熟悉的WORD和PDF文档.我们这里就来看一下从一个XML文件到RTF和PDF文件转换的实现.
二. 从XML到PDF
对于一个具有一定模板性质的XML文件,我们可以用FOP API来实现其到PDF的转换.
FOP需要fop.jar. 我们可以到http://xml.apache.org/fop/ 上获取和了解其用法.
以一个一般复杂的XML文件为例:
要转换XML文档 test.xml 如下:
<FeatureSRS title="SRS"> <introduction> <objective>objective here</objective> <scope>scope here</scope> <responsibilities>responsibilities here</responsibilities> <references>reference here</references> <DAA> <term> term here </term> <definition> definition here </definition> </DAA> </introduction> <generalDescription> <featureName> <summary>summary here</summary> <breakdown>breakdown here</breakdown> </featureName> <requirement> <content> content here. </content> </requirement> <requirement> <content> content2 here. </content> </requirement> <featureInteractions>featureInteractions here</featureInteractions> </generalDescription> <strResources> <strResource> <estring> estring here </estring> <resourceid> resourceid here </resourceid> <rqmt> rqmt here. </rqmt> </strResource> </strResources> </FeatureSRS> |
对于这样一个XML文档,我们要将其转化成PDF格式必须建立一个XSL-FO文件,来定义对各element和value格
式的转换.
我们建立XSL-FO文件 test.xsl 如下:
<?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"/> <!-- ========================= --> <!-- root element: projectteam --> <!-- ========================= --> <xsl:template match="FeatureSRS"> <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="20pt" font-weight="bold" space-after="5mm" text-align="center">Cardiac Feature SRS </fo:block> <fo:block font-size="10pt"> <xsl:apply-templates/> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <!-- ========================= --> <!-- child element: member --> <!-- ========================= --> <xsl:template name="introduction" match="introduction"> <fo:block font-size="18pt" font-weight="bold" space-after="5mm">1. Intruction</fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">1.1 Objective</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:value-of select="objective"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">1.2 Scope</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:value-of select="scope"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">1.3. Responsibilities</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:value-of select="responsibilities"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">1.4. References</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:value-of select="references"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">1.5. Definitions, Acronyms, and Abbreviations</fo:block> <fo:block font-size="10pt" font-weight="bold" space-after="5mm" margin-left="5mm"> <fo:table table-layout="fixed" border="2cm" background-color="#fff2d9" > <fo:table-column column-width="4cm"/> <fo:table-column column-width="6cm"/> <fo:table-body> <fo:table-row border="2"> <fo:table-cell> <fo:block> <xsl:text>Term</xsl:text> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:text>Definition</xsl:text> </fo:block> </fo:table-cell> </fo:table-row> <xsl:for-each select="DAA"> <fo:table-row border="2"> <fo:table-cell> <fo:block> <xsl:value-of select="term"/> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:value-of select="definition"/> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </xsl:template> <xsl:template name="generalDescription" match="generalDescription"> <fo:block font-size="18pt" font-weight="bold" space-after="5mm">2. General Description</fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">2.1. Feature Name</fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="7mm">2.1.1. Feature Summary</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="9mm"> <xsl:value-of select="featureName/summary"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="7mm">2.1.2. Feature Breakdown</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="9mm"> <xsl:value-of select="featureName/breakdown"/> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">2.2. Feature Requirements</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:for-each select="requirement"> <xsl:value-of select="content"/> </xsl:for-each> </fo:block> <fo:block font-size="14pt" font-weight="bold" space-after="5mm" margin-left="5mm">2.3. Feature Interactions</fo:block> <fo:block font-size="10pt" font-weight="normal" space-after="5mm" margin-left="7mm"> <xsl:value-of select="featureInteractions"/> </fo:block> </xsl:template> <xsl:template name="strResources" match="strResources"> <fo:block font-size="18pt" font-weight="bold" space-after="5mm">3. String Resources </fo:block> <fo:block font-size="10pt" font-weight="bold" space-after="5mm" margin-left="5mm"> <fo:table table-layout="fixed" border="2cm" background-color="#fff2d9" > <fo:table-column column-width="4cm"/> <fo:table-column column-width="10cm"/> <fo:table-column column-width="4cm"/> <fo:table-body> <fo:table-row border="2"> <fo:table-cell> <fo:block> <xsl:text>English String</xsl:text> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:text>Resource ID</xsl:text> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:text>Rqmt</xsl:text> </fo:block> </fo:table-cell> </fo:table-row> <xsl:for-each select="strResource"> <fo:table-row border="2"> <fo:table-cell> <fo:block> <xsl:value-of select="estring"/> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:value-of select="resourceid"/> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block> <xsl:value-of select="rqmt"/> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </xsl:template> </xsl:stylesheet>
|
其具体的XSL-FO文件格式的语法可以参照一些其他资料.
建立好了此文件之后,我们就可以用FOP提供的一些接口方便的进行转换了.
FOP提供了XML->FO,XML->PDF,FO-PDF,OBJ->FO,OBJ->PDF的转换接口.
我们这里以XML->PDF的为例,其余的可以参照FOP包里相应的DEMO.
public class ExampleXML2PDF { public void convertXML2PDF(File xml, File xslt, File pdf) throws IOException, FOPException, TransformerException { Driver driver = new Driver(); Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO); driver.setLogger(logger); MessageHandler.setScreenLogger(logger); //Setup Renderer (output format) driver.setRenderer(Driver.RENDER_PDF); //Setup output OutputStream out = new java.io.FileOutputStream(pdf); try { driver.setOutputStream(out); //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 SAXResult(driver.getContentHandler()); //Start XSLT transformation and FOP processing transformer.transform(src, res); } finally { out.close(); } } public static void main(String[] args) { try { System.out.println("FOP ExampleXML2PDF/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, "test.xml"); File xsltfile = new File(baseDir, "test.xsl"); File pdffile = new File(outDir, "test.pdf"); System.out.println("Input: XML (" + xmlfile + ")"); System.out.println("Stylesheet: " + xsltfile); System.out.println("Output: PDF (" + pdffile + ")"); System.out.println(); System.out.println("Transforming..."); ExampleXML2PDF app = new ExampleXML2PDF(); app.convertXML2PDF(xmlfile, xsltfile, pdffile); System.out.println("Success!"); } catch (Exception e) { System.err.println(ExceptionUtil.printStackTrace(e)); System.exit(-1); } } } |
这样我们就很轻易地实现了XML文档到PDF文档的转换.
如果这些用在webservice的servlet中,想从xml文件直接生成pdf传输给浏览者而并不生成的pdf文件,我们可以如
下实现:
public class FOPServlet extends HttpServlet { public static final String FO_REQUEST_PARAM = "fo"; public static final String XML_REQUEST_PARAM = "xml"; public static final String XSL_REQUEST_PARAM = "xsl"; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { String xmlParam =getServletContext().getRealPath("WEB-INF/doc/xml/test.xml"); String xslParam =getServletContext().getRealPath("WEB-INF/doc/xsl/test.xsl"); if ((xmlParam != null) && (xslParam != null)) { XSLTInputHandler input = new XSLTInputHandler(new File(xmlParam), new File(xslParam)); renderXML(input, response); } else { PrintWriter out = response.getWriter(); out.println("<html><head><title>Error</title></head>/n"+ "<body><h1>FopServlet Error</h1><h3>No 'fo' "+ "request param given.</body></html>"); } } catch (ServletException ex) { throw ex; } catch (Exception ex) { throw new ServletException(ex); } } public void renderXML(XSLTInputHandler input, HttpServletResponse response) throws ServletException { try { ByteArrayOutputStream out = new ByteArrayOutputStream(); response.setContentType("application/pdf"); Driver driver = new Driver(); driver.setRenderer(Driver.RENDER_PDF); driver.setOutputStream(out); driver.render(input.getParser(), input.getInputSource()); byte[] content = out.toByteArray(); response.setContentLength(content.length); response.getOutputStream().write(content); response.getOutputStream().flush(); } catch (Exception ex) { throw new ServletException(ex); } } } |
三. XML to RTF
xml到rtf的转换稍微有一些麻烦,我们没有直接从XML到RTF的API, 我们将要用的JFor API还没有整合到FOP
中去. JFor API可以实现 从 FO文件到RTF文件的转换, 它也提供了consle接口.
我们可以从 www.jfor.org 上获取jfor相关信息.
我们从XML文件到RTF文件的转换可以分为两步:
1. 用FOP将 xml 转换成 fo
2. 用JFor将 fo 转换成RTF
3.1 用FOP将 xml 转换成 fo
这一步我们可以很轻易的沿用上面所述的方法,如下实现xml到fo 的转换,依然会用到上面所用的xml文件
和xsl-fo文件.
OutputStream foOut = new FileOutputStream(fofile); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(new StreamSource( xsltfile)); Source src = new StreamSource(xmlfile); Result res = new StreamResult(foOut); transformer.transform(src, res); foOut.close(); |
3.2 用JFor将 fo 转换成RTF
仅以Serlvet需求的实现为例:
InputStream foInput = new FileInputStream(fofile); InputSource inputSource = new InputSource(foInput); ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer output = new OutputStreamWriter(out); response.setContentType("application/msword"); new Converter(inputSource,output,Converter.createConverterOption ()); output.flush(); byte[] content = out.toByteArray(); System.out.println(out.toString()); response.setContentLength(content.length); response.getOutputStream().write(content); response.getOutputStream().flush(); foInput.close(); output.close(); out.close(); |
这样我们就成功地将xml转化成了RTF格式的文件.
本文仅简述了大体的实现过程,具体的细节可参照各技术点的详细自述.