OpenOffice is an increasingly popular — and free — open source alternative to expensive commercial office software suites. Creating content and exporting existing content into OpenOffice can be cumbersome if you don't have the right tools.
Typically, dynamically creating an OpenOffice document or exporting your existing content into an OpenOffice document involves:
- A Web application running on a server to transform your content to the OpenDocument Format (ODF).
- Compressing the resulting content into the OpenOffice document archive.
- Storing the file somewhere or serving it to the user.
But what if you don't have access to server-side applications? Or you simply want to minimize server load by moving the process to the client?
In this article, learn how to use the Cross Platform Component Object Model (XPCOM) framework from Mozilla to speed development of your application. Examples show how to dynamically export existing XML content into an OpenOffice document using XPCOM components within the Firefox Extension. And, you're not limited to exporting just XML; you can process other types of content as long as it's supported by the transformation mechanism (for example, Extensible Stylesheet Language Transformations (XSLT)).
Before actually dynamically exporting content into OpenOffice, the next section covers the requirements for building an OpenOffice document.
The OpenOffice document is basically a compressed file consisting of a set of XML files to describe the different parts of the document, such as content and styles; a manifest; and a thumbnail.
Figure 1 shows the file structure you will get if you take an OpenOffice text document (.odt), rename it with a .zip extension, and extract it.
Figure 1. OpenOffice document structure
Table 1 briefly explains some of the files.
Table 1. OpenOffice document files
| File | Description |
|---|---|
| content.xml | Contains the actual content of the document. |
| meta.xml | Contains metadata information, such as creation date and author. |
| styles.xml | Defines formatting styles for paragraphs, characters, etc. |
To create a new OpenOffice document, the easiest and perhaps safest way is to edit an existing document. In this article, you'll only update content.xml where the actual content of the document is stored. The content.xml itself looks like Figure 2.
Figure 2. OpenOffice document's content.xml
For our examples, let's call the section before the actual content the content head and the section after the actual content the content tail. The actual content itself is the content body. You'll use these sections every time you build a new OpenOffice document.
Preparing the development environment
You need to do a couple of things in the Firefox Extension development environment in order to export to OpenOffice. Since you'll be creating a new OpenOffice document by editing an existing one, you need to:
- Include all the files in Figure 1 in the Firefox Extension package. You will use these files to build the new OpenOffice document.
- Store these files outside the chrome folder of the Firefox Extension. This is to ensure that the files are not compressed during extension packaging so you can retrieve them easily later on.
An example of how the files are stored within the Firefox Extension is shown below.
Figure 3. OpenOffice document files in the Firefox Extension structure
All files can be stored in the same folder. You'll put each file in the appropriate place within the archive when you build the OpenOffice document. xml2odt.xsl is the custom stylesheet file you will use to transform existing content into ODF.
The next step is to set several variables and constants to be used for file operations throughout the OpenOffice document generation process, such as locating and retrieving files. Listing 1 shows an example. You'll use the nsIExtensionManager XPCOM interface to set variables and constants.
Listing 1. Setting up variables and constants
var eid = "export2OO"; // extension id
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
var oopath = "export/oo/"; // path to the OpenOffice document files
var ooxslt = "xml2odt.xsl";
const PR_WRONLY = 0x02;
const PR_RDWR = 0x04;
const PR_CREATE_FILE = 0x08;
const PR_APPEND = 0x10;
const PR_TRUNCATE = 0x20;
const PR_USEC_PER_MSEC = 1000;
const time = Date.now();
|
All of the code in this article can be put anywhere as long as it can be accessed by Firefox Extension. Typically, you would store it in a JavaScript file (.js) inside the chrome folder and include it in the Firefox Extension main XUL file, as shown below.
Listing 2. Including code in Firefox Extension
<overlay id="export2OO"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript;version=1.7"
src="chrome://export2OO/content/export.js" />
|
Now that the development environment is prepared, the next section gets down to the real business.
Programmatically building an OpenOffice document
Three are three main tasks involved in dynamically exporting your existing content into an OpenOffice document:
- Transform existing content into OpenDocument format.
- Build a new OpenOffice document with the new content.
- Launch the newly created OpenOffice document automatically.
Transform existing content into OpenDocument format
You can easily transform existing content into ODF with Extensible Stylesheet Language Transformations (XSLT). For example, Listing 3 shows some content in XML format.
Listing 3. Content in XML
<h1>This is Heading 1</h1> <h3>This is Heading 3</h3> |
Listing 4 shows the same content presented in ODF.
Listing 4. Content in ODF
<text:h xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
text:style="Heading1" text:outline-level="1">
This is Heading 1
</text:h>
<text:h xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
text:style="Heading3" text:outline-level="3">
This is Heading 3
</text:h>
|
The ODF specification provides all sorts of information on defining and formatting styles (see Resources). Once your stylesheet file is ready, you can perform the transformation inside the Firefox Extension environment. Using the extension manager, locate the stylesheet file that will be used for the transformation. Listing 5 shows an example.
Listing 5. Locating XSLT file
// locate stylesheet file
var xslfile = em.getInstallLocation(eid).getItemFile(eid, oopath + ooxslt);
|
Next, load the stylesheet file.
Listing 6. Loading XSLT file
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components.interfaces.nsIScriptableInputStream);
var xsldata = "";
fstream.init(xslfile, -1, 0, 0);
sstream.init(fstream);
var tmp = sstream.read(4096);
while (tmp.length > 0) {
xsldata += tmp;
tmp = sstream.read(4096);
}
sstream.close();
fstream.close();
var parser = new DOMParser();
var xsldoc = parser.parseFromString(xsldata,"text/xml");
|
You can use the stylesheet to transform the content into ODF. In the
following example, xmldoc is the XML document of the existing content.
Listing 7. Transforming content into ODF with XSLT
var xsltprocessor = new XSLTProcessor();
xsltprocessor.importStylesheet(xsldoc);
var newcontentdoc = xsltprocessor.transformToFragment(xmldoc,document);
|
At this point, it's time to update content.xml with the new content. To make a valid OpenOffice content.xml, you need to include the appropriate content head and content tail (see Figure 2).
Listing 8. Updating content.xml with new content
// prepare new content
var contentbody = (new XMLSerializer()).serializeToString(newcontentdoc);
var newcontent = xmlheader + contenthead + contentbody + contenttail
// update content.xml
var contentfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "content.xml");
var fstream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
fstream.init(contentfile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666, 0);
fstream.write(newcontent, newcontent.length);
fstream.close();
|
You now have an updated content.xml. In the next section, you build the new OpenOffice document.
To build a new OpenOffice document, you need to create a new OpenOffice archive and add content.xml and the other required files to the archive. The example uses the nsIZipWriter XPCOM interface for this purpose.
The first step is to create the archive file and store it somewhere on the user's machine. The following example stores the new file in the desktop area, as shown in Listing 9. Depending on requirements, you might need to create a temporary file or store it in other places.
Listing 9. Creating new OpenOffice document archive
var odtfile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("Desk", Components.interfaces.nsIFile);
odtfile.append("new.odt");
odtfile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
var zipWriter = Components.Constructor("@mozilla.org/zipwriter;1", "nsIZipWriter");
var odt = new zipWriter ();
odt.open(odtfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE | PR_APPEND); |
Table 2 shows some commonly used values you can use in place of
Desk.
Table 2. Common directories for storing files
| File | Description |
|---|---|
| ProfD | Firefox Profile directory |
| Desk | Desktop directory (for example, ~/Desktop on Linux®, C:\Documents and Settings\username\Desktop on Windows®) |
| Home | Operating system root directory (for example, /root on Linux, C:\ on Windows) |
| TmpD | Operating system temporary directory |
The second step is to add the required OpenOffice document files to the archive. Keep in mind that you need to add each file to its appropriate place in the structure shown in Figure 1.
Listing 10. Adding OpenOffice document files to the archive
// locate file
var contentfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "content.xml");
// add file to archive
odt.addEntryFile("content.xml",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
contentfile, false);
// create directory
odt.addEntryDirectory("META-INF", time * PR_USEC_PER_MSEC, false);
// locate file
var manifestfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "manifest.xml");
// add file to specific directory in archive
odt.addEntryFile("META-INF/manifest.xml",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
manifestfile, false);
odt.addEntryDirectory("Thumbnails", time * PR_USEC_PER_MSEC, false);
var thumbfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "thumbnail.png");
odt.addEntryFile("Thumbnails/thumbnail.png",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
thumbfile, false);
var metafile = em.getInstallLocation(eid).getItemFile(eid, oopath + "meta.xml");
odt.addEntryFile("meta.xml",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
metafile, false);
var mimetypefile = em.getInstallLocation(eid).getItemFile(eid, oopath + "mimetype");
odt.addEntryFile("mimetype",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
mimetypefile, false);
var settingsfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "settings.xml");
odt.addEntryFile("settings.xml",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
settingsfile, false);
var stylesfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "styles.xml");
odt.addEntryFile("styles.xml",
Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
stylesfile, false);
// close the archive
odt.close();
|
Now that the new OpenOffice document creation is complete and the document is ready to use, you can launch it.
Launch the OpenOffice document
Launching is optional, since the new document has already been saved on your desktop area. The new document can be opened at any time manually, or it can be used as input for other processes.
If file association has been set properly, the code in the following example will automatically open the newly created document in OpenOffice.
Listing 11. Launching OpenOffice document automatically
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var odtURL = ios.newFileURI(odt);
location.href = odtURL.spec;
|
If file association has not been set, you are prompted by a window similar to the one shown below.
Figure 4. Opening OpenOffice document
That's all there is to it.
Once you build and install your Firefox Extension, the code in this article will give you an Export to OpenOffice functions right on the client.
XPCOM's rich libraries speed up development of your application and let you do things on the client side that were previously only possible on the server side. You now have a portable and cost-effective alternative to server-side solutions.
Learn
-
Read all about OpenOffice.org.
-
Read "An Introduction
to XPCOM" to speed development of your applications.
-
The Firefox Toolbar Tutorial
explains how to create a toolbar extension for the Firefox browser.
-
Mozilla Developer Center Extensions
has all the information you need for developing extensions for Mozilla
applications.
- Learn more about File
I/O, the XPCOM interface for file Input/Output.
-
Read how nsIZipWriter, the
XPCOM interface for data archiving, provides an easy way for scripts to archive
data in the ZIP file format.
-
"Manipulate
OpenOffice.org's XML-based document formats" provides an introduction to the OpenOffice document
structure.
- Read the Open
Document Format for Office Applications (OpenDocument) V1.1 OASIS Standard.
-
OpenDocument XML.org is the
official community gathering place and information resource for the OpenDocument Format (ODF) OASIS Standard (ISO/IEC 26300).
-
Take the XSLT Tutorial to learn how to use XSLT to transform XML documents into other formats, like XHTML.
-
To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Follow developerWorks on Twitter.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
-
Download OpenOffice and extensions.
-
XPCOM is a central
clearinghouse for information related to XPCOM.
-
Firefox Add-ons extend Firefox, letting you personalize your browsing experience.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download
IBM product evaluation versions
or explore
the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from
DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Participate in developerWorks blogs and get involved in the developerWorks community.




