Fork me on GitHub

How To: Write MSPDI files

Since Microsoft Project 2002, Microsoft Project has been able to read and write an XML-based data interchange format called MSPDI.

Writing MSPDI files

The sample code below illustrates how to write data to an MSPDI file.

import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;

...

MSPDIWriter writer = new MSPDIWriter();
writer.write(projectFile, outputFileName);

Using MSPDIWriter

Save Version

The MSPDI file contains a SaveVersion attribute which indicates the version of Microsoft Project used to save the file. The value of SaveVersion is defined by the net.sf.mpxj.mspdi.SaveVersion enum, which provides the following values:

Project2002
Project2003
Project2007
Project2010
Project2013
Project2016

By default MSPDIWriter sets the SaveVersion value to Project2016. The only functional difference this setting makes when writing MSPDI files is that the format of calendar exceptions changed in Project 2003 and onwards. MPXJ will always write calendar exceptions using the original Project 2002 format, and if the SaveVersion is set to Project2003 or later it will also write the new format data as well.

Here’s an example of the SaveVersion attribute being set to ensure that only the older style of calendar exceptions is written to the MSPDI file:

import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;
import net.sf.mpxj.mspdi.SaveVersion;
...

MSPDIWriter writer = new MSPDIWriter();
writer.setSaveVersion(SaveVersion.Project2002);
writer.write(projectFile, outputFileName);

Timephased Data

By default MSPDIWriter does not write timephased data to an MSPDI file. To enable writing timephased data, you can call the setWriteTimephasedData method.

When this setting is enabled, the default behaviour is for the timephased data is broken down into days when written to the file. If it better suits your use case (or you need a more compact file) you can choose to write an aggregated form of the timephased data by calling the setSplitTimephasedAsDays method and passing false. The difference between the two formats is that if for example you have a 10 day block with 8 hours work per day, this can either be represented as 10 entries in the file each for a single day with a value of 8 hours, or a single entry for a 10 day range with a value of 80 hours. Although the latter case is more compact, if you are consuming the MSPDI timephased data yourself you will need to differentiate between working an non-working days n order to break the single block down into smaller ranges. The default day-by-day format MPXJ writes does this for you automatically.

In the first example below we’re enabling timephased data, and using the default day-by-dat breakdown:

import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;

...

MSPDIWriter writer = new MSPDIWriter();
writer.setWriteTimephasedData(true);
writer.write(projectFile, outputFileName);

In this second example we’re overriding the default behaviour as asking MPXJ to write an aggregated form of the timephased data:

import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;

...

MSPDIWriter writer = new MSPDIWriter();
writer.setWriteTimephasedData(true);
writer.setSplitTimephasedAsDays(false);
writer.write(projectFile, outputFileName);