XML::QOFQSF - convert personal data to and from QSF XML files

Support for the QOF SQLite backend will be added in a separate module in due course.


Version 0.05


Provides a single home for all QOF objects expressed as QSF XML. A similar module for the SQLite backend is also planned. To have your QOF object included, simply send me a sample QSF XML file. A script to create the content is also planned.

A little code snippet.

 use XML::QOFQSF qw(QSFParse QSFWrite);
 use Date::Parse;
 use Date::Format;

 my $file = "qsf-mileage.xml";
 my %obj = QSFParse("$file");
 my $expenses = $obj{'pilot_expenses'};

 my $exp_count = @$expenses;
 print "Status: $exp_count expenses\n";
 my $template = "%A, %o %B %Y";
 my $total_miles = 0;
 foreach my $a (@$expenses)
   if ($a->type_of_expense eq "Mileage")
      $total_miles += $a->expense_amount;
      print $a->expense_amount . " " . $a->distance_unit . " : ";
      print $a->expense_vendor . " " . $a->expense_city;
      print " on " . time2str($template, $a->expense_date) . "\n";

 print "Total: $total_miles\n";

 my $c = new Appointment;
 $c->description("short summary");
 $c->guid($guid_str);  # QOF identifier like 5429307bcae611b59b4e2bedc77b2d68
 $c->note("long description");
 $c->repeat_type("repeatNone"); # dictated by pilot-qof source
 $c->repeat_forever("false");   # boolean
 $c->use_alarm("false");        # boolean
 $c->untimed_event("false");    #boolean

 my %obj;
 my @datebook=();
 push @datebook, $c;

 $obj{'pilot_datebook'} = \@datebook;



XML::QOFQSF exports two functions, QSFParse to parse a QSF XML file and QSFWrite to write data to a new QSF XML file. QSFParse reads data from the file into an array of objects of each supported type and references to each array are added to the object_list hash using the object name as the key. A similar hash can be passed to QSFWrite to generate a new QSF XML file.

Query Object Framework (QOF)

QOF, the Query Object Framework, provides a set of C Language utilities for performing generic structured complex queries on a set of data held by a set of C/C++ objects. This framework is unique in that it does NOT require SQL or any database at all to perform the query. Thus, it allows programmers to add query support to their applications without having to hook into an SQL Database.

Typically, if you have an app, and you want to add the ability to show a set of reports, you will need the ability to perform queries in order to get the data you need to show a report. Of course, you can always write a set of ad-hoc subroutines to return the data that you need. But this kind of a programming style is not extensible: just wait till you get a user who wants a slightly different report.

The idea behind QOF is to provide a generic framework so that any query can be executed, including queries designed by the end-user. Normally, this is possible only if you use a database that supports SQL, and then only if you deeply embed the database into your application. QOF provides simpler, more natural way to work with objects.

XML::QOFQSF extends this functionality to provide a simple, scriptable, interface to QOF data. When combined with the SQL-type queries supported by the QOF application, this provides a flexible method for handling, organising, converting and synchronising all kinds of compatible data.

Currently, QOF applications are based around PIM data (Personal Information Management) like contacts, calendar, expenses and todo lists. QOF is also an integral part of GnuCash and support for financial objects is pending (when the cashutil application is stable). In theory, QOF can be used with any kind of data that can be expressed in the variables available.


pilot-qof objects (pilot_address, pilot_expenses, pilot_datebook and pilot_todo) are supported. gpe-expenses is also supported. Outline support is included for cashutil objects but as cashutil is currently unreleased, full support is pending.

XML::QOFQSF objects are identical to the Query Object Framework (QOF) Objects used by applications like pilot-qof. The module is not intended to be a perl binding of any kind, merely a data conduit that understands the various elements of a QOF Object.

