Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 20 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
20
Dung lượng
317,98 KB
Nội dung
In both cases, you invoke a serializer by including a handler attribute in the xml- stylesheet processing instruction. The following is an example where the XSLT processor is invoked prior to the serializer: <?xml-stylesheet type=”text/xsl” href=”someStylesheet.xsl” serializer=”java:some.pkg.SomeSerializer”?> If you want the serializer to process the raw XSQL datagram, you can simply omit the href attribute: <?xml-stylesheet type=”text/xsl” serializer=”java:some.pkg.SomeSerializer”?> In most cases, you will want to run a stylesheet before handing the XML over to a serializer. This is especially true for serializers that utilize other technologies, such as SVG or FOP. FOP, for instance, expects its data to be in agreement with a certain schema. If you are writing your own custom serializer, you may find it easier to just process the raw datagram. However, this does make your work less reusable. What if you want to use your code outside of XSQL? You might have to transform the data to match the canonical datagram schema. Instead, you’ll probably want to create your own schema for your custom serializer. Creating PDFs with Apache FOP Many Web sites offer PDFs. They are better suited for printing and can be more pol- ished than HTML Web pages. You have complete control over fonts, formatting, and images. But the PDF file format is binary, making it tough to code to directly. This is where the Apache FOP project comes in. You can use it to create PDF documents on the fly. By using XSQL and Apache FOP together, you can create dynamic PDF documents based on your database data. This section covers the architecture of Apache FOP and how to use the XSQL FOP serializer. FOP Architecture FOP uses the second part of the XSL family: XSL-FO. You’re very familiar with XSLT, the first part. The aim of XSL-FO is quite different from XSLT. While XSLT is an XML application that gives you the ability to transform an XML document to some kind of output, XSL-FO is aimed at giving you great control over how the document 520 Chapter 19 looks. FOP is open source software that allows you to process and render XSL-FO documents. You can think of XSL-FO as an attempt to overcome the presentation shortcomings of HTML and CSS. For instance, how many times have you struggled to get your ele- ments positioned on the page just right? Once you get it right on one browser, you have to check other browsers. How many times have you printed a document and taken it with you to read, only to find that the printer had chopped off the last four words on the right-hand side? XSL-FO allows you to define exactly how items fit on a page and what the size and orientation of the page is. Assuming enough tool support, you could create a good-looking printed book by using XSL-FO. This isn’t really true with HTML and CSS. However, there isn’t a lot of client software out there that understands XSL-FO directly. Maybe at some point, all the Web browsers will be able to accept and render XSL-FO documents just as they can handle HTML documents today. For now, you use XSL-FO to create one of the following established formats that meets the same goals as XSL-FO: ■■ PDF: Adobe Portable Document Format ■■ PCL: Printer Control Language from HP ■■ PostScript ■■ SVG: Scalable Vector Graphics ■■ AWT: Java Abstract Window Toolkit ■■ MIF: Marker Interchange Format for Adobe FrameMaker You may be wondering, What does XSL-FO bring to the table? Why not just write one of these formats directly? First, you’d lose the benefits of a strong open standard. You’d also have to learn the intricacies of the underlying standard. Perhaps one the best benefits of XSL-FO is that you can easily use it in conjunction with XSLT stylesheets. You can transform an XSQL datagram in to an XSL-FO document. The XSQL FOP serializer hands it to FOP, which outputs the appropriate format. The archi- tecture appears in Figure 19.2. From the standpoint of the developer, you can consider that XSL-FO replaces HTML. Instead of writing an XSLT stylesheet that transforms the datagram in to HTML, you transform the datagram in to XSL-FO. Then, the serializer creates the out- put format. This is usually PDF. The XSQL FOP serializer that you’ll look at in the next section writes to PDF. However, if you need to write to one of the other standards you can easily write your own serializer. The details of XSL-FO aren’t covered in this book. Appendix A points to some resources online that can help you learn and use XSL-FO. Serializers 521 Figure 19.2 XSL-FO and FOP architecture. Using the XSQL FOP Serializer The XSQL FOP serializer comes with the XSQL distribution. You’ll need to do a little work before you can use it, though. First, you’ll need to download the release from Apache. Once that is installed, you need to set the classpath for your servlet engine so that it points to the correct jar files. From there, you should be able to verify your install by running the samples provided in the XSQL demos. The home page for FOP is http://xml.apache.org/fop. Before downloading a distribution, you should first check your XSQL release notes. They will specify the appropriate version of FOP to use with the XSQL FOP serializer. At the time of this writing, XSQL supports FOP 0.19.0. Once it is downloaded, you simply expand the dis- tribution file in to a convenient directory. Now you need to set up the classpath. If you are using the Oracle Apache server, you should add the following to your jserv.properties file: wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\fop.jar wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\lib\avalon-framework-cvs- 20020315.jar <ROWSET> <ROW> </ROW> </ROW> </ROW> </ROWSET> XSQL Datagram XSLT Processor XSLT Stylesheet xsl:fo Document PDF Document Client FOP Serializer Apache FOP 522 Chapter 19 wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\lib\batik.jar wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\lib\xalan-2.3.1.jar wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\lib\xercesImpl-2.0.1.jar wrapper.classpath=c:\xsql\Fop-0.19.0-CVS\lib\xml-apis.jar This takes care of FOP. You also need to make sure that the XSQL FOP serializer itself is installed. Here is the line that you need: wrapper.classpath=C:\xsql\lib\xsqlserializers.jar There should be a nickname for the XSQL FOP serializer in the XSQLConfig.xml file. You’ll need to have the nickname in place for the samples to work correctly. You’ll find it in the serializerdefs element. This is what it looks like: <serializer> <name>FOP</name> <class>oracle.xml.xsql.serializers.XSQLFOPSerializer</class> </serializer> You should be ready to go. There should be an FOP directory underneath your demos. If you installed XSQL on a local Web server, you should be able to access the demo with http://localhost/xsql/fop/emptable.xsql. This produces the output shown in Figure 19.3. Figure 19.3 Demo PDF output. Serializers 523 Here’s a closer look at what is going on. The XSQL looks quite like what you’ve seen before, except that a serializer is specified: <?xml version=”1.0”?> <?xml-stylesheet type=”text/xsl” href=”emptablefo.xsl” serializer=”FOP”?> <xsql:query connection=”demo” xmlns:xsql=”urn:oracle-xsql”> SELECT ENAME, SAL FROM EMP ORDER BY SAL asc </xsql:query> The stylesheet looks quite a bit different, though: <?xml version=”1.0”?> <fo:root xmlns:fo=”http://www.w3.org/1999/XSL/Format” xsl:version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”> <! defines the layout master > <fo:layout-master-set> <fo:simple-page-master master-name=”first” page-height=”29.7cm” page-width=”21cm” margin-top=”1cm” margin-bottom=”2cm” margin-left=”2.5cm” margin-right=”2.5cm”> <fo:region-body margin-top=”3cm”/> </fo:simple-page-master> </fo:layout-master-set> <! starts actual layout > <fo:page-sequence master-name=”first”> <fo:flow flow-name=”xsl-region-body”> <fo:block font-size=”24pt” font-family=”Garamond” line- height=”24pt” space-after.optimum=”3pt” font-weight=”bold” start- indent=”15pt”> Total of All Salaries is $<xsl:value-of select=”sum(/ROWSET/ROW/SAL)”/> </fo:block> <! Here starts the table > <fo:block border-width=”2pt”> <fo:table> <fo:table-column column-width=”4cm”/> <fo:table-column column-width=”4cm”/> <fo:table-body font-size=”10pt” font-family=”sans-serif”> <xsl:for-each select=”ROWSET/ROW”> <fo:table-row line-height=”12pt”> <fo:table-cell> <fo:block><xsl:value-of select=”ENAME”/></fo:block> 524 Chapter 19 </fo:table-cell> <fo:table-cell> <fo:block><xsl:value-of select=”SAL”/></fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> The best way to get an idea as to what the serializer is doing is to look at the XML that the serializer processes. You can do this by simply commenting out the serializer attribute in the XSQL page. This yields a document like the following. The document here is an abbreviated version of the document used to produce the PDF in Figure 19.3; it includes only three of the rows. <?xml version=”1.0” ?> <fo:root xmlns:fo=”http://www.w3.org/1999/XSL/Format”> <fo:layout-master-set> <fo:simple-page-master master-name=”first” page-height=”29.7cm” page-width=”21cm” margin-top=”1cm” margin-bottom=”2cm” margin-left=”2.5cm” margin-right=”2.5cm”> <fo:region-body margin-top=”3cm” /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-name=”first”> <fo:flow flow-name=”xsl-region-body”> <fo:block font-size=”24pt” font-family=”Garamond” line-height=”24pt” space-after.optimum=”3pt” font-weight=”bold” start-indent=”15pt”> Total of All Salaries is $14650 </fo:block> <fo:block border-width=”2pt”> <fo:table> <fo:table-column column-width=”4cm” /> <fo:table-column column-width=”4cm” /> <fo:table-body font-size=”10pt” font-family=”sans-serif”> <fo:table-row line-height=”12pt”> <fo:table-cell> <fo:block>SMITH</fo:block> </fo:table-cell> <fo:table-cell> Serializers 525 <fo:block>800</fo:block> </fo:table-cell> </fo:table-row> <fo:table-row line-height=”12pt”> <fo:table-cell> <fo:block>JAMES</fo:block> </fo:table-cell> <fo:table-cell> <fo:block>950</fo:block> </fo:table-cell> </fo:table-row> <fo:table-row line-height=”12pt”> <fo:table-cell> <fo:block>ALLEN</fo:block> </fo:table-cell> </fo:table-row> </fo:table-body> </fo:table> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> It looks quite a bit similar to HTML, but note that fonts and margins are defined precisely. This is the beauty of XSL-FO—that you are able to describe exactly what you want. A full treatment of XSL-FO is beyond the scope of this book. For more information, you should visit http://xml.apache.org/fop/index.html. This Web site not only describes the Apache FOP project but also provides links to resources for XSL-FO and describes the parts of the XSL-FO specification that aren’t yet covered by Apache FOP. Creating Custom Serializers You can create your own custom serializers in a manner similar to that for action han- dlers. You implement an interface and then point to the Java class in the XSQL page. But instead of having multiple serializers in the same page you can only have one. This section walks you through the steps for writing serializers. You start by creating a sim- ple text serializer. This should give you a good idea of how to program serializers. The second section shows you how to write binary serializers. There isn’t a lot of difference between writing text and writing binary serializers. In both cases, your class has to implement the oracle.xml.xsql.XSQLDocument- Serializer interface. These basic steps are expected for both text and binary serializers: 1. Set the content type. 2. Write the output. You have to set the content type before writing any output. When outputting text, you can optionally specify a character encoding. You can write to either a stream or a writer, though you shouldn’t try to write to both. 526 Chapter 19 Now it’s time for some examples, starting with a simple text serializer. Text Serializers As discussed previously, there isn’t a lot that you can accomplish with a text serializer that you can’t handle with an XSLT stylesheet. But from a learning perspective, the text serializer can be easier to understand. Here is a simple text serializer that outputs the skeleton of an XML document as HTML. Only the names of the elements are written. import oracle.xml.xsql.XSQLPageRequest; import oracle.xml.xsql.XSQLDocumentSerializer; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.io.PrintWriter; public class SimpleTextSerializer implements XSQLDocumentSerializer { public void serialize(Document doc, XSQLPageRequest env) { String mimeType=”text/html”; String encoding=env.getPageEncoding(); if (encoding!=null && encoding.length()>0) { mimeType=mimeType+”;charset=”+encoding; } env.setContentType(mimeType); PrintWriter out=env.getWriter(); The content type is set in the preceding lines. If a page encoding is specified in the XSQL page, it will be attached to the mime-type. You get the PrintWriter from the XSQLPageRequest object. Optionally, you could call getOutputStream() and write to a stream instead. However, you should try to write only to one or the other. The remainder of the serialize() method sets up the beginning and ending HTML and calls the displayElement() method. Element docElem=doc.getDocumentElement(); out.println(“<html>”); out.println(“<head><title>”+docElem.getTagName()+”</title></head>”); out.println(“<body><H1>Document: “+docElem.getTagName()+”</H1>”); out.println(“<table>”); displayElement(doc.getDocumentElement(),out,0); out.println(“</table>”); } Serializers 527 The displayElement() method is a recursive element that descends the docu- ment. The name for each element is printed, and then the method is called on each child of the elem element. The level argument represents the level in the tree at which the method is found. It is used to set the indentations properly. private void displayElement(Element elem, PrintWriter out, int level) { out.println(“<tr><td>”); out.println(getSpaces(level)+”<b>”+elem.getTagName()+”</b>”); out.println(“</td><tr>”); NodeList list=elem.getChildNodes(); for (int i=0;i<list.getLength();i++) { Node n=list.item(i); if (n.getNodeType()==Node.ELEMENT_NODE) { displayElement((Element)n,out,level+1); } } } The final method in the serializer is used to set the spacing. Three spaces are set for each level in depth. private String getSpaces(int num) { String s=””; for (int i=0;i<num*3;i++) { s=s+” ”; } return s; } } Now you need to invoke your serializer. The following XSQL page will apply only the serializer to the XSQL datagram. Since no stylesheet is specified, no XSLT transfor- mation will be performed prior to invoking the serializer. <?xml version=”1.0”?> <?xml-stylesheet serializer=”java:SimpleTextSerializer”?> <page xmlns:xsql=”urn:oracle-xsql” connection=”demo”> <xsql:query> 528 Chapter 19 select ename, job, sal from emp where deptno=20 order by sal </xsql:query> </page> This produces the output shown in Figure 19.4. For this example, you can see that the elements for the raw datagram are listed. You can also apply a serializer to the results of an XSLT transformation. The follow- ing XSQL page transforms the datagram with a stylesheet. The serializer is then called to process the results of that transformation. <?xml version=”1.0”?> <?xml-stylesheet type=”text/xsl” href=”emp-serializer.xsl” serializer=”java:SimpleTextSerializer”?> <page xmlns:xsql=”urn:oracle-xsql” connection=”demo”> <xsql:query> SELECT ename, job, sal FROM emp WHERE deptno=20 ORDER BY sal </xsql:query> </page> Figure 19.4 SimpleTextSerializer output. Serializers 529 [...]... general-purpose serializer that takes an SQL statement as input import oracle. xml.xsql.XSQLPageRequest; import oracle. xml.xsql.XSQLDocumentSerializer; import oracle. xml.parser.v2.XMLElement; import java.io.OutputStream; import java.io.PrintWriter; import java.io.InputStream; import org.w3c.dom.Document; import oracle. jdbc.driver.OracleResultSet; import oracle. sql.BLOB; Serializers import import import import java.sql.ResultSet;... use an OutputStream The following code is a simple binary serializer that reads an image file from the file system and writes it out In this example, the XML input is ignored import oracle. xml.xsql.XSQLPageRequest; import oracle. xml.xsql.XSQLDocumentSerializer; import import import import java.io.OutputStream; java.io.BufferedOutputStream; java.io.FileInputStream; java.io.BufferedInputStream; Serializers... just query the database with an action, as follows: SELECT file-name, content-type FROM binary_table WHERE id={@some-param} The last piece of the puzzle is the stylesheet that formats the query results so that... query Connection conn=DriverManager.getConnection(connectStr, username, password); Statement stmt = conn.createStatement (); ResultSet rset = stmt.executeQuery (cmd); //Get the blob data BLOB blob = ((OracleResultSet)rset).getBLOB(0); InputStream blobStream=blob.getBinaryStream(); //Get the output stream and set the mime type OutputStream out=env.getOutputStream(); env.setContentType(mimeType); //write... 536 Chapter 19 env.setContentType(“text/plain”); PrintWriter out=env.getWriter(); out.println(“An error has occurred”); out.println(e.getMessage()); } } } This code uses JDBC to access the database and Oracle JDBC connections to handle the BLOB data In this example, the connection is handled in the simplest manner However, it does mean that you’ll be opening and closing a connection on each request Some... document that looks like this: SELECT image FROM image_table WHERE id=5 image/jpeg jdbc :oracle: thin:@localhost:1521:ORCL momnpup momnpup This means that one of the products of your XSLT transformation is an SQL... points to the image_table: SELECT image_id FROM product WHERE id={product_id} Serializers This is just one possible example The idea is that you get... SELECT image FROM image_table WHERE id= image/jpeg jdbc :oracle: thin:@localhost:1521:ORCL momnpup momnpup In this example, only one value is dynamic—the . serializer that takes an SQL state- ment as input. import oracle. xml.xsql.XSQLPageRequest; import oracle. xml.xsql.XSQLDocumentSerializer; import oracle. xml.parser.v2.XMLElement; import java.io.OutputStream; import. java.io.PrintWriter; import java.io.InputStream; import org.w3c.dom.Document; import oracle. jdbc.driver.OracleResultSet; import oracle. sql.BLOB; 534 Chapter 19 import java.sql.ResultSet; import java.sql.Statement; import. an XML document as HTML. Only the names of the elements are written. import oracle. xml.xsql.XSQLPageRequest; import oracle. xml.xsql.XSQLDocumentSerializer; import org.w3c.dom.Document; import