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.
package org.mpxj.howto.write;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.writer.FileFormat;
import net.sf.mpxj.writer.UniversalProjectWriter;
public class MSPDI
{
public void write(ProjectFile project, String fileName) throws Exception
{
new UniversalProjectWriter(FileFormat.MSPDI).write(project, fileName);
}
}
using MPXJ.Net;
namespace MPXJ.Samples.HowToWrite;
public class MSPDI
{
public void Write(ProjectFile project, string fileName)
{
new UniversalProjectWriter(FileFormat.MSPDI).Write(project, fileName);
}
}
Using MSPDIWriter
If required, the MSPDIWriter
class can be used directly, which provides access
to additional options, as described below.
Microsoft Project Compatible Output
Microsoft Project has a non-standard way of representing negative duration values (it should have a minus sign as a prefix at the start of the XSD duration expression rather than embedded in it).
Originally MPXJ read and wrote correctly formatted XSD duration values, but unfortunately this meant that Project would not read these values correctly, and MPXJ would not be able to consume these values correctly from an MSPDI file written by Project. MPXJ has been updated so that it reads and writes the form of these duration values understood by Project, but this does mean that if you were previously expecting to be able to parse valid XSD duration values from output generated by MPXJ, that will no longer be the case.
To provide backward compatibility the MicrosoftProjectCompatibleOutput
flag
has been introduced. This defaults to true
so MSPDI files containing negative
durations written by MPXJ can be read by Project. If you need to produce
correctly formatted XSD durations for consumption by applications other than
Project you can set this flag to false
:
package org.mpxj.howto.write;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;
public class MSPDICompatibleOutput
{
public void write(ProjectFile project, String fileName) throws Exception
{
MSPDIWriter writer = new MSPDIWriter();
writer.setMicrosoftProjectCompatibleOutput(false);
writer.write(project, fileName);
}
}
using MPXJ.Net;
namespace MPXJ.Samples.HowToWrite;
public class MSPDICompatibleOutput
{
public void Write(ProjectFile project, string fileName)
{
var writer = new MSPDIWriter();
writer.MicrosoftProjectCompatibleOutput = false;
writer.Write(project, fileName);
}
}
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:
package org.mpxj.howto.write;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;
import net.sf.mpxj.mspdi.SaveVersion;
public class MSPDISaveVersion
{
public void write(ProjectFile project, String fileName) throws Exception
{
MSPDIWriter writer = new MSPDIWriter();
writer.setSaveVersion(SaveVersion.Project2002);
writer.write(project, fileName);
}
}
using MPXJ.Net;
namespace MPXJ.Samples.HowToWrite;
public class MSPDISaveVersion
{
public void Write(ProjectFile project, string fileName)
{
var writer = new MSPDIWriter();
writer.SaveVersion = SaveVersion.Project2002;
writer.Write(project, fileName);
}
}
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 and non-working days in
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:
package org.mpxj.howto.write;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;
public class MSPDITimephased
{
public void write(ProjectFile project, String fileName) throws Exception
{
MSPDIWriter writer = new MSPDIWriter();
writer.setWriteTimephasedData(true);
writer.write(project, fileName);
}
}
using MPXJ.Net;
namespace MPXJ.Samples.HowToWrite;
public class MSPDITimephased
{
public void Write(ProjectFile project, string fileName)
{
var writer = new MSPDIWriter();
writer.WriteTimephasedData = true;
writer.Write(project, fileName);
}
}
In this second example we're overriding the default behaviour as asking MPXJ to write an aggregated form of the timephased data:
package org.mpxj.howto.write;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.mspdi.MSPDIWriter;
public class MSPDITimephasedAggregate
{
public void write(ProjectFile project, String fileName) throws Exception
{
MSPDIWriter writer = new MSPDIWriter();
writer.setWriteTimephasedData(true);
writer.setSplitTimephasedAsDays(false);
writer.write(project, fileName);
}
}
using MPXJ.Net;
namespace MPXJ.Samples.HowToWrite;
public class MSPDITimephasedAggregate
{
public void Write(ProjectFile project, string fileName)
{
var writer = new MSPDIWriter();
writer.WriteTimephasedData = true;
writer.SplitTimephasedAsDays = true;
writer.Write(project, fileName);
}
}