The Perl structs follow the QSF XML tag names and XML::QOFQSF expects values that match the underlying QOF object - as output by QSF XML. Variable names must therefore comply with XML rules for attribute values and with Perl syntax rules - e.g. foo-bar is invalid, use foo_bar instead. The same variable names are also used as field names in SQLite.

Detailed information on QSF variables:

  • string : any valid XML/Perl string.

    guid : Original QOF GUID, if preserved, otherwise blank for new.

    boolean : valid XML boolean, true or false.

    numeric : Not fully supported in XML::QOFQSF yet, these are precise numerical variables expressed as a numerator and denominator: 599/100 = 5.99 or 5456321/148547 = 36.73127697 - see QOF for more information.

    time : xsd:dateTime format which follows the ISO 8601 standard in the Coordinated Universal Time (UTC) syntax to be timezone independent. This generates timestamps of the form: 2004-11-29T19:15:34Z - you can reproduce the same timestamps with time2str from Date::Format using the template: "%Y-%m-%dT%H:%M:%SZ" or with the GNU C Library formatting string %Y-%m-%dT%H:%M:%SZ - remember to use gmtime() NOT localtime()!. From the command line, use the -u switch with the date command: date -u +%Y-%m-%dT%H:%M:%SZ. Note that the QOF library can deal with dates far outside the range of GNU C, date and many Perl modules because dates are handled as 64bit signed values.

    gint32 : 32bit integer

    gint64 : 64bit integer

    double : Unused in XML::QOFQSF (no objects currently use it).

    char : Single character field.

    kvp : Key-value pairs. Incomplete support in XML::QOFQSF so far.

struct (ToDo => { "todo_note" => '$', "todo_description" => '$', "category" => '$', "guid" => '$', "date_due" => '$', "todo_priority" => '$', "todo_complete" => '$', "todo_length" => '$', });

<object type="pilot_todo" count="1"> <string type="todo_note"/> <string type="todo_description">short summary</string> <string type="category">Business</string> <guid type="guid">a018fa4d88d7439bbe0c94978ba78c82</guid> <time type="date_due">2005-07-27T00:00:00Z</time> <gint32 type="todo_priority">1</gint32> <gint32 type="todo_complete">1</gint32> <gint32 type="todo_length">0</gint32> </object>

QOF Objects can also reference other QOF Objects via the GUID - support for this functionality is pending in XML::QOFQSF.


QOF uses 128bit identifiers expressed as 32bit hexadecimal strings. Where these strings are preserved in the converted data (e.g. as UID fields), XML::QOFQSF can use these strings to recreate the original GUID. This can be used to retain data integrity by uniquely identifying instances across formats. If a GUID is lost for any reason, XML::QOFQSF will create a new GUID - methods exist in the main QOF library (written in C) to merge such instances into other datasets.


For detailed support on QOF Objects, QSF XML, XML::QOFQSF or datafreedom-perl, please use the QOF-devel mailing list:


XML::QOFQSF was written to support the 'datafreedom' scripts developed for 'pilot-qof' which will probably become a package in their own right.

Examples: New scripts are continually being added to the datafreedom packages. Some existing scripts packaged with datafreedom-perl include:

  • dfxml-invoice : parse a QSF XML file and prepare a simple invoice

    pilot-qof -x data.xml --invoice-city -t 2006-11-09 | dfxml-invoice -

  • dfical-datebook : parse an iCal file and create a QSF XML pilot_datebook instance

    dfical-datebook calendar.ics



Passed a QSF XML filename (or '-' for stdin), returns a hash of array references, indexed by the name of the objects found in the QSF XML file.


Passed a hash of array references containing QOF objects. The hash must be indexed by the name of the objects. Use QSFParse to obtain an example hash. Prints the XML to stdout.


Neil Williams, <codehelp at>


Please report any bugs or feature requests to bug-xml-qofqsf at, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.


You can find documentation for this module with the perldoc command.

    perldoc XML::QOFQSF

You can also look for information at:


  Copyright 2007 Neil Williams.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.