The following is an example where the XSLT processor is invoked prior to the serializer: If you want the serializer to process the raw XSQL datagram, you can simply omit the href attrib
Trang 1In 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
Trang 2looks 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
Trang 3Figure 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
Trang 4wrapper.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.
Trang 5Here’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>
Trang 6<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>
Trang 7<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-Serializerinterface 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
Trang 8Now 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>”);
}
Trang 9The 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>
Trang 10select 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.