The New Halloween Document
How to use the HSSF prototype API
Capabilities

This release of the how-to outlines functionality for the CVS HEAD. Those looking for information on previous releases should look in the documentation distributed with that release.

This release allows numeric and string cell values to be written to or read from an XLS file as well as reading and writing dates. Also in this release is row and column sizing, cell styling (bold, italics, borders,etc), and support for both built-in and user defined data formats. New to this release is an event-based API for reading XLS files. It differs greatly from the read/write API and is intended for intermediate developers who need a smaller memory footprint. It will also serve as the basis for the HSSF Generator.

General Use
User API
Writing a new one

The high level API (package: org.apache.poi.hssf.usermodel) is what most people should use. Usage is very simple.

Workbooks are created by creating an instance of org.apache.poi.hssf.usermodel.HSSFWorkbook.

Sheets are created by calling createSheet() from an existing instance of HSSFWorkbook, the created sheet is automatically added in sequence to the workbook. Sheets do not in themselves have a sheet name (the tab at the bottom); you set the name associated with a sheet by calling HSSFWorkbook.setSheetName(sheetindex,"SheetName",encoding). The name may be in 8bit format (HSSFWorkbook.ENCODING_COMPRESSED_UNICODE) or Unicode (HSSFWorkbook.ENCODING_UTF_16). Default encoding is 8bit per char.

Rows are created by calling createRow(rowNumber) from an existing instance of HSSFSheet. Only rows that have cell values should be added to the sheet. To set the row's height, you just call setRowHeight(height) on the row object. The height must be given in twips, or 1/20th of a point. If you prefer, there is also a setRowHeightInPoints method.

Cells are created by calling createCell(column, type) from an existing HSSFRow. Only cells that have values should be added to the row. Cells should have their cell type set to either HSSFCell.CELL_TYPE_NUMERIC or HSSFCell.CELL_TYPE_STRING depending on whether they contain a numeric or textual value. Cells must also have a value set. Set the value by calling setCellValue with either a String or double as a parameter. Individual cells do not have a width; you must call setColumnWidth(colindex, width) (use units of 1/256th of a character) on the HSSFSheet object. (You can't do it on an individual basis in the GUI either).

Cells are styled with HSSFCellStyle objects which in turn contain a reference to an HSSFFont object. These are created via the HSSFWorkbook object by calling createCellStyle() and createFont(). Once you create the object you must set its parameters (colors, borders, etc). To set a font for an HSSFCellStyle call setFont(fontobj).

Once you have generated your workbook, you can write it out by calling write(outputStream) from your instance of Workbook, passing it an OutputStream (for instance, a FileOutputStream or ServletOutputStream). You must close the OutputStream yourself. HSSF does not close it for you.

Here is some example code (excerpted and adapted from org.apache.poi.hssf.dev.HSSF test class):

Reading or modifying an existing file

Reading in a file is equally simple. To read in a file, create a new instance of org.apache.poi.poifs.Filesystem, passing in an open InputStream, such as a FileInputStream for your XLS, to the constructor. Construct a new instance of org.apache.poi.hssf.usermodel.HSSFWorkbook passing the Filesystem instance to the constructor. From there you have access to all of the high level model objects through their assessor methods (workbook.getSheet(sheetNum), sheet.getRow(rownum), etc).

Modifying the file you have read in is simple. You retrieve the object via an assessor method, remove it via a parent object's remove method (sheet.removeRow(hssfrow)) and create objects just as you would if creating a new xls. When you are done modifying cells just call workbook.write(outputstream) just as you did above.

An example of this can be seen in org.apache.poi.hssf.dev.HSSF.

Event API

The event API is brand new. It is intended for intermediate developers who are willing to learn a little bit of the low level API structures. Its relatively simple to use, but requires a basic understanding of the parts of an Excel file (or willingness to learn). The advantage provided is that you can read an XLS with a relatively small memory footprint.

To use this API you construct an instance of org.apache.poi.hssf.eventmodel.HSSFRequest. Register a class you create that supports the org.apache.poi.hssf.eventmodel.HSSFListener interface using the HSSFRequest.addListener(yourlistener, recordsid). The recordsid should be a static reference number (such as BOFRecord.sid) contained in the classes in org.apache.poi.hssf.record. The trick is you have to know what these records are. Alternatively you can call HSSFRequest.addListenerForAllRecords(mylistener). In order to learn about these records you can either read all of the javadoc in the org.apache.poi.hssf.record package or you can just hack up a copy of org.apache.poi.hssf.dev.EFHSSF and adapt it to your needs. TODO: better documentation on records.

Once you've registered your listeners in the HSSFRequest object you can construct an instance of org.apache.poi.poifs.filesystem.FileSystem (see POIFS howto) and pass it your XLS file inputstream. You can either pass this, along with the request you constructed, to an instance of HSSFEventFactory via the HSSFEventFactory.processWorkbookEvents(request, Filesystem) method, or you can get an instance of DocumentInputStream from Filesystem.createDocumentInputStream("Workbook") and pass it to HSSFEventFactory.processEvents(request, inputStream). Once you make this call, the listeners that you constructed receive calls to their processRecord(Record) methods with each Record they are registered to listen for until the file has been completely read.

A code excerpt from org.apache.poi.hssf.dev.EFHSSF (which is in CVS or the source distribution) is reprinted below with excessive comments:

Low Level APIs

The low level API is not much to look at. It consists of lots of "Records" in the org.apache.poi.hssf.record.* package, and set of helper classes in org.apache.poi.hssf.model.*. The record classes are consistent with the low level binary structures inside a BIFF8 file (which is embedded in a POIFS file system). You probably need the book: "Microsoft Excel 97 Developer's Kit" from Microsoft Press in order to understand how these fit together (out of print but easily obtainable from Amazon's used books). In order to gain a good understanding of how to use the low level APIs should view the source in org.apache.poi.hssf.usermodel.* and the classes in org.apache.poi.hssf.model.*. You should read the documentation for the POIFS libraries as well.

HSSF Class/Test Application

The HSSF application is nothing more than a test for the high level API (and indirectly the low level support). The main body of its code is repeated above. To run it:

  • download the poi-alpha build and untar it (tar xvzf tarball.tar.gz)
  • set up your classpath as follows: export HSSFDIR={wherever you put HSSF's jar files} export LOG4JDIR={wherever you put LOG4J's jar files} export CLASSPATH=$CLASSPATH:$HSSFDIR/hssf.jar:$HSSFDIR/poi-poifs.jar:$HSSFDIR/poi-util.jar:$LOG4JDIR/jog4j.jar
  • type: java org.apache.poi.hssf.dev.HSSF ~/myxls.xls write

This should generate a test sheet in your home directory called "myxls.xls".

  • Type: java org.apache.poi.hssf.dev.HSSF ~/input.xls output.xls

    This is the read/write/modify test. It reads in the spreadsheet, modifies a cell, and writes it back out. Failing this test is not necessarily a bad thing. If HSSF tries to modify a non-existant sheet then this will most likely fail. No big deal.
Logging facility

Poi can dynamically select it's logging implementation. Poi trys to create a logger using the System property named "org.apache.poi.util.POILogger". Out of the box this can be set to one of three values:

  • org.apache.poi.util.CommonsLogger
  • org.apache.poi.util.NullLogger
  • org.apache.poi.util.SystemOutLogger

If the property is not defined or points to an invalid classthen the NullLogger is used.

Refer to the commons logging package level javadoc for more information concerning how to configure commons logging.

HSSF Developer's Tools

HSSF has a number of tools useful for developers to debug/develop stuff using HSSF (and more generally XLS files). We've already discussed the app for testing HSSF read/write/modify capabilities; now we'll talk a bit about BiffViewer. Early on in the development of HSSF, it was decided that knowing what was in a record, what was wrong with it, etc. was virtually impossible with the available tools. So we developed BiffViewer. You can find it at org.apache.poi.hssf.dev.BiffViewer. It performs two basic functions and a derivative.

The first is "biffview". To do this you run it (assumes you have everything setup in your classpath and that you know what you're doing enough to be thinking about this) with an xls file as a parameter. It will give you a listing of all understood records with their data and a list of not-yet-understood records with no data (because it doesn't know how to interpret them). This listing is useful for several things. First, you can look at the values and SEE what is wrong in quasi-English. Second, you can send the output to a file and compare it.

The second function is "big freakin dump", just pass a file and a second argument matching "bfd" exactly. This will just make a big hexdump of the file.

Lastly, there is "mixed" mode which does the same as regular biffview, only it includes hex dumps of certain records intertwined. To use that just pass a file with a second argument matching "on" exactly.

In the next release cycle we'll also have something called a FormulaViewer. The class is already there, but its not very useful yet. When it does something, we'll document it.

What's Next?

This release contains code that supports "internationalization" or more accurately non-US/UK languages; however, it has not been tested with the new API changes (please help us with this). We've shifted focus a bit for this release in recognition of the international support we've gotten. We're going to focus on western European languages for our first beta. We're more than happy to accept help in supporting non-Western European languages if someone who knows what they're doing in this area is willing to pitch in! (There is next to no documentation on what is necessary to support such a move and its really hard to support a language when you don't even know the alphabet).

This release of HSSF does not yet support Formulas. I've been focusing on the requests I've gotten in. That being said, if we get more user feedback on what is most useful first we'll aim for that. As a general principal, HSSF's goal is to support HSSF-Serializer (meaning an emphasis on write). We would like to hear from you! How are you using HSSF/POIFS? How would you like to use it? What features are most important first?