diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68d988ee4f..1b85f64221 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
# Changelog
-## 12.9.1 (unreleased)
+## 12.9.2 (unreleased)
+
+## 12.9.1 (2024-04-17)
+* Fix an issue where `UniversalProjectReader` would raise an exception when handling an unknown file type.
+* Ensure that resource type is included as part of the resource assignment data when writing PMXML files.
## 12.9.0 (2024-04-11)
* Updated `UniversalProjectReader` to add `getProjectReaderProxy` methods to allow access to the instance of the reader class which will be used to read a schedule, prior to the schedule being read. This will allow the reader to be configured, or schedule to be ignored without reading its content.
diff --git a/build.xml b/build.xml
index a9c17d81d7..13e3bfb3ac 100644
--- a/build.xml
+++ b/build.xml
@@ -7,7 +7,7 @@
ConceptDrawProjectReader
class.
+
+
+
+
+
+
+
@@ -1675,6 +1672,7 @@ You'll find a general introduction to MPXJ's functionality here.
+ + + + + + + @@ -1624,6 +1621,7 @@diff --git a/docs/field-guide/index.html b/docs/field-guide/index.html index e56ca5b0d3..688b01b09e 100644 --- a/docs/field-guide/index.html +++ b/docs/field-guide/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-build/index.html b/docs/howto-build/index.html index d56651c858..f9ac62ef63 100644 --- a/docs/howto-build/index.html +++ b/docs/howto-build/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-com/index.html b/docs/howto-com/index.html index 7cf57fdbe7..12b541dbf7 100644 --- a/docs/howto-com/index.html +++ b/docs/howto-com/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-convert/index.html b/docs/howto-convert/index.html index ee6d83e2a9..3757ee7f86 100644 --- a/docs/howto-convert/index.html +++ b/docs/howto-convert/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-dotnet/index.html b/docs/howto-dotnet/index.html index 0f03f9db1a..b44bd98ca0 100644 --- a/docs/howto-dotnet/index.html +++ b/docs/howto-dotnet/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-asta/index.html b/docs/howto-read-asta/index.html index dce22ddf14..67e168c530 100644 --- a/docs/howto-read-asta/index.html +++ b/docs/howto-read-asta/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-conceptdraw/index.html b/docs/howto-read-conceptdraw/index.html index 6728f25bd3..512e23d9f1 100644 --- a/docs/howto-read-conceptdraw/index.html +++ b/docs/howto-read-conceptdraw/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-fasttrack/index.html b/docs/howto-read-fasttrack/index.html index 813881e2e7..b308591db4 100644 --- a/docs/howto-read-fasttrack/index.html +++ b/docs/howto-read-fasttrack/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-ganttdesigner/index.html b/docs/howto-read-ganttdesigner/index.html index 874c894cc2..ec48f546d6 100644 --- a/docs/howto-read-ganttdesigner/index.html +++ b/docs/howto-read-ganttdesigner/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-ganttproject/index.html b/docs/howto-read-ganttproject/index.html index f6dd3342c9..7d3409441a 100644 --- a/docs/howto-read-ganttproject/index.html +++ b/docs/howto-read-ganttproject/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-merlin/index.html b/docs/howto-read-merlin/index.html index cdfa1a0b55..2e15d689d4 100644 --- a/docs/howto-read-merlin/index.html +++ b/docs/howto-read-merlin/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-mpd/index.html b/docs/howto-read-mpd/index.html index d1db7b10c5..379951dfc4 100644 --- a/docs/howto-read-mpd/index.html +++ b/docs/howto-read-mpd/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-mpp/index.html b/docs/howto-read-mpp/index.html index 19a886c542..deadf315fd 100644 --- a/docs/howto-read-mpp/index.html +++ b/docs/howto-read-mpp/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-mpx/index.html b/docs/howto-read-mpx/index.html index 9a5139ac09..e0296d317f 100644 --- a/docs/howto-read-mpx/index.html +++ b/docs/howto-read-mpx/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-mspdi/index.html b/docs/howto-read-mspdi/index.html index 8ccd3efbbd..81f307f85a 100644 --- a/docs/howto-read-mspdi/index.html +++ b/docs/howto-read-mspdi/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-openplan/index.html b/docs/howto-read-openplan/index.html index 2007732a0c..ca18147263 100644 --- a/docs/howto-read-openplan/index.html +++ b/docs/howto-read-openplan/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-p3/index.html b/docs/howto-read-p3/index.html index 9d5e5ff3df..e4bc7726a3 100644 --- a/docs/howto-read-p3/index.html +++ b/docs/howto-read-p3/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-phoenix/index.html b/docs/howto-read-phoenix/index.html index 75819bbe57..9929daf7c6 100644 --- a/docs/howto-read-phoenix/index.html +++ b/docs/howto-read-phoenix/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-planner/index.html b/docs/howto-read-planner/index.html index 03d33ddbd6..913196566f 100644 --- a/docs/howto-read-planner/index.html +++ b/docs/howto-read-planner/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-plf/index.html b/docs/howto-read-plf/index.html index 3e28bf28a6..f9a4037d60 100644 --- a/docs/howto-read-plf/index.html +++ b/docs/howto-read-plf/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-pmxml/index.html b/docs/howto-read-pmxml/index.html index 7c1ba44ff6..24b08ff3c9 100644 --- a/docs/howto-read-pmxml/index.html +++ b/docs/howto-read-pmxml/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-primavera/index.html b/docs/howto-read-primavera/index.html index 7ea5a47990..76eb6a1969 100644 --- a/docs/howto-read-primavera/index.html +++ b/docs/howto-read-primavera/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-projectcommander/index.html b/docs/howto-read-projectcommander/index.html index 64adbb770b..35851db942 100644 --- a/docs/howto-read-projectcommander/index.html +++ b/docs/howto-read-projectcommander/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-projectlibre/index.html b/docs/howto-read-projectlibre/index.html index 3ca8f8a03b..af6a30c751 100644 --- a/docs/howto-read-projectlibre/index.html +++ b/docs/howto-read-projectlibre/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-schedule-grid/index.html b/docs/howto-read-schedule-grid/index.html index bbcee78125..0257aa9654 100644 --- a/docs/howto-read-schedule-grid/index.html +++ b/docs/howto-read-schedule-grid/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-sdef/index.html b/docs/howto-read-sdef/index.html index 5a2be6c7a2..c81c2ae924 100644 --- a/docs/howto-read-sdef/index.html +++ b/docs/howto-read-sdef/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-suretrak/index.html b/docs/howto-read-suretrak/index.html index 794c90f750..ba845fa8af 100644 --- a/docs/howto-read-suretrak/index.html +++ b/docs/howto-read-suretrak/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-synchro/index.html b/docs/howto-read-synchro/index.html index 662eae4943..928743c0e2 100644 --- a/docs/howto-read-synchro/index.html +++ b/docs/howto-read-synchro/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-turboproject/index.html b/docs/howto-read-turboproject/index.html index 0344f731a9..5bb844cf44 100644 --- a/docs/howto-read-turboproject/index.html +++ b/docs/howto-read-turboproject/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-read-xer/index.html b/docs/howto-read-xer/index.html index 3983ed60b6..fff65a1c43 100644 --- a/docs/howto-read-xer/index.html +++ b/docs/howto-read-xer/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-start-java/index.html b/docs/howto-start-java/index.html index 45b9d7da9d..9e43858e36 100644 --- a/docs/howto-start-java/index.html +++ b/docs/howto-start-java/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-start-python/index.html b/docs/howto-start-python/index.html index 30da8c0f16..8c2bf8d240 100644 --- a/docs/howto-start-python/index.html +++ b/docs/howto-start-python/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-start-ruby/index.html b/docs/howto-start-ruby/index.html index 6c91137129..2d928ede80 100644 --- a/docs/howto-start-ruby/index.html +++ b/docs/howto-start-ruby/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-start/index.html b/docs/howto-start/index.html index 0bd5ba7d93..18f7ce4f8a 100644 --- a/docs/howto-start/index.html +++ b/docs/howto-start/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-use-calendars/index.html b/docs/howto-use-calendars/index.html index 1a60cf12fd..d114b71628 100644 --- a/docs/howto-use-calendars/index.html +++ b/docs/howto-use-calendars/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-use-external-projects/index.html b/docs/howto-use-external-projects/index.html index 058b46d3d5..0a41484ee0 100644 --- a/docs/howto-use-external-projects/index.html +++ b/docs/howto-use-external-projects/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-use-fields/index.html b/docs/howto-use-fields/index.html index 50c768f2a2..bb2f20dbf1 100644 --- a/docs/howto-use-fields/index.html +++ b/docs/howto-use-fields/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-use-universal/index.html b/docs/howto-use-universal/index.html index 2d79021d14..b96ea3643b 100644 --- a/docs/howto-use-universal/index.html +++ b/docs/howto-use-universal/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-mpx/index.html b/docs/howto-write-mpx/index.html index 637fb198e2..e94e14b1e7 100644 --- a/docs/howto-write-mpx/index.html +++ b/docs/howto-write-mpx/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-mspdi/index.html b/docs/howto-write-mspdi/index.html index 875ae3f976..ead7a7b371 100644 --- a/docs/howto-write-mspdi/index.html +++ b/docs/howto-write-mspdi/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-planner/index.html b/docs/howto-write-planner/index.html index 4097d3cd62..ed1c690154 100644 --- a/docs/howto-write-planner/index.html +++ b/docs/howto-write-planner/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-pmxml/index.html b/docs/howto-write-pmxml/index.html index a0a3e22603..3d733a7603 100644 --- a/docs/howto-write-pmxml/index.html +++ b/docs/howto-write-pmxml/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-sdef/index.html b/docs/howto-write-sdef/index.html index 03bb42fba8..433816e258 100644 --- a/docs/howto-write-sdef/index.html +++ b/docs/howto-write-sdef/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/howto-write-xer/index.html b/docs/howto-write-xer/index.html index ee385dc37d..d71e9755d4 100644 --- a/docs/howto-write-xer/index.html +++ b/docs/howto-write-xer/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/index.html b/docs/index.html index fec88ca3ba..858c09579f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -16,7 +16,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -66,9 +66,6 @@
diff --git a/docs/issue-management.html b/docs/issue-management.html index d01ff65271..218abdc9d1 100644 --- a/docs/issue-management.html +++ b/docs/issue-management.html @@ -32,7 +32,7 @@
diff --git a/docs/mailing-lists.html b/docs/mailing-lists.html index 77216b8f2e..6bba995df6 100644 --- a/docs/mailing-lists.html +++ b/docs/mailing-lists.html @@ -32,7 +32,7 @@
diff --git a/docs/maven-reports/index.html b/docs/maven-reports/index.html index 2dfb9cea2e..0a6fd08102 100644 --- a/docs/maven-reports/index.html +++ b/docs/maven-reports/index.html @@ -16,7 +16,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -66,9 +66,6 @@
diff --git a/docs/mpp-field-guide/index.html b/docs/mpp-field-guide/index.html index 243b802298..d2724d79cc 100644 --- a/docs/mpp-field-guide/index.html +++ b/docs/mpp-field-guide/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/plugin-updates-report.html b/docs/plugin-updates-report.html index 4fc083c313..345dbc16c2 100644 --- a/docs/plugin-updates-report.html +++ b/docs/plugin-updates-report.html @@ -32,7 +32,7 @@
@@ -70,7 +70,7 @@
+
+
+
+
@@ -339,7 +339,7 @@
maven-dependency-plugin | |
Current Version | -3.6.0 |
---|
Status | -No newer versions available. | There is at least one newer incremental version available. Incremental updates are typically passive. |
---|---|
Group Id | org.apache.maven.plugins | maven-jar-plugin |
Current Version | -3.2.0 |
Status | -No newer versions available. | There is at least one newer minor version available. Minor updates are sometimes passive. |
---|---|
Group Id | org.apache.maven.plugins | maven-javadoc-plugin |
Current Version | -3.2.0 |
Status | -No newer versions available. | There is at least one newer minor version available. Minor updates are sometimes passive. |
---|---|
Group Id | org.apache.maven.plugins | maven-site-plugin |
Current Version | -3.9.1 |
Status | -No newer versions available. | There is at least one newer minor version available. Minor updates are sometimes passive. |
---|---|
Group Id | org.apache.maven.plugins | maven-source-plugin |
Current Version | -3.2.1 |
2.22.2 | |
Newer versions | -3.0.0-M1 Next Minor 3.0.0-M2 3.0.0-M3 3.0.0-M4 3.0.0-M5 Latest Minor |
---|
Status | -No newer versions available. | There is at least one newer incremental version available. Incremental updates are typically passive. |
---|---|
Group Id | org.sonatype.plugins | nexus-staging-maven-plugin |
Current Version | -1.6.8 |
+
+
diff --git a/docs/project-info.html b/docs/project-info.html index fdf1f7e150..6dacfc8565 100644 --- a/docs/project-info.html +++ b/docs/project-info.html @@ -32,7 +32,7 @@
diff --git a/docs/project-reports.html b/docs/project-reports.html index df9201c28b..938518a128 100644 --- a/docs/project-reports.html +++ b/docs/project-reports.html @@ -32,7 +32,7 @@
diff --git a/docs/scm.html b/docs/scm.html index 98609df762..7f78a15af6 100644 --- a/docs/scm.html +++ b/docs/scm.html @@ -32,7 +32,7 @@
diff --git a/docs/search/search_index.json b/docs/search/search_index.json index 26023aab15..bb23001cbf 100644 --- a/docs/search/search_index.json +++ b/docs/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":"
Welcome to MPXJ! This library enables you to read project plans (sometimes known as schedules or programmes) from a variety of file formats and databases, and can also write that information to a variety of file formats.
The library is based on data structures which follow the way schedule data is represented by Microsoft Project, extended to accommodate features and concepts from other applications.
"},{"location":"#sponsors","title":"Sponsors","text":"
Work to build and maintain MPXJ is kindly supported by my sponsors:
Head over to my sponsors page if you'd like to see your name and logo here!
"},{"location":"#file-formats","title":"File Formats","text":"
MPXJ can read file formats including MPX, MPP, MSPDI, MPD, Planner, Primavera P6 PMXML and XER, Primavera P3, SureTrak, Asta Powerproject, Asta Easyplan, Phoenix, Fasttrack, GanttProject, TurboProject, ConceptDraw PROJECT, Synchro, Gantt Designer, SDEF, Sage 100 Contractor Schedule Grid, Project Commander and Deltek Open Plan BK3.
MPXJ can also write schedule data as MPX, MSPDI, PMXML, XER, Planner and SDEF files.
More details of the supported file formats can be found here.
"},{"location":"#languages","title":"Languages","text":"
MPXJ is written and maintained in Java, however this is no barrier to using its functionality in other languages. Thanks to IKVM, MPXJ is available for .Net, allowing it to be used from any .Net language.
There is also now a Ruby Gem which provides native Ruby access to read from schedule files using MPXJ, and a Python package which wraps the Java library to provide full read/write access to schedule files.
You may be able to leverage MPXJ from other languages too, for example the PHP/Java Bridge can be used to expose the complete MPXJ API in PHP.
"},{"location":"#contact","title":"Contact","text":"
Having problems? Need support? All the details you need can be found on the support page.
Using MPXJ successfully somewhere? I'd love to hear from you about your experiences. Do tell me what's missing or what could be better - I can use this feedback to guide future development work. It would also be great to add a link to your website from the MPXJ users page.
Finally, if you're deriving value from MPXJ, please consider sponsoring me to ensure I can continue enhancing and maintaining the library. Thank you!
"},{"location":"#licensing","title":"Licensing","text":"
MPXJ is distributed under the terms of the GNU LGPL a copy of which can be found in the root of the distribution. Please read this license carefully! It will cost you nothing to use MPXJ commercially or non-commercially, but you must comply with the terms of the license.
Please see the legal folder within the distribution for details of the licences for the third party libraries used by MPXJ.
"},{"location":"#acknowledgements","title":"Acknowledgements","text":"
This library includes functionality provided by:
This library has been built with the assistance of:
"},{"location":"CHANGELOG/","title":"Changelog","text":""},{"location":"CHANGELOG/#1291-unreleased","title":"12.9.1 (unreleased)","text":""},{"location":"CHANGELOG/#1290-2024-04-11","title":"12.9.0 (2024-04-11)","text":"
UniversalProjectReader
to add getProjectReaderProxy
methods to allow access to the instance of the reader class which will be used to read a schedule, prior to the schedule being read. This will allow the reader to be configured, or schedule to be ignored without reading its content.ProjectReader.setProperties
method. This method was originally implemented to allow settings to be passed to reader classes when using UniversalProjectReader
. You can now use UniversalProjectReader.getProjectReaderProxy
to achieve this.from
method to all Builder
classes to allow initialisation from existing objects.CostAccount.Builder
class now provides two notes
methods to allow formatted or unformatted notes to be added to cost accounts.CostAccount
method getDescription()
has been marked as deprecated. Use the getNotes()
or getNotesObject()
method instead.CustomFieldValueItem
methods getParent
and setParent
have been marked as deprecated. Use the getParentUniqueID
and setParentUniqueID
methods instead."},{"location":"CHANGELOG/#1281-2024-03-11","title":"12.8.1 (2024-03-11)","text":"
"},{"location":"CHANGELOG/#1280-2024-03-04","title":"12.8.0 (2024-03-04)","text":"
Relation.Builder
class.Relation(Task,Task,RelationType,Duration)
constructor as deprecated, use the Relation.Builder
class instead.RelationContainer.addPredecessor(Task,Task,RelationType,Duration)
method as deprecated, use the RelationContainer.addPredecessor(Relation.Builder)
method instead.Task.addPredecessor(Task,RelationType,Duration)
method as deprecated, use the Task.addPredecessor(Relation.Builder)
method instead.Relation
class and ensure that it is read from and written to P6 schedules.readAll
method on reader classes to ensure that if the reader is unable to read any schedule data, an empty list is returned rather than a list containing null
."},{"location":"CHANGELOG/#1270-2024-02-07","title":"12.7.0 (2024-02-07)","text":"
ProjectCalendar.getPreviousWorkFinish
method when called with a time which was already at the end of a period of work.proj_node_flag
is set for the root WBS node when writing XER files."},{"location":"CHANGELOG/#1260-2024-01-22","title":"12.6.0 (2024-01-22)","text":"
ResourceAssignment.getEffectiveCalendar
method.ResourceAssignment.getCalendar
method, use getEffectiveCalendar
method instead.TimephasedUtility.segmentBaselineWork
and segmentBaselineCost
methods which take a ProjectCalendar
instance as the first argument rather than a ProjectFile
instance.TimephasedUtility.segmentBaselineWork
and segmentBaselineCost
methods which take a ProjectFile
instance as the first argument.ProjectCalendar.getDate()
method which just takes a date and a duration as its arguments. This method handles both positive and negative durations.ProjectCalendar.getDate()
method as deprecated. Use the new version instead."},{"location":"CHANGELOG/#1250-2023-12-18","title":"12.5.0 (2023-12-18)","text":"
ProjectProperties
Relationship Lag Calendar attribute for PMXML files.ProjectProperties
custom properties map are now deprecated. These properties now have individual getter and setter methods available on the ProjectProperties
class. Note: this may be a breaking change if you were creating schedules from scratch, populating the custom properties map, then writing PMXML or XER files. In this case you will need to update your code, for all other use cases your code will continue to work unchanged until the next major version of MPXJ.ProjectProperties
attributes Baseline Type Name, Baseline Type Unique ID, and Last Baseline Update Date for baseline projects in PMXML files.ProjectProperties
creation date attribute with the PMXML date added attribute.CustomFieldContainer.remove
method to allow field configurations to be removed.UserDefinedFieldContainer.remove
method to ensure that any associated field configuration is removed from the CustomFieldContainer
."},{"location":"CHANGELOG/#1240-2023-11-23","title":"12.4.0 (2023-11-23)","text":"
ProjectProperties
.ActivityCodeValue
instances when reading Asta PP files.ProjectFile.expandSubprojects
method which takes a boolean
argument indicating if external tasks should be removed. Passing true
to this method will recreate predecessor and successor relationships using the original tasks rather than the placeholder external tasks, and will remove the external tasks.ProjectFile.expandSubprojects()
method as deprecated, use the new version which takes a boolean
argument instead.ProjectProperties
name attribute is set correctly when reading XER files and P6 databases.ProjectEntityContainer
method renumberUniqueIDs
has been marked as deprecated.ProjectEntityContainer
method getNextUniqueID
has been marked as deprecated. Use ProjectFile.getUniqueIdObjectSequence(class).getNext()
instead.ProjectEntityContainer
method updateUniqueIdCounter
has been marked as deprecated as it is no longer required.ProjectFile
method updateUniqueIdCounters
has been marked as deprecated as it is no longer required.ObjectSequence
method reset
has been marked as deprecated as it is no longer required.Location
instance using the Builder
class, a Unique ID will be generated if one is not supplied.Location.Builder
constructor has been marked a deprecated. Use the constructor which requires a ProjectFile
instance instead.ExpenseItem.Builder
class.ExpenseItem(task)
constructor as deprecated, use the ExpenseItem.Builder
class instead.ExpenseItem
setter methods a deprecated. The ExpenseItem
class will be immutable in the next major release.UnitOfMeasure.Builder()
constructor as deprecated, use the UnitOfMeasure.Builder(ProjectFile)
constructor instead.Step.Builder
class.Step(task)
constructor as deprecated, use the Step.Builder
class instead.Step
setter methods a deprecated. The Step
class will be immutable in the next major release.NotesTopic
constructor as deprecated, use the NotesTopic.Builder(ProjectFile)
constructor instead.ExpenseCategory.Builder
class.ExpenseCategory
constructor as deprecated, use the ExpenseCategory.Builder
class instead.CostAccount.Builder
class.CostAccount
constructor as deprecated, use the CostAccount.Builder
class instead.ActivityCodeValue.Builder
class.ActivityCodeValue
constructor as deprecated, use the ActivityCodeValue.Builder
class instead.ActivityCodeValue.setParent
method as deprecated, use the ActivityCodeValue.Builder
class instead.ActivityCode.addValue
method as deprecated, use the ActivityCodeValue.Builder
class instead to create an ActivityCodeValue
instance and add it directly to the list held by the parent ActivityCode
.ActivityCode.Builder
class.ActivityCode
constructor as deprecated, use the ActivityCode.Builder
class instead.Relation
instances are now stored in RelationContainer
, successors are generated dynamically. You will only notice a difference if you are iterating over the RelationContainer
collection directly, in which case you will only see predecessors."},{"location":"CHANGELOG/#1230-2023-11-07","title":"12.3.0 (2023-11-07)","text":"
"},{"location":"CHANGELOG/#1220-2023-10-12","title":"12.2.0 (2023-10-12)","text":"
UnitOfMeasure
class to represent the unit of measure for a material resource. The unit of measure corresponds to the current \"material label\" attribute of a resource. The Resource.getMaterialLabel()
method will now retrieve the label from the UnitOfMeasure
instance associated with the resource. The Resource.setMaterialLabel()
method is now deprecated, the Resource.setUnitOfMeasure()
or Resource.setUnitOfMeasureUniqueID()
methods should be used instead.setIgnoreErrors
method to the Primavera database reader class, and MSPDI, Schedule Grid, and SDEF file reader classes. The current default behavior of ignoring data type parse errors is unchanged. Calling setIgnoreErrors(false)
on one of these reader classes will ensure that an exception is raised when a data type parse error is encountered.ProjectFile.getIgnoredErrors()
method. The default behavior for MPXJ reader classes is to ignore data type parse errors. If any errors have been ignored when reading a schedule, details of these errors can be retrieved by calling the ProjectFile.getIgnoredErrors()
method.Resource.getMaxUnits()
method will return the resource's Max Units attribute for the current date. To retrieve the Max Units for a different date, use the AvailabilityTable.getEntryByDate()
method.Resource.setMaxUnits()
method as deprecated. The Max Units attribute is derived from the resource's availability table. Changes to Max Units should now be made by modifying the availability table.Resource.getAvailableFrom()
method will return the resource's Available From attribute for the current date. To retrieve the Available From attribute for a different date, use the AvailabilityTable.availableFrom()
method.Resource.setAvailableFrom()
method as deprecated. The Available From attribute is derived from the resource's availability table. Changes to the Available From attribute should now be made by modifying the availability table.Resource.getAvailableTo()
method will return the resource's Available To attribute for the current date. To retrieve the Available To attribute for a different date, use the AvailabilityTable.availableTo()
method.Resource.setAvailableTo()
method as deprecated. The Available To attribute is derived from the resource's availability table. Changes to the Available To attribute should now be made by modifying the availability table."},{"location":"CHANGELOG/#1213-2023-09-25","title":"12.1.3 (2023-09-25)","text":"
"},{"location":"CHANGELOG/#1212-2023-09-21","title":"12.1.2 (2023-09-21)","text":"
ProjectProperties.getCustomProperties()
returns an empty Map rather than returning null
if no custom properties have been configured."},{"location":"CHANGELOG/#1211-2023-08-23","title":"12.1.1 (2023-08-23)","text":"
"},{"location":"CHANGELOG/#1210-2023-08-22","title":"12.1.0 (2023-08-22)","text":"
TimeUnitDefaultsContainer
argument rather than a ProjectFile
for greater flexibility. Marked methods taking a ProjectFile
argument as deprecated.null
actual start date for actual duration calculation when reading PMXML files (Contributed by Andrew Marks)."},{"location":"CHANGELOG/#1202-2023-07-25","title":"12.0.2 (2023-07-25)","text":"
"},{"location":"CHANGELOG/#1201-2023-07-21","title":"12.0.1 (2023-07-21)","text":"
"},{"location":"CHANGELOG/#1200-2023-06-29","title":"12.0.0 (2023-06-29)","text":"
java.time.LocalDateTime
, java.time.LocalDate
and java.time.LocalTime
respectively, rather than java.util.Date
as they were originally.ToDateTime
and ToNullableDateTime
extension methods have been provided to convert java.time.LocalDateTime
, java.time.LocalDate
, java.time.LocalTime
to DateTime
instances.ToJavaLocalDateTime
, ToJavaLocalDate
and ToJavaLocalTime
extension methods have been provided to convert DateTime
instances to java.time.LocalDateTime
, java.time.LocalDate
, and java.time.LocalTime
.net.sf.mpxj.Day
has been replaced by java.time.DayOfWeek
."},{"location":"CHANGELOG/#1154-2023-06-27","title":"11.5.4 (2023-06-27)","text":"
PrimaveraXERFileReader.setIgnoreErrors
method to change the behavior."},{"location":"CHANGELOG/#1153-2023-06-19","title":"11.5.3 (2023-06-19)","text":"
java.sql.Date
values are correctly formatted when writing XER files."},{"location":"CHANGELOG/#1152-2023-06-08","title":"11.5.2 (2023-06-08)","text":"
"},{"location":"CHANGELOG/#1151-2023-05-24","title":"11.5.1 (2023-05-24)","text":"
"},{"location":"CHANGELOG/#1150-2023-05-19","title":"11.5.0 (2023-05-19)","text":"
getBarName
and setBarName
methods. This is populated with the name of the bar to which a task belongs when reading an Asta Powerproject schedule.null
rather than as a zero duration."},{"location":"CHANGELOG/#1140-2023-05-08","title":"11.4.0 (2023-05-08)","text":"
getResourcePoolFile
and setResourcePoolFile
methods.getResourcePoolObject
method to allow the resource pool file to be located and readgetSubprojectGUID
and setSubprojectGUID
methods.getExternalProject
and setExternalProject
methods.getSubprojectObject
which allows the caller to retrieve a ProjectFile instance representing the external project linked to a task.expandSubproject
. For task which represent an external project, this method automatically loads the external project and attaches the tasks it contains as children of the current task. This is analogous to the behavior in Microsoft Project where a subproject is expanded to reveal the tasks it contains.expandSubprojects
which identifies any tasks in the project which represent an external project and expands them, linking the tasks from the external project as children of the task in the parent project. Note that the method works recursively so multiple levels of external tasks will be expanded.internal_name
attribute of a UserdefinedField
is generated if not present.setSubprojectName
as deprecated. Use the setSubProjectFile
method instead.getSubprojectName
as deprecated. Use getSubprojectFile
instead.setExternalTaskProject
as deprecated. Use the setSubprojectFile
method instead.getExternalTaskProject
as deprecated. Use the getSubprojectFile
method instead.getSubProjects
as deprecated. Use the subproject attributes on individual tasks instead.getSubProject
and setSubProject
as deprecated. Use the subproject attributes instead."},{"location":"CHANGELOG/#1132-2023-04-29","title":"11.3.2 (2023-04-29)","text":"
"},{"location":"CHANGELOG/#1131-2023-04-21","title":"11.3.1 (2023-04-21)","text":"
"},{"location":"CHANGELOG/#1130-2023-04-12","title":"11.3.0 (2023-04-12)","text":"
PrimaveraXERFileWriter
to allow MPXJ to write XER files.ActivityCode
class to ensure that both the scope Project ID and EPS ID can be represented when reading a P6 schedule. (Potentially breaking change if you were using this class).WorkContour.isDefault()
method to allow \"built in\" resource curves/work contours to be distinguished from user defined curves.ProjectFile.getNotesTopics()
method.critical_drtn_hr_cnt
field is expressed a decimal rather than an integer."},{"location":"CHANGELOG/#1120-2023-03-13","title":"11.2.0 (2023-03-13)","text":"
Duration
rather than as an Integer
. (Potentially breaking change if you were using this property directly).TaskType
is now a simple enum with all Microsoft Project specific functionality moved into TaskTypeHelper
. (Potentially breaking change if you were using the TaskType
methods getInstance
or getValue
in your code)TaskType
enum has been updated to more closely match P6. The main changes are that the P6 type \"Fixed Units\" now maps to TaskType.FIXED_WORK
and the \"Fixed Duration & Units\" type now maps to a new enumeration value TaskType.FIXED_DURATION_AND_UNITS
."},{"location":"CHANGELOG/#1110-2023-02-15","title":"11.1.0 (2023-02-15)","text":"
ActivityCode
class.getChildCodes
method to ActivityCode
and ActivityCodeValue
to make it easier to traverse activity code values hierarchically.setDescription
method to Step
class to make it simpler to add a plan text description."},{"location":"CHANGELOG/#1100-2023-02-08","title":"11.0.0 (2023-02-08)","text":"
UserDefinedField
. They will no longer be mapped to custom field instances.UserDefinedField
.UserDefinedField
type implements the FieldType
interface and so can be used with the FieldContainer
get
and set
methods to work with the contents of the user defined fields.ProjectFile.getUserDefinedFields()
method has been added to provide access to all user defined fields defined in the project.CustomFieldContainer
returned by ProjectFile.getCustomFields()
will contain entries for all UserDefinedField
instances.getFieldTypeByAlias
and getFieldByAlias
methods will retrieve user defined fields by name.ProjectFile.getPopulatedFields()
to retrieve details of all populated fields across the project. This avoids the caller having to individually retrieve the populated fields from the tasks container, resource container and so on.getPopulatedFields
methods to return a Set
of FieldType
rather than a Set
of TaskField
, ResourceField
etc.getPopulatedFields
methods will include instances of UserDefinedField
in the returned collection if relevant.ENTERPRISE_CUSTOM_FIELDn
values have been removed from the TaskField
, ResourceField
, AssignmentField
and ProjectField
enumerations.getEnterpriseCustomField
and setEnterpriseCustomField
methods have been removed from ProjectProperties
, Task,
Resourceand
ResourceAssignment`."},{"location":"CHANGELOG/#10162-2023-01-29","title":"10.16.2 (2023-01-29)","text":"
"},{"location":"CHANGELOG/#10161-2023-01-26","title":"10.16.1 (2023-01-26)","text":"
WorkContourContainer
. This container is accessed using the ProjectFile.getWorkContours()
method."},{"location":"CHANGELOG/#10160-2023-01-24","title":"10.16.0 (2023-01-24)","text":"
GanttBarCommonStyle
and GanttBarStyle
classes to use a FieldType
instance rather than a TaskField
instance to allow more flexibility. (Note: this may be a breaking change if you are currently using these classes.)"},{"location":"CHANGELOG/#10150-2023-01-11","title":"10.15.0 (2023-01-11)","text":"
MPXJ.VERSION
."},{"location":"CHANGELOG/#10141-2022-11-25","title":"10.14.1 (2022-11-25)","text":"
"},{"location":"CHANGELOG/#10140-2022-11-21","title":"10.14.0 (2022-11-21)","text":"
File
instance, ensure a more memory-efficient approach is used."},{"location":"CHANGELOG/#10130-2022-11-16","title":"10.13.0 (2022-11-16)","text":"
"},{"location":"CHANGELOG/#10120-2022-11-01","title":"10.12.0 (2022-11-01)","text":"
CostAccount
method getSequence
and replace with getSequenceNumber
to improve naming consistency.ExpenseCategory
method getSequence
and replace with getSequenceNumber
to improve naming consistency."},{"location":"CHANGELOG/#10110-2022-09-27","title":"10.11.0 (2022-09-27)","text":"
Resource
methods getParentID
and setParentID
. Replaced with getParentResourceUniqueID
and setParentResourceUniqueID
for clarity and consistency.Resource
methods setParent
and getParent
.ChildResourceContainer
interface and ResourceContainer.updateStructure
method to ensure that resources can be accessed hierarchically when reading a schedule.ResourceAssignment
methods getFieldByAlias
and setFieldByAlias
to simplify working with custom fields, and mkae the API consistent with existing methods on Task
and Resource
.TaskContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to task custom fields.ResourceContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to resource custom fields.ResourceAssignmentContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to resource assignment custom fields.getCustomFieldsByFieldTypeClass
method to CustomFieldContainer
to allow retrieval of custom field details by parent class.CustomFieldContainer
method getFieldByAlias
to be replaced by getFieldTypeByAlias
to provide a more consistent method name.CustomFieldContainer
method add
.CustomFieldContainer
method getCustomField
, which is replaced by the get
method (which returns null
if the field type is not configured) and the getOrCreate
method (which will return an existing configuration or create a new one if the requested field does not yet have a configuration)."},{"location":"CHANGELOG/#10100-2022-09-13","title":"10.10.0 (2022-09-13)","text":"
setProperties
method to reader classes to allow configuration to be supplied via a Properties
instance rather than having to call setter methods. Properties passed to the UniversalProjectReader
version of this method will be forwarded to the reader class UniversalProjectReader
chooses to reader the supplied file. Properties for multiple reader classes can be included in the Properties
instance, each reader class will ignore irrelevant properties.get
method to Task
, Resource
, ResourceAssignment
and ProjectProperties
as a replacement for the getCurrentValue
method. The new get
method is paired with the existing set
method to provide read and write access to attributes of these classes. This change is intended to improve the interfaces to these classes by making them more consistent, and thus easier to understand.getCurrentValue
method on the Task
, Resource
, ResourceAssignment
and ProjectProperties
classes. Use the new get
method instead.ResourceAssignment
calculated fields are returned correctly when using the getCurrentValue
method.ProjectProperties
calculated fields are returned correctly when using the getCurrentValue
method."},{"location":"CHANGELOG/#1091-2022-08-31","title":"10.9.1 (2022-08-31)","text":"
"},{"location":"CHANGELOG/#1090-2022-08-23","title":"10.9.0 (2022-08-23)","text":"
ResourceAssignment.getEffectiveRate
method to allow the cost rate effective on a given date for a resource assignment to be calculated. For P6 schedules this will take account of the cost rate configuration included as part of the resource assignment.ResourceAssignment.getCostRateTable
method now takes in account any cost rate configuration details from the resource assignment when determining which table to return.setStandardRate
, setOvertimeRate
, and setCostPerUse
have been deprecated. These attributes can now only be set or updated by modifying the resource's cost rate table.ResourceAssignment.getRateIndex
method. The value returned by this method can be used to select the required rate using the CostRateTableEntry,getRate
method.ResourceAssignment.getRole
and ResourceAssignment.setRole
methods.ResourceAssignment.getOverrideRate
and ResourceAssignment.setOverrideRate
methods.ResourceAssignment.getRateSource
and ResourceAssignment.setRateSource
methods."},{"location":"CHANGELOG/#1080-2022-08-17","title":"10.8.0 (2022-08-17)","text":"
CostRateTableEntry.getRate
method.getStandardRateUnits
and getOvertimeRateUnits
are deprecated. Use the getStandardRate
and getOvertimeRate
methods to retrieve a Rate
instance which will include the units for these rates.setStandardRateUnits
and setOvertimeRateUnits
are deprecated. Supply Rate
instances to the setStandardRate
and setOvertimeRate
methods with the required units instead.getStandardRateUnits
and getOvertimeRateUnits
are deprecated. Use the getStandardRate
and getOvertimeRate
methods to retrieve a Rate
instance which will include the units for these rates."},{"location":"CHANGELOG/#1070-2022-08-09","title":"10.7.0 (2022-08-09)","text":"
"},{"location":"CHANGELOG/#1062-2022-06-29","title":"10.6.2 (2022-06-29)","text":"
ProjectCleanUtility
can load dictionary words from distribution jar."},{"location":"CHANGELOG/#1061-2022-06-14","title":"10.6.1 (2022-06-14)","text":"
"},{"location":"CHANGELOG/#1060-2022-06-08","title":"10.6.0 (2022-06-08)","text":"
getUniqueID
and setUniqueID
methods on `CustomField (based on a suggestion by Wes Lund).isWorking
method to ProjectCalendarException
to make it clearer how to determine if the exception changes the dates it is applied to into working or non-working days."},{"location":"CHANGELOG/#1050-2022-05-24","title":"10.5.0 (2022-05-24)","text":"
ProjectCalendarWeek
methods addCalendarHours()
, attachHoursToDay
, removeHoursFromDay
have been removed. Use addCalendarHours(day)
, removeCalendarHours(day)
instead. (Note: this will be a breaking change if you were using the original methods to create or modify a schedule)ProjectCalendar
methods attachHoursToDay
and removeHoursFromDay
have been removed. Use the addCalendarHours
and removeCalendarHours
methods instead. (Note: this will be a breaking change if you were using the original methods to create or modify a schedule)ProjectCalendarHours
and ProjectCalendarException
has been simplified, but there should be no impact for uses of these classes.ProjectCalendarHours
class now implements the List
interface. Methods in this class not part ofthe List
interface have been deprecated in favour of the equivalent List
methods.MPXWriter
to ensure: calendar names are quoted if necessary, all calendars have names, all calendar names are unique.MPXReader
to recognise wk
as a valid time unit.MPXWriter
, PrimaveraPMFileWriter
, SDEFWriter
and PlannerWriter
to ensure any working weeks defined by a calendar are represented by exceptons.MSPDIWriter
to ensure any working weeks defined by a calendar are represented in the \"legacy\" exception definition used by Microsoft Project prior to 2007.SDEFWriter
to ensure: only relevant calendars are written, and derived calendars are flattened.ProjectCalendar
and ProjectCalendarWeek
both now inherit from a new class ProjectCalendarDays
. Note that ProjectCalendar
is no longer a subclass of ProjectCalendarWeek
.getHours
and isWorkingDay
methods have been moved up to ProjectCalendar
from the ProjectCalendarWeek
class.ProjectCalendar
method copy
has been deprecated, without replacement.getWork
method to ProjectCalendar
which calculates the amount of work given a Day
instance.removeWorkWeek
and removeCalendarException
methods to ProjectCalendar
.ProjectCalendar
using the addCalendarException
method which takes a recurringData
instance its argument.ProjectCalendarException
method setRecurringData
has been removed, recurring exceptions should be added using the addCalendarExcepton
method described above. (Note: this will be a breaking change if you were creating recurring exceptions)"},{"location":"CHANGELOG/#1040-2022-05-05","title":"10.4.0 (2022-05-05)","text":"
getParent
, setParent
, and isDerived
from ProjectCalendarWeek
. (Note: this will be a breaking change if you were working with ProjectCalendarWeek
directly).ProjectProperties
methods getDefaultCalendarName()
and setDefaultCalendarName()
have been deprecated. Use getDefaultCalendar()
and setDefaultCalendar()
instead."},{"location":"CHANGELOG/#1030-2022-04-29","title":"10.3.0 (2022-04-29)","text":"
MPXWriter
and MSPDIWriter
to ensure that, when written, calendars are correctly structured in the form required by Microsoft Project.JsonWriter
now includes calendar data as part of its output.ProjectCalendar
methods setMinutesPerDay
, setMinutesPerWeek
, setMinutesPerMonth
and setMinutesPerYear
have been deprecated, use setCalendarMinutesPerDay
, setCalendarMinutesPerWeek
, setCalendarMinutesPerMonth
and setCalendarMinutesPerYear
instead.setResource
has been deprecated and will not be replaced. Use the Resource method setCalendar
or setCalendarUniqueID
to link a calendar with a resource.getResource
has been deprecated. Use the getResources
method instead to retrieve all resources linked with a calendar.Resource
methods addResourceCalendar
, setResourceCalendar
, getResourceCalendar
, setResourceCalendarUniqueID
and getResourceCalendarUniqueID
have been deprecated and replaced by addCalendar
, setCalendar
, getCalendar
, setCalendarUniqueID
and getCalendarUniqueID
respectively."},{"location":"CHANGELOG/#1020-2022-03-06","title":"10.2.0 (2022-03-06)","text":"
StructuredTextParser
to replace original code handling calendar data, project properties and curve data read from XER files and Primavera databases. Can also be used to extract data from Primavera Layout Files (PLF)."},{"location":"CHANGELOG/#1010-2022-01-29","title":"10.1.0 (2022-01-29)","text":"
"},{"location":"CHANGELOG/#1005-2022-01-11","title":"10.0.5 (2022-01-11)","text":"
Task.getActivityCodes()
returns an empty list rather than null
when no activity code values have been assigned."},{"location":"CHANGELOG/#1004-2022-01-07","title":"10.0.4 (2022-01-07)","text":"
ProjectCleanUtility
to provide a \"replace\" strategy alongside the original \"redact\" strategy."},{"location":"CHANGELOG/#1003-2021-12-22","title":"10.0.3 (2021-12-22)","text":"
"},{"location":"CHANGELOG/#1002-2021-12-16","title":"10.0.2 (2021-12-16)","text":"
"},{"location":"CHANGELOG/#1001-2021-12-10","title":"10.0.1 (2021-12-10)","text":"
"},{"location":"CHANGELOG/#1000-2021-12-01","title":"10.0.0 (2021-12-01)","text":"
net45
) and .NET Core 3.1 (netcoreapp3.1
)"},{"location":"CHANGELOG/#983-2021-11-30","title":"9.8.3 (2021-11-30)","text":"
"},{"location":"CHANGELOG/#982-2021-11-01","title":"9.8.2 (2021-11-01)","text":"
"},{"location":"CHANGELOG/#981-2021-10-13","title":"9.8.1 (2021-10-13)","text":"
"},{"location":"CHANGELOG/#980-2021-09-30","title":"9.8.0 (2021-09-30)","text":"
"},{"location":"CHANGELOG/#970-2021-09-28","title":"9.7.0 (2021-09-28)","text":"
"},{"location":"CHANGELOG/#960-2021-09-13","title":"9.6.0 (2021-09-13)","text":"
"},{"location":"CHANGELOG/#952-2021-08-22","title":"9.5.2 (2021-08-22)","text":"
"},{"location":"CHANGELOG/#951-2021-07-01","title":"9.5.1 (2021-07-01)","text":"
"},{"location":"CHANGELOG/#950-2021-06-30","title":"9.5.0 (2021-06-30)","text":"
"},{"location":"CHANGELOG/#940-2021-06-11","title":"9.4.0 (2021-06-11)","text":"
"},{"location":"CHANGELOG/#931-2021-05-18","title":"9.3.1 (2021-05-18)","text":"
"},{"location":"CHANGELOG/#930-2021-05-06","title":"9.3.0 (2021-05-06)","text":"
"},{"location":"CHANGELOG/#926-2021-04-26","title":"9.2.6 (2021-04-26)","text":"
"},{"location":"CHANGELOG/#925-2021-04-20","title":"9.2.5 (2021-04-20)","text":"
"},{"location":"CHANGELOG/#924-2021-04-09","title":"9.2.4 (2021-04-09)","text":"
"},{"location":"CHANGELOG/#923-2021-04-08","title":"9.2.3 (2021-04-08)","text":"
"},{"location":"CHANGELOG/#922-2021-04-07","title":"9.2.2 (2021-04-07)","text":"
"},{"location":"CHANGELOG/#921-2021-04-04","title":"9.2.1 (2021-04-04)","text":"
"},{"location":"CHANGELOG/#920-2021-03-30","title":"9.2.0 (2021-03-30)","text":"
"},{"location":"CHANGELOG/#910-2021-03-11","title":"9.1.0 (2021-03-11)","text":"
"},{"location":"CHANGELOG/#900-2020-02-18","title":"9.0.0 (2020-02-18)","text":"
"},{"location":"CHANGELOG/#851-2021-01-07","title":"8.5.1 (2021-01-07)","text":"
"},{"location":"CHANGELOG/#850-2021-01-06","title":"8.5.0 (2021-01-06)","text":"
"},{"location":"CHANGELOG/#840-2020-12-29","title":"8.4.0 (2020-12-29)","text":"
"},{"location":"CHANGELOG/#835-2020-12-15","title":"8.3.5 (2020-12-15)","text":"
"},{"location":"CHANGELOG/#834-2020-12-10","title":"8.3.4 (2020-12-10)","text":"
"},{"location":"CHANGELOG/#833-2020-11-24","title":"8.3.3 (2020-11-24)","text":"
"},{"location":"CHANGELOG/#832-2020-10-22","title":"8.3.2 (2020-10-22)","text":"
"},{"location":"CHANGELOG/#831-2020-10-14","title":"8.3.1 (2020-10-14)","text":"
"},{"location":"CHANGELOG/#830-2020-10-13","title":"8.3.0 (2020-10-13)","text":"
"},{"location":"CHANGELOG/#820-2020-09-09","title":"8.2.0 (2020-09-09)","text":"
"},{"location":"CHANGELOG/#814-2020-08-31","title":"8.1.4 (2020-08-31)","text":"
"},{"location":"CHANGELOG/#813-2020-06-25","title":"8.1.3 (2020-06-25)","text":"
"},{"location":"CHANGELOG/#812-2020-06-18","title":"8.1.2 (2020-06-18)","text":"
"},{"location":"CHANGELOG/#811-2020-06-17","title":"8.1.1 (2020-06-17)","text":"
"},{"location":"CHANGELOG/#810-2020-06-11","title":"8.1.0 (2020-06-11)","text":"
"},{"location":"CHANGELOG/#808-2020-04-20","title":"8.0.8 (2020-04-20)","text":"
"},{"location":"CHANGELOG/#807-2020-04-17","title":"8.0.7 (2020-04-17)","text":"
"},{"location":"CHANGELOG/#806-2020-03-05","title":"8.0.6 (2020-03-05)","text":"
"},{"location":"CHANGELOG/#805-2020-02-07","title":"8.0.5 (2020-02-07)","text":"
"},{"location":"CHANGELOG/#804-2020-02-06","title":"8.0.4 (2020-02-06)","text":"
"},{"location":"CHANGELOG/#803-2020-01-27","title":"8.0.3 (2020-01-27)","text":"
"},{"location":"CHANGELOG/#802-2020-01-16","title":"8.0.2 (2020-01-16)","text":"
"},{"location":"CHANGELOG/#801-2020-01-05","title":"8.0.1 (2020-01-05)","text":"
"},{"location":"CHANGELOG/#800-2020-01-02","title":"8.0.0 (2020-01-02)","text":"
"},{"location":"CHANGELOG/#798-2019-12-27","title":"7.9.8 (2019-12-27)","text":"
"},{"location":"CHANGELOG/#797-2019-11-25","title":"7.9.7 (2019-11-25)","text":"
"},{"location":"CHANGELOG/#796-2019-11-22","title":"7.9.6 (2019-11-22)","text":"
"},{"location":"CHANGELOG/#795-2019-11-19","title":"7.9.5 (2019-11-19)","text":"
"},{"location":"CHANGELOG/#794-2019-11-08","title":"7.9.4 (2019-11-08)","text":"
"},{"location":"CHANGELOG/#793-2019-09-10","title":"7.9.3 (2019-09-10)","text":"
"},{"location":"CHANGELOG/#792-2019-08-19","title":"7.9.2 (2019-08-19)","text":"
"},{"location":"CHANGELOG/#791-2019-07-01","title":"7.9.1 (2019-07-01)","text":"
"},{"location":"CHANGELOG/#790-2019-07-01","title":"7.9.0 (2019-07-01)","text":"
"},{"location":"CHANGELOG/#784-2019-06-27","title":"7.8.4 (2019-06-27)","text":"
"},{"location":"CHANGELOG/#783-2019-05-24","title":"7.8.3 (2019-05-24)","text":"
"},{"location":"CHANGELOG/#782-2019-05-19","title":"7.8.2 (2019-05-19)","text":"
"},{"location":"CHANGELOG/#781-2019-02-13","title":"7.8.1 (2019-02-13)","text":"
"},{"location":"CHANGELOG/#780-2019-01-18","title":"7.8.0 (2019-01-18)","text":"
"},{"location":"CHANGELOG/#771-2018-10-23","title":"7.7.1 (2018-10-23)","text":"
"},{"location":"CHANGELOG/#770-2018-10-12","title":"7.7.0 (2018-10-12)","text":"
"},{"location":"CHANGELOG/#763-2018-10-04","title":"7.6.3 (2018-10-04)","text":"
"},{"location":"CHANGELOG/#762-2018-08-30","title":"7.6.2 (2018-08-30)","text":"
"},{"location":"CHANGELOG/#761-2018-08-29","title":"7.6.1 (2018-08-29)","text":"
"},{"location":"CHANGELOG/#760-2018-07-13","title":"7.6.0 (2018-07-13)","text":"
"},{"location":"CHANGELOG/#750-2018-06-19","title":"7.5.0 (2018-06-19)","text":"
"},{"location":"CHANGELOG/#744-2018-06-06","title":"7.4.4 (2018-06-06)","text":"
"},{"location":"CHANGELOG/#743-2018-05-25","title":"7.4.3 (2018-05-25)","text":"
"},{"location":"CHANGELOG/#742-2018-04-30","title":"7.4.2 (2018-04-30)","text":"
"},{"location":"CHANGELOG/#741-2018-04-16","title":"7.4.1 (2018-04-16)","text":"
"},{"location":"CHANGELOG/#740-2018-03-23","title":"7.4.0 (2018-03-23)","text":"
"},{"location":"CHANGELOG/#730-2018-03-12","title":"7.3.0 (2018-03-12)","text":"
"},{"location":"CHANGELOG/#721-2018-01-26","title":"7.2.1 (2018-01-26)","text":"
"},{"location":"CHANGELOG/#720-2018-01-18","title":"7.2.0 (2018-01-18)","text":"
"},{"location":"CHANGELOG/#710-2018-01-03","title":"7.1.0 (2018-01-03)","text":"
"},{"location":"CHANGELOG/#703-2017-12-21","title":"7.0.3 (2017-12-21)","text":"
"},{"location":"CHANGELOG/#702-2017-11-20","title":"7.0.2 (2017-11-20)","text":"
"},{"location":"CHANGELOG/#701-2017-11-20","title":"7.0.1 (2017-11-20)","text":"
"},{"location":"CHANGELOG/#700-2017-11-08","title":"7.0.0 (2017-11-08)","text":"
"},{"location":"CHANGELOG/#621-2017-10-11","title":"6.2.1 (2017-10-11)","text":"
"},{"location":"CHANGELOG/#620-2017-10-06","title":"6.2.0 (2017-10-06)","text":"
"},{"location":"CHANGELOG/#612-2017-09-12","title":"6.1.2 (2017-09-12)","text":"
"},{"location":"CHANGELOG/#611-2017-08-30","title":"6.1.1 (2017-08-30)","text":"
"},{"location":"CHANGELOG/#610-2017-07-28","title":"6.1.0 (2017-07-28)","text":"
"},{"location":"CHANGELOG/#600-2017-07-22","title":"6.0.0 (2017-07-22)","text":"
"},{"location":"CHANGELOG/#5140-2017-07-13","title":"5.14.0 (2017-07-13)","text":"
"},{"location":"CHANGELOG/#5130-2017-06-27","title":"5.13.0 (2017-06-27)","text":"
"},{"location":"CHANGELOG/#5120-2017-06-26","title":"5.12.0 (2017-06-26)","text":"
"},{"location":"CHANGELOG/#5110-2017-06-20","title":"5.11.0 (2017-06-20)","text":"
"},{"location":"CHANGELOG/#5100-2017-05-23","title":"5.10.0 (2017-05-23)","text":"
"},{"location":"CHANGELOG/#590-2017-04-27","title":"5.9.0 (2017-04-27)","text":"
"},{"location":"CHANGELOG/#580-2017-04-21","title":"5.8.0 (2017-04-21)","text":"
"},{"location":"CHANGELOG/#571-2017-03-22","title":"5.7.1 (2017-03-22)","text":"
"},{"location":"CHANGELOG/#570-2017-03-20","title":"5.7.0 (2017-03-20)","text":"
"},{"location":"CHANGELOG/#565-2017-03-07","title":"5.6.5 (2017-03-07)","text":"
"},{"location":"CHANGELOG/#564-2017-02-16","title":"5.6.4 (2017-02-16)","text":"
"},{"location":"CHANGELOG/#563-2017-02-08","title":"5.6.3 (2017-02-08)","text":"
"},{"location":"CHANGELOG/#562-2017-02-06","title":"5.6.2 (2017-02-06)","text":"
"},{"location":"CHANGELOG/#561-2017-02-03","title":"5.6.1 (2017-02-03)","text":"
"},{"location":"CHANGELOG/#560-2017-01-29","title":"5.6.0 (2017-01-29)","text":"
"},{"location":"CHANGELOG/#559-2017-01-27","title":"5.5.9 (2017-01-27)","text":"
"},{"location":"CHANGELOG/#558-2017-01-23","title":"5.5.8 (2017-01-23)","text":"
"},{"location":"CHANGELOG/#557-2017-01-13","title":"5.5.7 (2017-01-13)","text":"
"},{"location":"CHANGELOG/#556-2017-01-06","title":"5.5.6 (2017-01-06)","text":"
"},{"location":"CHANGELOG/#555-2017-01-06","title":"5.5.5 (2017-01-06)","text":"
"},{"location":"CHANGELOG/#554-2016-12-01","title":"5.5.4 (2016-12-01)","text":"
"},{"location":"CHANGELOG/#553-2016-11-29","title":"5.5.3 (2016-11-29)","text":"
"},{"location":"CHANGELOG/#552-2016-11-02","title":"5.5.2 (2016-11-02)","text":"
"},{"location":"CHANGELOG/#551-2016-10-14","title":"5.5.1 (2016-10-14)","text":"
"},{"location":"CHANGELOG/#550-2016-10-13","title":"5.5.0 (2016-10-13)","text":"
"},{"location":"CHANGELOG/#540-2016-10-06","title":"5.4.0 (2016-10-06)","text":"
"},{"location":"CHANGELOG/#533-2016-08-31","title":"5.3.3 (2016-08-31)","text":"
"},{"location":"CHANGELOG/#532-2016-08-31","title":"5.3.2 (2016-08-31)","text":"
"},{"location":"CHANGELOG/#531-2016-07-01","title":"5.3.1 (2016-07-01)","text":"
"},{"location":"CHANGELOG/#530-2016-06-10","title":"5.3.0 (2016-06-10)","text":"
"},{"location":"CHANGELOG/#522-2016-03-11","title":"5.2.2 (2016-03-11)","text":"
"},{"location":"CHANGELOG/#521-2016-02-11","title":"5.2.1 (2016-02-11)","text":"
"},{"location":"CHANGELOG/#520-2016-02-08","title":"5.2.0 (2016-02-08)","text":"
"},{"location":"CHANGELOG/#5118-2016-01-25","title":"5.1.18 (2016-01-25)","text":"
"},{"location":"CHANGELOG/#5117-2015-12-30","title":"5.1.17 (2015-12-30)","text":"
"},{"location":"CHANGELOG/#5116-2015-12-18","title":"5.1.16 (2015-12-18)","text":"
"},{"location":"CHANGELOG/#5115-2015-12-16","title":"5.1.15 (2015-12-16)","text":"
"},{"location":"CHANGELOG/#5114-2015-12-09","title":"5.1.14 (2015-12-09)","text":"
"},{"location":"CHANGELOG/#5113-2015-11-26","title":"5.1.13 (2015-11-26)","text":"
"},{"location":"CHANGELOG/#5112-2015-11-16","title":"5.1.12 (2015-11-16)","text":"
"},{"location":"CHANGELOG/#5111-2015-11-12","title":"5.1.11 (2015-11-12)","text":"
"},{"location":"CHANGELOG/#5110-2015-09-09","title":"5.1.10 (2015-09-09)","text":"
"},{"location":"CHANGELOG/#519-2015-08-29","title":"5.1.9 (2015-08-29)","text":"
"},{"location":"CHANGELOG/#518-2015-07-13","title":"5.1.8 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#517-2015-07-13","title":"5.1.7 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#516-2015-07-13","title":"5.1.6 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#515-2015-06-05","title":"5.1.5 (2015-06-05)","text":"
"},{"location":"CHANGELOG/#514-2015-06-03","title":"5.1.4 (2015-06-03)","text":"
"},{"location":"CHANGELOG/#513-2015-05-18","title":"5.1.3 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#512-2015-05-18","title":"5.1.2 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#511-2015-05-18","title":"5.1.1 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#510-2015-05-17","title":"5.1.0 (2015-05-17)","text":"
"},{"location":"CHANGELOG/#500-2015-05-06","title":"5.0.0 (2015-05-06)","text":"
"},{"location":"CHANGELOG/#476-2015-03-18","title":"4.7.6 (2015-03-18)","text":"
"},{"location":"CHANGELOG/#475-2015-02-27","title":"4.7.5 (2015-02-27)","text":"
"},{"location":"CHANGELOG/#474-2015-02-25","title":"4.7.4 (2015-02-25)","text":"
"},{"location":"CHANGELOG/#473-2014-12-23","title":"4.7.3 (2014-12-23)","text":"
"},{"location":"CHANGELOG/#472-2014-12-15","title":"4.7.2 (2014-12-15)","text":"
"},{"location":"CHANGELOG/#471-2014-12-08","title":"4.7.1 (2014-12-08)","text":"
"},{"location":"CHANGELOG/#470-2014-12-04","title":"4.7.0 (2014-12-04)","text":"
"},{"location":"CHANGELOG/#462-2014-11-11","title":"4.6.2 (2014-11-11)","text":"
"},{"location":"CHANGELOG/#461-2014-10-17","title":"4.6.1 (2014-10-17)","text":"
"},{"location":"CHANGELOG/#460-2014-10-17","title":"4.6.0 (2014-10-17)","text":"
"},{"location":"CHANGELOG/#450-2014-03-01","title":"4.5.0 (2014-03-01)","text":"
"},{"location":"CHANGELOG/#440-2013-03-14","title":"4.4.0 (2013-03-14)","text":"
"},{"location":"CHANGELOG/#430-2012-02-08","title":"4.3.0 (2012-02-08)","text":"
"},{"location":"CHANGELOG/#420-2011-06-23","title":"4.2.0 (2011-06-23)","text":"
"},{"location":"CHANGELOG/#410-2011-05-30","title":"4.1.0 (2011-05-30)","text":"
"},{"location":"CHANGELOG/#400-2010-05-25","title":"4.0.0 (2010-05-25)","text":"
"},{"location":"CHANGELOG/#320-2010-01-20","title":"3.2.0 (2010-01-20)","text":"
"},{"location":"CHANGELOG/#310-2009-05-20","title":"3.1.0 (2009-05-20)","text":"
"},{"location":"CHANGELOG/#300-2009-01-25","title":"3.0.0 (2009-01-25)","text":"
"},{"location":"CHANGELOG/#210-2008-03-23","title":"2.1.0 (2008-03-23)","text":"
"},{"location":"CHANGELOG/#200-2007-10-07","title":"2.0.0 (2007-10-07)","text":"
"},{"location":"CHANGELOG/#100-2007-08-30","title":"1.0.0 (2007-08-30)","text":"
"},{"location":"CHANGELOG/#092-2006-03-07","title":"0.9.2 (2006-03-07)","text":"
"},{"location":"CHANGELOG/#091-2006-01-26","title":"0.9.1 (2006-01-26)","text":"
"},{"location":"CHANGELOG/#0025-2005-08-11","title":"0.0.25 (2005-08-11)","text":"
"},{"location":"CHANGELOG/#0024-2005-01-10","title":"0.0.24 (2005-01-10)","text":"
"},{"location":"CHANGELOG/#0023-2004-11-17","title":"0.0.23 (2004-11-17)","text":"
"},{"location":"CHANGELOG/#0022-2004-07-27","title":"0.0.22 (2004-07-27)","text":"
"},{"location":"CHANGELOG/#0021-2004-05-06","title":"0.0.21 (2004-05-06)","text":"
"},{"location":"CHANGELOG/#0020-2004-03-15","title":"0.0.20 (2004-03-15)","text":"
"},{"location":"CHANGELOG/#0019-2003-12-02","title":"0.0.19 (2003-12-02)","text":"
"},{"location":"CHANGELOG/#0018-2003-11-13","title":"0.0.18 (2003-11-13)","text":"
"},{"location":"CHANGELOG/#0017-2003-08-05","title":"0.0.17 (2003-08-05)","text":"
"},{"location":"CHANGELOG/#0016-2003-07-04","title":"0.0.16 (2003-07-04)","text":"
"},{"location":"CHANGELOG/#0015-2003-06-17","title":"0.0.15 (2003-06-17)","text":"
"},{"location":"CHANGELOG/#0014-2003-05-28","title":"0.0.14 (2003-05-28)","text":"
"},{"location":"CHANGELOG/#0013-2003-05-22","title":"0.0.13 (2003-05-22)","text":"
"},{"location":"CHANGELOG/#0012-2003-05-08","title":"0.0.12 (2003-05-08)","text":"
"},{"location":"CHANGELOG/#0011-2003-04-15","title":"0.0.11 (2003-04-15)","text":"
"},{"location":"CHANGELOG/#0010-2003-04-08","title":"0.0.10 (2003-04-08)","text":"
"},{"location":"CHANGELOG/#009-2003-04-03","title":"0.0.9 (2003-04-03)","text":"
"},{"location":"CHANGELOG/#008-2003-03-27","title":"0.0.8 (2003-03-27)","text":"
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#general-questions","title":"General Questions","text":"
Can I use MPXJ to write MPP files?
Not at present. Although it is technically feasible to generate an MPP file, the knowledge we have of the file structure is still relatively incomplete, despite the amount of data we are able to correctly extract. It is therefore likely to take a considerable amount of development effort to make this work, and it is conceivable that we will not be able to write the full set of attributes that MPXJ supports back into the MPP file - simply because we don't understand the format well enough. You are therefore probably better off using MSPDI which does support the full range of data items present in an MPP file.
I'm generating output using MPXJ, and when my end users open the file in Microsoft Project, I want to control the appearance of the project data that they see. Can I do this with MPXJ?
In short, the answer to this question is no. The only file format which allows you to control the appearance of project data when opened in Microsoft Project is MPP. Just to clarify, visual appearance in this context refers to the view that appears when the project opens, the filtering applied to the view, the table data visible, the columns in the table, bar styles, text styles and so on. While MPXJ can read this information from an MPP file, none of the supported output file formats contain these attributes.
When I double click on an MPX file to open it in Microsoft Project, I end up with two copies of the file open. What's happening?
This isn't an issue with MPXJ - but we have an answer for you anyway! The problem is caused by an incorrect setting in Microsoft Windows which controls the way MPX files are opened. To fix the setting, open the Control Panel and click on the \"Folder Options\" icon. Select the \"File Types\" tab and scroll down the list of file types until you find an entry for MPX. Once you have found the entry for MPX, click on it to highlight it, then press the \"Advanced\" button at the bottom right hand side of the dialog. In the list of actions that you are now presented with, click on the word \"open\" to highlight it, then click the \"Edit\" button on the right hand side of the dialog. Finally, ensure that the \"Use DDE\" check box is not checked, and you can now finish by clicking OK on each of the open dialogs to dismiss them. You should now find that double clicking on an MPX file will now only open one copy of the file in Microsoft Project.
I use a version of Java older than Java 8, can I use MPXJ?
The last version of MPXJ which supports versions of Java prior to Java 8 is version 7.9.8.
I use a Java 1.4 JVM, but MPXJ is built with a later version of Java, is there anything I can do which will allow me to use it?
Yes there is. Assuming you are using a version of MPXJ prior to 8.0.0, try using Retroweaver.
"},{"location":"faq/#known-issues-with-mpxj","title":"Known Issues with MPXJ","text":"
I have an MPP file created by MS Project 98, and some Flag field values are incorrect.
The MPP8 file format is rather cryptic, and one part of it that I have yet to really understand fully is how the Flag fields are stored. I've spent a lot of time looking at this and have not made a lot of progress, so at the moment no further work is being undertaken to fix this. Contributions of insights, knowledge or fixed code for this problem are welcome. You'll find a bug for this item logged in the SourgeForge bug tracker.
When I read an MPP file I sometimes see an extra task or resource record.
What you are seeing are \"hidden\" tasks and resources which newer versions of Microsoft Project appear to use as placeholders for summary information about all of the tasks and all of the resources in a project. We're not sure exactly which versions of Project hold data like this, although we think this is only relevant for the MPP9 and MPP12 file formats. We've also noticed that the information in these hidden tasks and resources may not be reliable, so don't place too much emphasis on them in your application.
You can ignore the first resource if it has a null value as its name. The attributes of this resource should actually be a summary of all of the resource combined, e.g. utilisation, actual work, remaining work and so on for the complete set of \"real\" resources.
You can ignore the first task if it has an outline level of zero, this task will be a summary of all the \"real\" tasks in the project. You may also find that the name of this task matches the name of the project.
My localised version of MS Project won't read the MPX files created by MPXJ, or MPXJ won't read the MPX files written by my localised version of MS Project.
Localised versions of MS Project (i.e. those which have been translated for use in a non-English locale) read and write MPX files which include localised text strings. The end result of this is that an English/International version of MS Project can't read MPX files produced by a localised version of MS Project, and vice versa.
MPXJ supports a small number of non-English locales, and can read and write MPX files correctly for those locales. You can also use MPXJ to translate MPX files from one locale to another. The MPXFile.setLocale() method must be called prior to reading or writing an MPX file in order to set the required locale. By default, MPXJ will always produce MPX files for the International/English locale, regardless of the locale for which your operating system if configured.
Supported locales for MPX files currently include German, Spanish, French, Italian, Portuguese, Swedish, and Simplified Chinese. Producing a translation for your locale is very easy, please contact us for details on how you can help us to do this.
When I write an MPX file, changes to the project header settings I've made seem to be lost, what's happening?
One of the first things the MPXWriter's write method does is to determine the current locale and update various project settings (for example, currency and date formats) to match the selected locale. This behaviour can be changed so that the settings in the project are left unmodified by setting the useLocaleDefaults parameter to false when calling the write method (for versions of MPXJ up to and including 3.0.0) or by calling the method setUseLocaleDefaults on the MPXWriter instance before calling the write method (for versions of MPXJ after 3.0.0).
"},{"location":"faq/#unit-tests","title":"Unit Tests","text":"
I am trying to run the MPXJ unit tests and I'm having problems with failures in JAXB functionality. What's happening?
Older versions of JAXB were known to have issues with the JUnit classloader, so running the JUnit test runner with the -noloading command line option, other taking other steps to disable JUnit classloading was recommended. This problem is not believed to affect the more recent version of JAXB now used by MPXJ.
"},{"location":"faq/#net-core","title":".NET Core","text":"
When using MPXJ from .NET Core I get an error similar to No data is available for encoding 437. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
By default .NET Core does not include all of the character encodings which may be used by MPXJ (and which are present by default in .NET Framework). To resolve this issue add the following to your code:
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);\n
"},{"location":"faq/#log4j2","title":"log4j2","text":"
When you start MPXJ, you may see the following message written to the console:
ERROR StatusLogger Log4j2 could not find a logging implementation.\nPlease add log4j-core to the classpath. Using SimpleLogger to log to the console.\n
MPXJ uses Apache POI to read MPP files. Apache POI uses log4j2 to write log messages. By default the only dependency POI has on log4j2 is to its interfaces. If you're not already using log4j2 as part of your code, and you don't explicitly include the rest of the log4j2 implementation jar files, you'll see the warning message shown above. This message can safely be ignored, it's just telling you that any log messages POI produces will be written to the console. If you would like to silence this message, you can supply the following argument to the JVM:
-Dlog4j2.loggerContextFactory=org.apache.logging.log4j.simple.SimpleLoggerContextFactory\n
If you are using the Python version of MPXJ, you can provide the argument as shown below when you initialize jpype
.
jpype.startJVM(\"-Dlog4j2.loggerContextFactory=org.apache.logging.log4j.simple.SimpleLoggerContextFactory\")\n
"},{"location":"field-guide/","title":"Field Guide","text":""},{"location":"field-guide/#field-guide","title":"Field Guide","text":"
The tables below provide an indication of which fields are populated when files of different types are read using MPXJ The tables are not hand-crafted: they have been generated from test data and are therefore may be missing some details.
"},{"location":"field-guide/#project","title":"Project","text":""},{"location":"field-guide/#core-fields","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) AM Text \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Increment \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Increment Based On Selected Activity \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Prefix \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Suffix \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 Actual Duration \u2713 Actual Start \u2713 Actual Work \u2713 Actuals In Sync \u2713 Application Version \u2713 \u2713 \u2713 \u2713 Author \u2713 \u2713 \u2713 \u2713 \u2713 Auto Add New Resources and Tasks \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Auto Filter \u2713 Auto Link \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Bar Text Date Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calculate Float on Finish Date of Each Project \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calculate Multiple Float Paths \u2713 \u2713 \u2713 Calculate Multiple Float Paths Ending With Activity Unique ID \u2713 Calculate Multiple Paths Using Total Float \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Category \u2713 \u2713 Comments \u2713 \u2713 \u2713 Company \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Compute Start to Start Lag From Early Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Consider Assignments In Other Project With Priority Equal or Higher Than \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Content Status \u2713 Content Type \u2713 Cost \u2713 Creation Date \u2713 \u2713 \u2713 \u2713 \u2713 Critical Activity Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Critical Slack Limit \u2713 \u2713 Currency Code \u2713 \u2713 Currency Digits \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Currency Symbol \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Currency Symbol Position \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Current Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Custom Properties \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Order \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Days per Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Decimal Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Duration Is Fixed \u2713 Default End Time \u2713 \u2713 \u2713 \u2713 \u2713 Default Overtime Rate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Standard Rate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Start Time \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Work Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Document Version \u2713 Duration \u2713 \u2713 Earned Value Method \u2713 Editable Actual Costs \u2713 \u2713 Editing Time \u2713 Export Flag \u2713 \u2713 Extended Creation Date \u2713 File Application \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 File Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fiscal Year Start \u2713 Fiscal Year Start Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Full Application Name \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Honor Constraints \u2713 \u2713 \u2713 Hyperlink Base \u2713 Ignore Relationships To And From Other Projects \u2713 Inserted Projects Like Summary \u2713 Keywords \u2713 \u2713 \u2713 Language \u2713 Last Author \u2713 Last Printed \u2713 Last Saved \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level All Resources \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level Resources Only Within Activity Total Float \u2713 \u2713 Leveling Priorities \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Limit Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Location Unique ID \u2713 MPP File Type \u2713 MPX Code Page \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX Delimiter \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX File Version \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX Program Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Manager \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Maximum Percentage to Overallocate Resources \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Microsoft Project Server URL \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Day \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Week \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Year \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Multiple Critical Paths \u2713 \u2713 Must Finish By \u2713 \u2713 Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Task Start Is Project Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Tasks Are Effort Driven \u2713 \u2713 New Tasks Are Manual \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Tasks Estimated \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 PM Text \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Percentage Complete \u2713 Planned Start \u2713 \u2713 \u2713 Presentation Format \u2713 Preserve Minimum Float When Leveling \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Preserve Scheduled Early and Late Dates \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Project Externally Edited \u2713 Project File Path \u2713 Project ID \u2713 \u2713 \u2713 Project Title \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Relationship Lag Calendar \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resource Pool File \u2713 Revision \u2713 \u2713 Schedule From \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Scheduled Finish \u2713 \u2713 \u2713 Short Application Name \u2713 Show Project Summary Task \u2713 Split In Progress Tasks \u2713 \u2713 \u2713 \u2713 Start Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 Status Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Subject \u2713 \u2713 \u2713 \u2713 Template \u2713 Thousands Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Time Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Time Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Total Slack Calculation Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 Updating Task Status Updates Resource Status \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Use Expected Finish Dates \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 WBS Code Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Week Start Day \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 When Scheduling Progressed Activities Use \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work \u2713 Work 2 \u2713"},{"location":"field-guide/#baseline-fields","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Date \u2713 Baseline2 Date \u2713 Baseline3 Date \u2713 Baseline4 Date \u2713 Baseline5 Date \u2713 Baseline6 Date \u2713 Baseline7 Date \u2713 Baseline8 Date \u2713 Baseline9 Date \u2713 Baseline10 Date \u2713 Baseline Calendar Name \u2713 \u2713 Baseline Cost \u2713 Baseline Date \u2713 Baseline Duration \u2713 Baseline Finish \u2713 \u2713 Baseline Project Unique ID \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 Baseline Type Name \u2713 Baseline Work \u2713 Last Baseline Update Date \u2713"},{"location":"field-guide/#task","title":"Task","text":""},{"location":"field-guide/#core-fields_1","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) % Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 % Work Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 ACWP \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity Codes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity Status \u2713 \u2713 \u2713 Activity Type \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Duration Units \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work (Labor) \u2713 \u2713 \u2713 Actual Work (Nonlabor) \u2713 \u2713 \u2713 Actual Work Protected \u2713 Bar Name \u2713 Bid Item \u2713 Board Status ID \u2713 Budget Cost \u2713 Budget Work \u2713 CV \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Category of Work \u2713 Complete Through \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Constraint Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Constraint Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Contact \u2713 \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Critical \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Deadline \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Department \u2713 Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Duration Units \u2713 Duration Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Early Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Early Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Earned Value Method \u2713 Effort Driven \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Estimated \u2713 \u2713 \u2713 \u2713 Expanded \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Expected Finish \u2713 \u2713 Expense Items \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 External Early Start \u2713 \u2713 External Late Finish \u2713 \u2713 External Project \u2713 \u2713 External Task \u2713 \u2713 Feature of Work \u2713 Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fixed Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fixed Cost Accrual \u2713 \u2713 \u2713 Free Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Hammock Code \u2713 Hide Bar \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink SubAddress \u2713 ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Ignore Resource Calendar \u2713 \u2713 \u2713 \u2713 \u2713 Late Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Late Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level Assignments \u2713 \u2713 \u2713 Leveling Can Split \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 \u2713 Longest Path \u2713 \u2713 Mail \u2713 Manager \u2713 Manual Duration \u2713 \u2713 Manual Duration Units \u2713 Marked \u2713 \u2713 Milestone \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Null \u2713 \u2713 \u2713 Outline Level \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Outline Number \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Overall Percent Complete \u2713 Overallocated \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Work \u2713 Parent Task Unique ID \u2713 Percent Complete Type \u2713 \u2713 \u2713 Phase of Work \u2713 Physical % Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Planned Cost \u2713 \u2713 \u2713 Planned Duration \u2713 \u2713 \u2713 \u2713 Planned Finish \u2713 \u2713 \u2713 \u2713 Planned Start \u2713 \u2713 \u2713 \u2713 Planned Work \u2713 \u2713 \u2713 Planned Work (Labor) \u2713 \u2713 \u2713 Planned Work (Nonlabor) \u2713 \u2713 \u2713 Preleveled Finish \u2713 \u2713 \u2713 Preleveled Start \u2713 \u2713 \u2713 Primary Resource Unique ID \u2713 \u2713 \u2713 Priority \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Project \u2713 \u2713 \u2713 \u2713 \u2713 Recalc Outline Codes \u2713 Recurring \u2713 \u2713 \u2713 Recurring Data \u2713 Regular Work \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Early Finish \u2713 \u2713 \u2713 Remaining Early Start \u2713 \u2713 \u2713 Remaining Late Finish \u2713 \u2713 \u2713 Remaining Late Start \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Work (Labor) \u2713 \u2713 \u2713 Remaining Work (Nonlabor) \u2713 \u2713 \u2713 Resource Names \u2713 \u2713 Responsibility Code \u2713 Resume \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resume No Earlier Than \u2713 Resume Valid \u2713 Rollup \u2713 \u2713 \u2713 \u2713 Scheduled Duration \u2713 Scheduled Finish \u2713 Scheduled Start \u2713 Secondary Constraint Date \u2713 \u2713 Secondary Constraint Type \u2713 \u2713 Section \u2713 Sequence Number \u2713 \u2713 \u2713 Splits \u2713 \u2713 Sprint ID \u2713 Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Steps \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 \u2713 Subproject File \u2713 \u2713 \u2713 Subproject GUID \u2713 Subproject Task ID \u2713 \u2713 Subproject Task Unique ID \u2713 Subproject Tasks Unique ID Offset \u2713 Summary \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Summary Progress \u2713 Suspend Date \u2713 \u2713 Task Calendar GUID \u2713 Task Mode \u2713 \u2713 Task Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Total Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID Successors \u2713 WBS \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_1","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Duration \u2713 \u2713 \u2713 \u2713 Baseline1 Duration Units \u2713 Baseline1 Estimated Duration \u2713 Baseline1 Estimated Finish \u2713 Baseline1 Estimated Start \u2713 Baseline1 Finish \u2713 \u2713 \u2713 \u2713 Baseline1 Fixed Cost \u2713 Baseline1 Fixed Cost Accrual \u2713 Baseline1 Start \u2713 \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Duration \u2713 \u2713 \u2713 Baseline2 Duration Units \u2713 Baseline2 Estimated Duration \u2713 Baseline2 Estimated Finish \u2713 Baseline2 Estimated Start \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Fixed Cost \u2713 Baseline2 Fixed Cost Accrual \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Duration \u2713 \u2713 \u2713 Baseline3 Duration Units \u2713 Baseline3 Estimated Duration \u2713 Baseline3 Estimated Finish \u2713 Baseline3 Estimated Start \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Fixed Cost \u2713 Baseline3 Fixed Cost Accrual \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Duration \u2713 \u2713 \u2713 Baseline4 Duration Units \u2713 Baseline4 Estimated Duration \u2713 Baseline4 Estimated Finish \u2713 Baseline4 Estimated Start \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Fixed Cost \u2713 Baseline4 Fixed Cost Accrual \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Duration \u2713 \u2713 \u2713 Baseline5 Duration Units \u2713 Baseline5 Estimated Duration \u2713 Baseline5 Estimated Finish \u2713 Baseline5 Estimated Start \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Fixed Cost \u2713 Baseline5 Fixed Cost Accrual \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Duration \u2713 \u2713 \u2713 Baseline6 Duration Units \u2713 Baseline6 Estimated Duration \u2713 Baseline6 Estimated Finish \u2713 Baseline6 Estimated Start \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Fixed Cost \u2713 Baseline6 Fixed Cost Accrual \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Duration \u2713 \u2713 \u2713 Baseline7 Duration Units \u2713 Baseline7 Estimated Duration \u2713 Baseline7 Estimated Finish \u2713 Baseline7 Estimated Start \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Fixed Cost \u2713 Baseline7 Fixed Cost Accrual \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Duration \u2713 \u2713 \u2713 Baseline8 Duration Units \u2713 Baseline8 Estimated Duration \u2713 Baseline8 Estimated Finish \u2713 Baseline8 Estimated Start \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Fixed Cost \u2713 Baseline8 Fixed Cost Accrual \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Duration \u2713 \u2713 \u2713 Baseline9 Duration Units \u2713 Baseline9 Estimated Duration \u2713 Baseline9 Estimated Finish \u2713 Baseline9 Estimated Start \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Fixed Cost \u2713 Baseline9 Fixed Cost Accrual \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 \u2713 Baseline10 Deliverable Finish \u2713 Baseline10 Duration \u2713 \u2713 \u2713 \u2713 Baseline10 Duration Units \u2713 Baseline10 Estimated Duration \u2713 Baseline10 Estimated Finish \u2713 Baseline10 Estimated Start \u2713 Baseline10 Finish \u2713 \u2713 \u2713 \u2713 Baseline10 Fixed Cost \u2713 Baseline10 Fixed Cost Accrual \u2713 Baseline10 Start \u2713 \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Deliverable Finish \u2713 Baseline Deliverable Start \u2713 Baseline Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Duration Units \u2713 Baseline Estimated Duration \u2713 Baseline Estimated Finish \u2713 Baseline Estimated Start \u2713 Baseline Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Fixed Cost \u2713 \u2713 \u2713 Baseline Fixed Cost Accrual \u2713 Baseline Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#custom-fields","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 Outline Code8 \u2713 \u2713 Outline Code8 Index \u2713 Outline Code9 \u2713 \u2713 Outline Code9 Index \u2713 Outline Code10 \u2713 \u2713 Outline Code10 Index \u2713 Start1 \u2713 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"field-guide/#enterprise-fields","title":"Enterprise Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Enterprise Data \u2713 Enterprise Duration1 Units \u2713 Enterprise Duration2 Units \u2713 Enterprise Duration3 Units \u2713 Enterprise Duration4 Units \u2713 Enterprise Duration5 Units \u2713 Enterprise Duration6 Units \u2713 Enterprise Duration7 Units \u2713 Enterprise Duration8 Units \u2713 Enterprise Duration9 Units \u2713 Enterprise Duration10 Units \u2713 Enterprise Project Date1 \u2713 Enterprise Project Date2 \u2713 Enterprise Project Date3 \u2713 Enterprise Project Date4 \u2713 Enterprise Project Number2 \u2713 Enterprise Project Number4 \u2713 Enterprise Project Number5 \u2713 Enterprise Project Number22 \u2713 Enterprise Project Text1 \u2713 \u2713 Enterprise Project Text2 \u2713 Enterprise Project Text3 \u2713 Enterprise Project Text4 \u2713 Enterprise Project Text5 \u2713 Enterprise Project Text6 \u2713 Enterprise Project Text8 \u2713 Enterprise Project Text9 \u2713 Enterprise Project Text10 \u2713 Enterprise Project Text11 \u2713 Enterprise Project Text12 \u2713 Enterprise Project Text13 \u2713 Enterprise Project Text14 \u2713 Enterprise Project Text15 \u2713 Enterprise Project Text16 \u2713 Enterprise Project Text17 \u2713 Enterprise Project Text18 \u2713 Enterprise Project Text19 \u2713 Enterprise Project Text21 \u2713 Enterprise Project Text40 \u2713 \u2713"},{"location":"field-guide/#resource","title":"Resource","text":""},{"location":"field-guide/#core-fields_2","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) % Work Complete \u2713 ACWP \u2713 \u2713 Accrue At \u2713 \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Availability Data \u2713 Available From \u2713 Available To \u2713 BCWS \u2713 Base Calendar \u2713 Booking Type \u2713 \u2713 Budget \u2713 \u2713 Budget Cost \u2713 Budget Work \u2713 CV \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calendar GUID \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Can Level \u2713 \u2713 Code \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Center \u2713 \u2713 Cost Per Use \u2713 Cost Rate A \u2713 Cost Rate B \u2713 Cost Rate C \u2713 Cost Rate D \u2713 Cost Rate E \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Default Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Description \u2713 Email Address \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Generic \u2713 \u2713 Group \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 Hyperlink Address \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink SubAddress \u2713 ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Initials \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Material Label \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Max Units \u2713 Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Overallocated \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Rate \u2713 Overtime Rate Units \u2713 Overtime Work \u2713 \u2713 \u2713 Parent ID \u2713 \u2713 \u2713 \u2713 \u2713 Peak \u2713 \u2713 \u2713 \u2713 \u2713 Per Day \u2713 Phone \u2713 Phonetics \u2713 Pool \u2713 Rate \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resource ID \u2713 \u2713 \u2713 \u2713 Role \u2713 \u2713 \u2713 SV \u2713 Sequence Number \u2713 \u2713 \u2713 Standard Rate \u2713 Standard Rate Units \u2713 Subproject Unique Resource ID \u2713 Supply Reference \u2713 Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unit \u2713 Unit of Measure Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Windows User Account \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 Workgroup \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_2","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 Baseline1 Work \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 Baseline2 Work \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 Baseline3 Work \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 Baseline4 Work \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 Baseline5 Work \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 Baseline6 Work \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 Baseline7 Work \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 Baseline8 Work \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 Baseline9 Work \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 Baseline10 Work \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#custom-fields_1","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"field-guide/#enterprise-fields_1","title":"Enterprise Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Enterprise \u2713 \u2713 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 Enterprise Duration2 Units \u2713 Enterprise Duration3 Units \u2713 Enterprise Duration4 Units \u2713 Enterprise Duration5 Units \u2713 Enterprise Duration6 Units \u2713 Enterprise Duration7 Units \u2713 Enterprise Duration8 Units \u2713 Enterprise Duration9 Units \u2713 Enterprise Duration10 Units \u2713 Enterprise Unique ID \u2713"},{"location":"field-guide/#resource-assignment","title":"Resource Assignment","text":""},{"location":"field-guide/#core-fields_3","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) ACWP \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Assignment Delay \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Assignment GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Assignment Resource GUID \u2713 Assignment Task GUID \u2713 Assignment Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 BCWS \u2713 Budget Cost \u2713 \u2713 Budget Work \u2713 \u2713 CV \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Confirmed \u2713 Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost Account ID \u2713 \u2713 \u2713 Cost Rate Table \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 Created \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink Subaddress \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 Leveling Delay Units \u2713 Linked Fields \u2713 Notes \u2713 \u2713 \u2713 Override Rate \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Owner \u2713 Percent Work Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Planned Cost \u2713 \u2713 \u2713 Planned Finish \u2713 \u2713 \u2713 Planned Start \u2713 \u2713 \u2713 Planned Work \u2713 \u2713 \u2713 Rate Index \u2713 \u2713 Rate Source \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Early Finish \u2713 \u2713 \u2713 Remaining Early Start \u2713 \u2713 \u2713 Remaining Late Finish \u2713 \u2713 Remaining Late Start \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resource Request Type \u2713 Resource Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Response Pending \u2713 \u2713 Resume \u2713 \u2713 \u2713 Role Unique ID \u2713 \u2713 \u2713 SV \u2713 Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 Task Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Team Status Pending \u2713 \u2713 Timephased Actual Overtime Work \u2713 Timephased Actual Work \u2713 Timephased Work \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Variable Rate Units \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Contour \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_3","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 Baseline Finish \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713 Timephased Baseline1 Cost \u2713 Timephased Baseline1 Work \u2713 Timephased Baseline2 Cost \u2713 Timephased Baseline2 Work \u2713 Timephased Baseline3 Cost \u2713 Timephased Baseline3 Work \u2713 Timephased Baseline4 Cost \u2713 Timephased Baseline4 Work \u2713 Timephased Baseline5 Cost \u2713 Timephased Baseline5 Work \u2713 Timephased Baseline6 Cost \u2713 Timephased Baseline6 Work \u2713 Timephased Baseline7 Cost \u2713 Timephased Baseline7 Work \u2713 Timephased Baseline8 Cost \u2713 Timephased Baseline8 Work \u2713 Timephased Baseline9 Cost \u2713 Timephased Baseline9 Work \u2713 Timephased Baseline10 Cost \u2713 Timephased Baseline10 Work \u2713 Timephased Baseline Cost \u2713 Timephased Baseline Work \u2713"},{"location":"field-guide/#custom-fields_2","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"howto-build/","title":"Building MPXJ","text":"
Although MPXJ can be downloaded as a complete package from Maven, GitHub and SourceForge, the development of the library continues between releases and is driven by user requests for new functionality and bug fixes being applied to existing features. Many MPXJ users will work with and ship software based on intermediate versions of MPXJ built from the code on GitHub in order to take advantage of these enhancements before they become available in an official release. This approach is supported by the fact that code is only pushed to the master branch on GitHub if the suite of regression tests have been completed successfully: therefore the quality of the code taken from GitHub at any point can normally be guaranteed to be as good as that in an official release.
In order to take advantage of MPXJ functionality from GitHub, you will need to understand how to build the library, whether you are using it in the form of a Java JAR or a .NET DLL. The following sections explain how to do this.
"},{"location":"howto-build/#obtaining-the-source","title":"Obtaining the source","text":"
The first step in the process of building your own version of MPXJ is to obtain the latest source from GitHub. Instructions for cloning the repository can be found on this page.
"},{"location":"howto-build/#building-the-java-jar","title":"Building the Java JAR","text":"
MPXJ is built using Maven. Once you have a cloned copy of the MPXJ repository, you may wish to update the groupId
, artifactId
or version
attributes in pom.xml
. This will ensure that there is no confusion between the version of MPXJ you build and the official distributions.
If you have a copy of Maven installed, you can issue the following command to build MPXJ:
mvn -DskipTests=true -Dmaven.javadoc.skip=true -Dsource.skip=true package\n
This will generate the mpxj.jar
for you in the Maven target directory, and copies MPXJ's dependencies to the lib
directory. Note that for convenience this skips running the unit tests, javadoc generation and source packaging.
If you are using Maven to manage dependencies for your own project, you can install your newly built version of MPXJ in a local Maven repository:
mvn -DskipTests=true -Dmaven.javadoc.skip=true -Dsource.skip=true install\n
"},{"location":"howto-build/#building-the-net-dlls","title":"Building the .NET DLLs","text":"
Building the .NET versions of MPXJ uses an Ant script to first run Maven to create the Java version, then run IKVM to create a .Net Framework and a .Net Core version.
build.xml
file and ensure that the property named ikvm.net45.dir
is set to point to the location where you have unzipped IKVM.You can now issue the following command:
ant archive\n
The Ant script will recognise that IKVM is present and build the .NET Framework version of MPXJ, with the results found in the src.net\\lib\\net45
folder.
"},{"location":"howto-build/#generating-the-jaxb-code","title":"Generating the JAXB code","text":"
In order to read and write various XML file formats, MPXJ relies on code generated by the JAXB tool xjc
from the XML schema for each file format. Normally you will not need to regenerate this source, but if you are changing the JAXB implementation, or modifying the use of JAXB in some way, then you may need to regenerate this code.
Where I have created an XML schema to support a particular file format, I have included it in the MPXJ distribution in the jaxb
directory. For XML schemas published by product vendors, I have included a note on the home page indicating where these can be located.
If you obtain a copy of the XML schema file you want to work with, you can update the JAXB source using the xjc
target found in the ant build.xml
file. Note that the xjc
target is platform specific, you will need to change the name of xjc
tool to be xjc.bat
, xjc.exe
, or xjc.sh
depending on your operating system. You will also need to set the properties indicated in build.xml
to tell it where to find xjc
and the XML schema file. If you are only regenerating source for one of the XML schemas, you can comment out the others in the Ant script to avoid unnecessary work.
"},{"location":"howto-com/","title":"Getting Started with COM","text":"
The .Net Framework assemblies provided in the DLLs described here are accessible from COM. This should allow you to, for example, write VBA code which utilises MPXJ functionality. To assist with this, for each of the DLLs distributed with MPXJ type libraries in the form of TLB
files are provided in the src.net\\lib\\net45
directory. You will also need to register the MPXJ assemblies in order to use them from COM, using the regasm
assembly registration tool.
For your convenience two batch files have been provided in the src.net\\lib\\net45
directory: mpxj-register-assemblies.bat
and mpxj-unregister-assemblies.bat
. These batch files will register and unregister the MPXJ assemblies respectively. These batch files assume that regasm
is available on the path.
"},{"location":"howto-convert/","title":"Converting Files","text":"
To convert project data between different formats you read the source data using an appropriate Reader class, then write the data using a Writer class which matches the format you want to convert to.
MPXJ can do a lot of the work for you, as the example below illustrates. The UniversalProjectReader
will detect the type of schedule being read and handle it accordingly. The ProjectWriterUtility
will use the extension of the output file to determine the type of file written.
The extensions recognised by the ProjectWriterUtility
class are:
JavaC#Python
package org.mpxj.howto.convert;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\nimport net.sf.mpxj.writer.ProjectWriter;\nimport net.sf.mpxj.writer.ProjectWriterUtility;\n\npublic class ConvertUniversal\n{\n public void convert(String inputFile, String outputFile) throws Exception\n {\n UniversalProjectReader reader = new UniversalProjectReader();\n ProjectFile projectFile = reader.read(inputFile);\n\n ProjectWriter writer = ProjectWriterUtility.getProjectWriter(outputFile);\n writer.write(projectFile, outputFile);\n }\n}\n
using net.sf.mpxj.reader;\nusing net.sf.mpxj.writer;\n\nnamespace MpxjSamples.HowToConvert;\n\npublic class ConvertUniversal\n{\n public void Convert(string inputFile, string outputFile)\n {\n var reader = new UniversalProjectReader();\n var projectFile = reader.read(inputFile);\n\n var writer = ProjectWriterUtility.getProjectWriter(outputFile);\n writer.write(projectFile, outputFile);\n }\n}\n
import jpype\nimport mpxj\n\njpype.startJVM()\n\nfrom net.sf.mpxj.reader import UniversalProjectReader\nfrom net.sf.mpxj.writer import ProjectWriterUtility\n\ndef convert(input_file, output_file):\n reader = UniversalProjectReader();\n project_file = reader.read(input_file);\n writer = ProjectWriterUtility.getProjectWriter(output_file);\n writer.write(project_file, output_file);\n\njpype.shutdownJVM()\n
If you already know the file types you are converting between, you can use the specific Reader and Writer classes, as shown below.
JavaC#Python
package org.mpxj.howto.convert;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\nimport net.sf.mpxj.mpx.MPXWriter;\nimport net.sf.mpxj.reader.ProjectReader;\nimport net.sf.mpxj.writer.ProjectWriter;\n\npublic class ConvertMppToMpx\n{\n public void convert(String inputFile, String outputFile) throws Exception\n {\n ProjectReader reader = new MPPReader();\n ProjectFile projectFile = reader.read(inputFile);\n\n ProjectWriter writer = new MPXWriter();\n writer.write(projectFile, outputFile);\n }\n}\n
using net.sf.mpxj.mpp;\nusing net.sf.mpxj.mpx;\n\nnamespace MpxjSamples.HowToConvert;\n\npublic class ConvertMppToMpx\n{\n public void Convert(string inputFile, string outputFile)\n {\n var reader = new MPPReader();\n var projectFile = reader.read(inputFile);\n\n var writer = new MPXWriter();\n writer.write(projectFile, outputFile);\n }\n}\n
import jpype\nimport mpxj\n\njpype.startJVM()\n\nfrom net.sf.mpxj.mpp import MPPReader\nfrom net.sf.mpxj.mpx import MPXWriter\n\ndef convert(input_file, output_file):\n reader = MPPReader()\n project_file = reader.read(input_file)\n writer = MPXWriter()\n writer.write(project_file, output_file)\n\njpype.shutdownJVM()\n
"},{"location":"howto-dotnet/","title":"Getting Started with .Net","text":"
MPXJ uses a tool called IKVM to convert the original Java version of MPXJ into .Net assemblies. The MPXJ .Net assemblies provided via NuGet and shipped as part of the MPXJ distribution use a \"legacy\" version of IKVM to do this. The \"modern\" version of IKVM allows .Net assemblies to be generated in a different, and ultimately more future-proof way. However there are, at present, some minor disadvantages to using the approach based on the \"modern\" version of IKVM. These disadvantages are being addressed, and ultimately assemblies produced by the \"modern\" version of IKVM will become the default way to include MPXJ in your project.
"},{"location":"howto-dotnet/#mpxj-assemblies-legacy-ikvm","title":"MPXJ assemblies (legacy IKVM)","text":"
For many people the easiest way to work with MPXJ is to use the assemblies generated by the \"legacy\" version of IKVM. This are available via NuGet and also as part of the zip file distribution from GitHub or SourceForge.
MPXJ ships with a set of .Net Framework and .Net Core assemblies, which are managed for you by NuGet or can be found in the src.net\\lib\\net45
and src.net\\lib\\netcoreapp3.1
folders of the distribution respectively.
There are actually three different .Net DLLs available for MPXJ - you only need one of these:
As noted above, in the \"for C#\" and \"for VB\" versions of the MPXJ DLL, getters and setters have been replaced by properties. For example, where you would have previously written code like this:
String text = task.getText();\ntask.setText(text);\n
Now when you work with the \"for C#\" and \"for VB\" versions of the MPXJ DLL, you'll be able to write code in a more familiar style:
String text = task.Text\ntask.Text = text;\n
Also noted above, in the case of the \"for C#\" MPXJ DLL, method names have been modified to begin with an initial capital, so the code will again have a more familiar style. For example, using the original Java method names you'd write something like this:
Task task = projectFile.addTask();\n
Using the \"for C#\" DLL your code will look like this:
Task task = projectFile.AddTask();\n
Once you have selected the version of the MPXJ DLL most suitable for your project, you will need to add its dependencies. If you are using NuGet to manage your dependencies, this is done for you automatically. If you are managing the dependencies manually, the files you need will all be in the relevant sub folder with the src.net\\lib
folder of the MPXJ distribution.
"},{"location":"howto-dotnet/#mpxj-assemblies-modern-ikvm","title":"MPXJ assemblies (modern IKVM)","text":"
The modern version of IKVM provides an extension to modern SDK-style .Net projects which allows you to refer to a Java library using Maven (probably the most common dependency management solution for Java projects). This means that your .Net project will be working directly with the original Java version of the library, which will automatically be translated into .Net assemblies for you as you build your project.
Note that this build process can be time-consuming when your project is first built using this approach, but the results of this translation will be reused, so subsequent builds will be more rapid. You may also see various transient warning messages as this first build completes. These can be ignored and will disappear once your project has finished building.
To include MPXJ in your project using the modern version of IKVM, edit your project file and include the following lines:
<ItemGroup>\n <PackageReference Include=\"IKVM.Maven.Sdk\" Version=\"1.6.8\" />\n</ItemGroup>\n\n<ItemGroup>\n <MavenReference Include=\"net.sf.mpxj:mpxj\" Version=\"12.8.0\"/>\n</ItemGroup>\n
The first <ItemGroup>
you are adding enables IKVM's Maven integration functionality. The second <ItemGroup>
simply refers to the version of MPXJ you'd like to use from Maven.
The advantages of using MPXJ this way are:
The disadvantages of using MPXJ this way are:
As mentioned earlier, work is underway to provide address these disadvantages by providing a \"wrapper\" assembly which hides the \"Java-ness\" of the original MPXJ library.
"},{"location":"howto-dotnet/#net-samples","title":".Net samples","text":"
MPXJ ships with some sample files which can be found in the src.net\\samples
folder of the distribution. These files illustrate how the MPXJ API can be used to manipulate project data. In particular the MpxjQuery
example shows how various elements which make up the project data can be queried. Two versions of this utility are present in src.net\\samples
, one written in C#, and the other written in Visual Basic (VB) to illustrate the basics of using MPXJ in either language. Even if you are developing software in a .Net language you may still find it useful to refer to the Java examples, and indeed the original Java source of MPXJ, to give you an insight into how the API can be used. There is also a standalone repository containing sample .Net code for MPXJ covering use of the library in more depth. This repository can be found here.
"},{"location":"howto-dotnet/#net-and-java-types","title":".Net and Java types","text":"
The .Net version of MPXJ has been generated directly from the Java version using a tool called IKVM. One of the side effects of using IKVM to perform this conversion is that the MPXJ exposes .Net versions of the original Java data types, so for example you will find that the API returns a type called LocalDateTime
rather than a .Net DateTime
, and collections which don't expose the familiar IEnumerable
interface.
To simplify the translation between Java and .Net types, a set of extension methods have been provided. These are included n the NuGet package, and the source can be found in the src.net\\utilities
folder, in a project called MpxjUtilities
. This project contains extension methods which enhance both Java and .Net classes to make it easier to pass data to and from the API. For example the extension method ToIEnumerable
is added to Java collection data types which allows them to be iterated using the familiar foreach
.Net syntax.
To use these extension methods, simply add a reference to the MpxjUtilities
assembly in your own project. The methods themselves are documented in the source, and examples of their use can be seen in the samples provided in the src.net\\samples
folder.
"},{"location":"howto-dotnet/#mpxj-and-the-gac","title":"MPXJ and the GAC","text":"
For your convenience two batch files are provided in the src.net\\lib\\net45
directory: mpxj-gac-install.bat
and mpxj-gac-uninstall.bat
. These batch files install the MPXJ assemblies into the GAC and uninstall the MPXJ assemblies from the GAC using the gacutil
global assembly cache tool. Note that these batch files assume that gacutil
is available on the path.
"},{"location":"howto-read-asta/","title":"How To: Read Asta Powerproject and Easyproject files","text":"
Asta Powerproject and Asta Easyproject both use PP files.
"},{"location":"howto-read-asta/#reading-pp-files","title":"Reading PP files","text":"
The simplest way to read a PP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pp\");\n
You can work directly with the AstaFileReader
by replacing UniversalProjectReader
with AstaFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the AstaFileReader
class.
"},{"location":"howto-read-conceptdraw/","title":"How To: Read ConceptDraw PROJECT files","text":"
ConceptDraw PROJECT writes CDPX, CPDZ and CPDTZ files.
"},{"location":"howto-read-conceptdraw/#reading-cdpx-cpdz-and-cpdtz-files","title":"Reading CDPX, CPDZ and CPDTZ files","text":"
The simplest way to read a CDPX, CPDZ or CPDTZ file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.cdpx\");\n
You can work directly with the ConceptDrawProjectReader
by replacing UniversalProjectReader
with ConceptDrawProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the ConceptDrawProjectReader
class.
"},{"location":"howto-read-fasttrack/","title":"How To: Read FastTrack Schedule files","text":"
FastTrack Schedule writes schedule data to FTS files. Note that MPXJ has only been tested with FTS files produced by FastTrack 10.
"},{"location":"howto-read-fasttrack/#reading-fts-files","title":"Reading FTS files","text":"
The simplest way to read an FTS file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.fts\");\n
You can work directly with the FastTrackReader
by replacing UniversalProjectReader
with FastTrackReader
, although this offers no particular advantage as there are no additional configuration settings available on the FastTrackReader
class.
"},{"location":"howto-read-ganttdesigner/","title":"How To: Read Gantt Designer files","text":"
Gantt Designer writes schedule data to GNT files.
"},{"location":"howto-read-ganttdesigner/#reading-gnt-files","title":"Reading GNT files","text":"
The simplest way to read a GNT file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.gnt\");\n
You can work directly with the GanttDesignerReader
by replacing UniversalProjectReader
with GanttDesignerReader
, although this offers no particular advantage as there are no additional configuration settings available on the GanttDesignerReader
class.
"},{"location":"howto-read-ganttproject/","title":"How To: Read GanttProject files","text":"
GanttProject writes schedule data to GAN files (which are actually just XML files).
"},{"location":"howto-read-ganttproject/#reading-gan-files","title":"Reading GAN files","text":"
The simplest way to read a GAN file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.gan\");\n
You can work directly with the GanttProjectReader
by replacing UniversalProjectReader
with GanttProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the GanttProjectReader
class.
"},{"location":"howto-read-merlin/","title":"How To: Read Merlin files","text":"
Merlin Project is a Mac application. MPXJ provides experimental support for reading some Merlin Project files. The Merlin file format does not necessarily contain a full set of start and finish dates for each task. Merlin calculates these dates when it displays a schedule. At the moment MPXJ lacks this functionality, so you may not find start and finish dates for each task.
"},{"location":"howto-read-merlin/#reading-merlin-files","title":"Reading Merlin files","text":"
The simplest way to read a Merlin file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample-merlin-project\");\n
Note that on a Mac Merlin projects are not single files, but rather they are directories containing multiple files (the Mac Finder normally hides this from you). When using MPXJ to read a Merlin project you pass the directory name to the UniversalProjectReader
class.
You can work directly with the MerlinReader
by replacing UniversalProjectReader
with MerlinReader
, although this offers no particular advantage as there are no additional configuration settings available on the MerlinReader
class.
"},{"location":"howto-read-mpd/","title":"How To: Read MPD files","text":"
Microsoft Project from Project 98 until Project 2003 could read and write schedules as Microsoft Access database files with the extension MPD. Versions of Microsoft Project after 2003 can import projects from MPD databases but cannot create or write to them. Project 98 crates a database with a schema known as MPD8, which MPXJ does not currently support reading. Project 2000 onward uses a schema call MPD9 which MPXJ can read.
Coincidentally, Microsoft Project Server originally shared the same database schema as the MPD9 file format. This means that the MPDDatabaseReader
class may also be used to read data from a Project Server SQL Server database.
"},{"location":"howto-read-mpd/#reading-mpd-files","title":"Reading MPD files","text":"
The simplest way to read an MPD file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpd\");\n
In order for this to work the UniversalProjectReader
assumes that the JDBC-ODBC bridge driver is available. As an MPD file can contain multiple projects, the UniversalProjectReader
assumes that a single project is present in the file with an ID of 1. This is normally the case when a single project is saved as an MPD file.
"},{"location":"howto-read-mpd/#using-mpddatabasereader","title":"Using MPDDatabaseReader","text":"
You can work directly with the MPDDatabaseReader
class by replacing UniversalProjectReader
with MPDDatabaseReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpd/#setting-the-database-connection","title":"Setting the database connection","text":"
Three read
methods are provided by the MPDDatabaseReader
class which allow you to work directly with an MPD file, either by passing in a file name a File
instance or an InputStream
instance. These methods use the JDBC-ODBC bridge driver to open the database. An alternative approach is for you to provide your own database connection. To that end the MPDDatabaseReader
class provides two additional methods: setConnection
and setDataSource
which allows you to supply a JDBC Connection
instance or a JDBC DataSource
instance.
You can of course use this to set up your own JDBC connection to read from the MDB file, however these methods may be more useful if you wish to read data from a Microsoft Project Server database instance, which shares the same schema as the MDB file.
"},{"location":"howto-read-mpd/#selecting-a-project","title":"Selecting a project","text":"
If the MPD file contains multiple projects, you can retrieve details of the available projects using the listProjects
method. This returns a map of project IDs and project names. The sample code below illustrates how to retrieve this list of projects, and select the specific project that you want to read. In this case we read each project in the file in turn.
import java.util.Map;\nimport java.util.Map.Entry;\nimport net.sf.mpxj.mpd.MPDDatabaseReader;\n\nMPDDatabaseReader reader = new MPDDatabaseReader();\nreader.setConnection(connection);\nMap<Integer, String> projects = reader.listProjects();\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(\"Project name: \" + entry.getValue());\n reader.setProjectID(entry.getKey());\n reader.read();\n}\n
"},{"location":"howto-read-mpp/","title":"How To: Read MPP files","text":"
The native Microsoft Project file format is typically has the extension MPP (or MPT for a template file). Although a common file extension uis used, there are actually a number if different variants of the file format. The list below shows the different variants, and the versions of Microsoft Project which produce them:
"},{"location":"howto-read-mpp/#reading-mpp-files","title":"Reading MPP files","text":"
The simplest way to read an MPP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#using-mppreader","title":"Using MPPReader","text":"
You can work directly with the MPPReader
class by replacing UniversalProjectReader
with MPPReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpp/#password-protected-files","title":"Password Protected Files","text":"
When a read password has been set for an MPP file, the contents of the file are partially encrypted. If you attempt to read an MPP file which has been password protected an MPXJException
will be raised, with the message File is password protected
.
MPXJ only supports decryption of password protected MPP9 files. The code below illustrates how you would supply the password:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPassword(\"my secret password\");\nProjectFile project = reader.read(\"my-sample.mpp\");\n
The encryption used by MPP9 files doesn't actually require the password in order to read the contents of the file. If you wish you can set a flag to ignore the MPP9 password protection.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setRespectPasswordProtection(false);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#presentation-data","title":"Presentation Data","text":"
Alongside the schedule data itself, MPXJ also extracts much of the presentation data available in an MPP file, for example table layouts, filters, graphical indicators and so on. If you are not interested in this type of data, you can tell MPXJ not to read it. This will speed up reading MPP files, and slightly reduce memory consumption. To do this you will use the setReadPresentationData
method, as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPresentationData(false);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#properties-only","title":"Properties Only","text":"
Should you wish to simply \"peek\" at the contents of the MPP file by just reading the summary properties from the file, you can use the setReadPropertiesOnly
method as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPropertiesOnly(true);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#raw-timephased-data","title":"Raw timephased data","text":"
When MPXJ reads timephased data from an MPP file it \"normalises\" the data, converting it from the compact format Microsoft Project uses internally into a representation which shows the timephased values day-by-day. This is generally easier to understand, and can be further processed using the methods in the TimephasedUtility
class to show the data over the required timescale.
If you do not want MPXJ to normalise the data, and would prefer instead to work with the raw data directly from the MPP file, you can use the setUseRawTimephasedData
to do this, as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setUseRawTimephasedData(true);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpx/","title":"How To: Read MPX files","text":"
Versions of Microsoft Project up to Project 98 could read and write MPX files as a data interchange format. Versions of Project after Project 98 until Project 2010 can only read MPX files. Versions of Microsoft Project after 2010 cannot read MPX files. Other third party project planning applications continue to use MPX as a data interchange format.
"},{"location":"howto-read-mpx/#reading-mpx-files","title":"Reading MPX files","text":"
The simplest way to read an MPX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpx\");\n
"},{"location":"howto-read-mpx/#using-mpxreader","title":"Using MPXReader","text":"
You can work directly with the MPXReader
class by replacing UniversalProjectReader
with MPXReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpx/#locale","title":"Locale","text":"
It appears that very early in the life of the MPX file format, Microsoft Project was internationalised to allow versions of the application to be used in languages other than English. One unfortunate side effect of this was that the text used in the MPX file format was also internationalised. Thus rather than having a single file format which could be exchanged globally between any applications, you now need to know which internationalised version of Microsoft Project was used to create the MPX file in order to read it successfully.
Fortunately in most cases MPX files have been generated using the English language version of Microsoft Project, or an application which generates this variant, so the default settings for MPXReader
will work.
If you encounter an MPX file generated by something other than an English version of Microsoft Project, you'll need to explicitly set the locale in order to read the file. The sample below shows how this is done:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nMPXReader reader = new MPXReader();\nreader.setLocale(Locale.GERMAN);\nProjectFile project = reader.read(\"my-sample.mpx\");\n
The following locales are supported by MPXReader
:
You can retrieve a list of supported locales programmatically using the code shown below:
import net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nLocale[] locales = MPXReader.getSupportedLocales();\n
"},{"location":"howto-read-mpx/#ignore-text-models","title":"Ignore Text Models","text":"
You should not normally need to modify this option.
An MPX file consists of a series of sections with each section representing a specific entity, for example tasks, resources, and so on. The set of attributes written for each entity is not fixed, instead at the start of each section the attributes which appear in the file are listed in two forms: as a series of numeric values, and as a series on human-readable attribute names.
Originally MPXJ used to read both of these lists, however it was found that the human-readable attribute names were often not consistent and caused problems when attempting to read MPX files. The default now is that these attributes are ignored. If for some reason you should wish to enable MPXJ's original behaviour and read these files, you would call setIgnoreTextModels
as shown in the example below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nMPXReader reader = new MPXReader();\nreader.setIgnoreTextModels(false);\nProjectFile project = reader.read(\"my-sample.mpx\");\n
"},{"location":"howto-read-mspdi/","title":"How To: Read MSPDI files","text":"
The Microsoft Project Data Interchange (MSPDI) format is an XML file format which Microsoft Project has been able to read and write since Project 2002.
"},{"location":"howto-read-mspdi/#reading-mspdi-files","title":"Reading MSPDI files","text":"
The simplest way to read an MSPDI file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#using-mspdireader","title":"Using MSPDIReader","text":"
You can work directly with the MSPDIReader
class by replacing UniversalProjectReader
with MSPDIReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mspdi/#encoding","title":"Encoding","text":"
By default MPXJ assumes that MSPDI files are encoded as UTF-8. The UniversalProjectReader
understands Unicode Byte Order Marks (BOM) and will adjust the encoding appropriately if a BOM is present. If you have an MSPDI file with an unusual encoding, you can manually set the encoding used by the reader.
Two methods are provided to do this: setCharset
and setEncoding
. The setCharset
method takes an instance of the Charset
class, while the setEncoding
method takes the name of an encoding. Examples of these methods are shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\n\n// Use a Charset instance\nreader.setCharset(Charset.forName(\"GB2312\"));\nProjectFile project = reader.read(\"my-sample.xml\");\n\n// Use an encoding name\nreader.setEncoding(\"GB2312\");\nproject = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#microsoft-project-compatibility","title":"Microsoft Project Compatibility","text":"
Microsoft Project will read MSPDI files which are not valid XML according to the MSPDI schema. By default MPXJ has been configured to take the same approach. If for some reason you wish to apply strict validation when reading an MSPDI file, you can do this using the setMicrosoftProjectCompatibleInput
method, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\nreader.setMicrosoftProjectCompatibleInput(false);\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from an MSPDI file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the MSPDIReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.xml\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-openplan/","title":"How To: Deltek Open Plan BK3 files","text":"
Deltek Open Plan is a planning tool for Windows which can store schedule data in a variety of databases, and export schedules to BK3 files.
"},{"location":"howto-read-openplan/#reading-open-plan-files","title":"Reading Open Plan files","text":"
The simplest way to read an Open Plan file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.bk3\");\n
You can work directly with the OpenPlanReader
by replacing UniversalProjectReader
with OpenPlanReader
, although this offers no particular advantage as there are no additional configuration settings available on the OpenPlanReader
class.
"},{"location":"howto-read-p3/","title":"How To: Read P3 files","text":"
A Primavera P3 installation stores project data as a database consisting of a number of individual files. In a typical P3 installation files for a number of different projects live in a single projects directory. A P3 user can back up an individual project to create a PRX file, which is a compressed archive containing all of the files from a single project.
"},{"location":"howto-read-p3/#reading-prx-files","title":"Reading PRX files","text":"
The simplest way to read a PRX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.prx\");\n
You can work directly with the P3PRXFileReader
by replacing UniversalProjectReader
with P3PRXFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the P3PRXFileReader
class.
"},{"location":"howto-read-p3/#reading-a-p3-directory","title":"Reading a P3 directory","text":"
If you are working with a directory containing P3 project data you have two options. If you know that the directory only contains a single project, you can use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-p3-directory\");\n
If the directory happens to contain multiple projects the UniversalProjectReader
will simply read the first one it finds, in alphabetic order.
If you know that the directory you are working with contains multiple projects, you will need to use the P3DatabaseReader
class.
import java.util.List;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.p3.P3DatabaseReader;\n\n// ...\n\n// Find a list of the project names\nString directory = \"my-p3-directory\";\nList<String> projectNames = P3DatabaseReader.listProjectNames(directory);\n\n// Tell the reader which project to work with\nP3DatabaseReader reader = new P3DatabaseReader();\nreader.setProjectName(projectNames.get(0));\n\n// Read the project\nProjectFile project = reader.read(directory);\n
As the example above shows, the P3DatabaseReader
class provides a method which lists the names of the P3 projects it finds in a directory. You can then select which project you want to load, and call the setProjectName
method of the reader to make this selection. You can then call the read
method passing in the name of the directory, and the reader will extract data for the selected project.
"},{"location":"howto-read-phoenix/","title":"How To: Read Phoenix Project Manager files","text":"
Phoenix Project Manager uses PPX files.
"},{"location":"howto-read-phoenix/#reading-ppx-files","title":"Reading PPX files","text":"
The simplest way to read a PPX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.ppx\");\n
You can work directly with the PhoenixReader
by replacing UniversalProjectReader
with PhoenixReader
, although this offers no particular advantage as there are no additional configuration settings available on the PhoenixReader
class.
"},{"location":"howto-read-planner/","title":"How To: Read Planner files","text":"
Gnome Planner is a popular open source planning tool which writes its own XML files.
"},{"location":"howto-read-planner/#reading-planner-files","title":"Reading Planner files","text":"
The simplest way to read a Planner file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
You can work directly with the PlannerReader
by replacing UniversalProjectReader
with PlannerReader
, although this offers no particular advantage as there are no additional configuration settings available on the PlannerReader
class.
"},{"location":"howto-read-plf/","title":"How To: Read Primavera PLF files","text":"
Primavera P6 can export layout information as PLF files. These files define the visual appearance of the P6 user interface, and can be imported and exported by P6. Although MPXJ doesn't currently offer any facilities to interpret the contents of these files, the data they contain can be read.
"},{"location":"howto-read-plf/#reading-plf-files","title":"Reading PLF files","text":"
A PLF file contains \"structured text\" and can be read using StructuredTextParser
:
import net.sf.mpxj.primavera.StructuredTextParser;\n\n// ...\n\nStructuredTextParser parser = new StructuredTextParser();\nStructuredTextRecord record = parser.parse(new FileInputStream(\"test.plf\"))\n
"},{"location":"howto-read-plf/#attributes","title":"Attributes","text":"
The resulting StructuredTextRecord
contains attributes which can be accesed individually by name, as shown below:
record.getAttribute(\"attribute_name\");\n
The attributes can also be retrieved in the form of a Map
containing all attributes for this record:
Map<String,String> attributes = record.getAttributes();\nattributes.get(\"attribute_name\");\n
Each record has two special attributes: a record number, and optionally a record name. These appear as part of the identifying information for each record, not as part of the general set of attributes for the record. These can be retrieved as shown below:
String recordNumber = record.getRecordNumber();\nString recordName = record.getRecordName();\n
These attributes will also be found in the attributes Map
with the keys _record_number
and _record_name
.
"},{"location":"howto-read-plf/#child-records","title":"Child records","text":"
Along with a set of attributes, each StructuredTextRecord
may have child StructuredTextRecord
instances. These be retrieved as a list, as shown below:
List<StructuredTextRecord> childRecords = record.getChildren();\n
Certain record types are named, and where this is the case a child record can be retrieved individually by name:
StructuredTextRecord child = record.getChild(\"child_name\");\n
"},{"location":"howto-read-pmxml/","title":"How To: Read Primavera PMXML files","text":"
Primavera P6 can export data in an XML format known as PMXML.
"},{"location":"howto-read-pmxml/#reading-pmxml-files","title":"Reading PMXML files","text":"
The simplest way to read a PMXML file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-pmxml/#using-primaverapmfilereader","title":"Using PrimaveraPMFileReader","text":"
You can work directly with the PrimaveraPMFileReader
by replacing UniversalProjectReader
with PrimaveraPMFileReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-pmxml/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently, the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-pmxml/#multiple-projects","title":"Multiple Projects","text":"
A PMXML file can contain multiple projects. By default, MPXJ reads the first non-external project it finds in the file, otherwise it defaults to the first project it finds. You can however use MPXJ to list the projects contained in a PMXML file, as shown below:
import net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nFileInputStream is = new FileInputStream(\"my-sample.xml\");\nMap<Integer, String> projects = reader.listProjects(is);\nSystem.out.println(\"ID\\tName\");\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(entry.getKey()+\"\\t\"+entry.getValue());\n}\n
The call to listProjects
returns a Map
whose key is the project ID, and the values are project short names.
Once you have decided which of these projects you want to work with, you can call setProjectID
to tell the reader which project to open, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setProjectID(123);\nProjectFile file = reader.read(\"my-sample.xml\");\n
Alternatively you can ask MPXJ to read all the projects contained in the file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
The call to the readAll
method returns a list of ProjectFile
instances corresponding to the projects in the PMXML file.
"},{"location":"howto-read-pmxml/#link-cross-project-relations","title":"Link Cross-Project Relations","text":"
A PMXML file can contain multiple projects with relations between activities which span those projects. By default, these cross-project relations are ignored. However, if you set the linkCrossProjectRelations
reader attribute to true
, MPXJ will attempt to link these relations across projects:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setLinkCrossProjectRelations(true);\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-pmxml/#baselines","title":"Baselines","text":"
Users can export PMXML files from P6 which contain the baseline project along with the main project being exported. When the readAll
method is used to read a PMXML file, MPXJ will attempt to populate the baseline fields of the main project if it can locate the baseline project in the PMXML file.
By default the \"Planned Dates\" strategy is used to populate baseline fields, which is the approach P6 uses when the \"Earned Value Calculation\" method is set to \"Budgeted values with planned dates\".
PrimaveraPMFileReader
provides a method allowing the strategy to be changed, thus allowing you to select the \"Current Dates\" strategy, which is the approach used by P6 when the Earned Value Calculation method is set to \"At Completion values with current dates\" or \"Budgeted values with current dates\". The example below illustrates how this method is used:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraBaselineStrategy;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setBaselineStrategy(PrimaveraBaselineStrategy.CURRENT_DATES);\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-primavera/","title":"How To: Read a Primavera P6 database","text":"
Reading from a Primavera database is a slightly different proposition to reading file-based project data, as a database connection is required.
"},{"location":"howto-read-primavera/#java","title":"Java","text":"
The example below illustrates how to do this for a Primavera database hosted in SQL Server, using the open source JTDS JDBC driver. The only difference when reading from an Oracle database will be the JDBC driver and connection string used.
import java.sql.Connection;\nimport java.sql.DriverManager;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\n//\n// Load the JDBC driver\n//\nString driverClass=\"net.sourceforge.jtds.jdbc.Driver\";\nClass.forName(driverClass);\n\n//\n// Open a database connection. You will need to change\n// these details to match the name of your server, database, user and password.\n//\nString connectionString=\"jdbc:jtds:sqlserver://localhost/PMDB;user=pmdb;password=pmdb\";\nConnection c = DriverManager.getConnection(connectionString);\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setConnection(c);\n\n//\n// Retrieve a list of the projects available in the database\n//\nMap<Integer,String> projects = reader.listProjects();\n\n//\n// At this point you'll select the project\n// you want to work with.\n//\n\n//\n// Now open the selected project using its ID\n//\nint selectedProjectID = 1;\nreader.setProjectID(selectedProjectID);\nProjectFile projectFile = reader.read();\n
You can also connect to a standalone SQLite P6 database. This is easier to achieve as a specific reader class has been created which manages the database connection for you:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseFileReader;\n\n...\n\nPrimaveraDatabaseFileReader reader = new PrimaveraDatabaseFileReader();\n\n//\n// Retrieve a list of the projects available in the database\n//\nMap<Integer,String> projects = reader.listProjects(\"PPMDBSQLite.db\");\n\n//\n// At this point you'll select the project\n// you want to work with.\n//\n\n//\n// Now open the selected project using its ID\n//\nint selectedProjectID = 1;\nreader.setProjectID(selectedProjectID);\nProjectFile projectFile = reader.read(\"PPMDBSQLite.db\");\n
"},{"location":"howto-read-primavera/#net","title":".Net","text":"
The situation is a little more complicated when using the .Net version of MPXJ. In this case you are still actually running Java code, so you need to use a JDBC driver to establish a database connection.
Your first step will be to convert your JDBC driver to a .Net assembly using IKVM. For example the command line below converts a version of Microsoft's SQL Server JDBC driver to a .Net assembly:
c:\\java\\ikvm-8.0.5449.1\\bin\\ikvmc.exe -out:mssql-jdbc-6.4.0.jre8.dll -target:library -keyfile:c:\\java\\mpxj\\src.net\\mpxj.snk -version:6.4.0.0 mssql-jdbc-6.4.0.jre8.jar\n
You can then add a reference to this assembly to your project. Configuring the JDBC driver needs to be done in a slightly different way than you would when using Java. Here we need to create an instance of the JDBC driver class directly, rather than referencing it by name as we would in Java.
//\n// Configure the connection\n//\nvar driver = new SQLServerDriver();\nvar connectionProperties = new Properties();\nvar connection = driver.connect(connectionString, connectionProperties);\n\n//\n// Configure the reader\n//\nvar reader = new PrimaveraDatabaseReader();\nreader.Connection = connection;\n
You can find the complete code for this here.
"},{"location":"howto-read-primavera/#using-primaveradatabasereader","title":"Using PrimaveraDatabaseReader","text":"
This section documents the additional options provided by the PrimaveraDatabaseReader.
"},{"location":"howto-read-primavera/#activity-wbs","title":"Activity WBS","text":"
In the original implementation of the database handling code, MPXJ would assign each task representing a Primavera Activity its own distinct WBS value. This does not match Primavera's behaviour where all of a WBS element's child activities will have the same WBS value as the parent WBS element. MPXJ's default behaviour now matches Primavera, but should you wish to you can revert to the original behaviour by calling the setMatchPrimaveraWBS
as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setMatchPrimaveraWBS(false);\n
"},{"location":"howto-read-primavera/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently, the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-primavera/#reading-additional-attributes","title":"Reading Additional Attributes","text":"
A data-driven approach is used to extract the attributes used by MPXJ from the database. You can if you wish change the way attributes are read from the file, or add support for additional attributes. This assumes that you know the column name of the attributes you want to work with in the database. To make changes you will need to retrieve the maps which define which MPXJ attributes are used to store which columns from the database:
PrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nMap<FieldType, String> resourceFieldMap = reader.getResourceFieldMap();\nMap<FieldType, String> wbsFieldMap = reader.getWbsFieldMap();\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nMap<FieldType, String> assignmentFieldMap = reader.getAssignmentFieldMap();\n
These maps will contain the default mapping between columns and MPXJ attributes. You can modify these existing mappings, or add new ones, for example:
//\n// Change the field used to store rsrc_id\n//\nactivityFieldMap.remove(TaskField.NUMBER1);\nactivityFieldMap.put(TaskField.NUMBER2, \"rsrc_id\");\n\n//\n// Read an Activity column called an_example_field and store it in TEXT10\n//\nactivityFieldMap.put(TaskField.TEXT10, \"an_example_field\");\n
"},{"location":"howto-read-primavera/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from a Primavera database. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the PrimaveraDatabaseReader
to report errors encountered when reading from a Primavera database:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\n\nreader.setIgnoreErrors(false);\n
Note that if errors are ignored when reading from a Primavera database, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-projectcommander/","title":"How To: Read Project Commander files","text":"
Project Commander is a planning tool for Windows which writes its own PC file format.
"},{"location":"howto-read-projectcommander/#reading-project-commander-files","title":"Reading Project Commander files","text":"
The simplest way to read a Project Commander file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pc\");\n
You can work directly with the ProjectCommanderReader
by replacing UniversalProjectReader
with ProjectCommanderReader
, although this offers no particular advantage as there are no additional configuration settings available on the ProjectCommanderReader
class.
"},{"location":"howto-read-projectlibre/","title":"How To: Read ProjectLibre files","text":"
ProjectLibre writes schedule data to POD files. MPXJ can read POD files written by ProjectLibre version 1.5.5 and later versions.
"},{"location":"howto-read-projectlibre/#reading-pod-files","title":"Reading POD files","text":"
The simplest way to read a POD file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pod\");\n
You can work directly with the ProjectLibreReader
by replacing UniversalProjectReader
with ProjectLibreReader
, although this offers no particular advantage as there are no additional configuration settings available on the ProjectLibreReader
class.
"},{"location":"howto-read-schedule-grid/","title":"How To: Read Schedule Grid files","text":"
Schedule grid files are produced when a schedule is exported from Sage 100 Contractor.
"},{"location":"howto-read-schedule-grid/#reading-schedule-grid-files","title":"Reading Schedule Grid files","text":"
The simplest way to read a schedule grid file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.schedule_grid\");\n
"},{"location":"howto-read-schedule-grid/#using-sagereader","title":"Using SageReader","text":"
You can work directly with the SageReader
class by replacing UniversalProjectReader
with SageReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-schedule-grid/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from a Schedule Grid file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the SageReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sage.SageReader;\n\n// ...\n\nSageReader reader = new SageReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.schedule_grid\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-sdef/","title":"How To: Read SDEF files","text":"
The Standard Data Exchange Format (SDEF) is the US Army Corps of Engineers standard format for exchanging schedule data between systems. The definition of this format can be found here.
"},{"location":"howto-read-sdef/#reading-sdef-files","title":"Reading SDEF files","text":"
The simplest way to read an SDEF file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.sdef\");\n
"},{"location":"howto-read-sdef/#using-sdefreader","title":"Using SDEFReader","text":"
You can work directly with the SDEFReader
class by replacing UniversalProjectReader
with SDEFReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-sdef/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from an SDEF file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the SDEFReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFReader;\n\n// ...\n\nSDEFReader reader = new SDEFReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.sdef\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-suretrak/","title":"How To: Read SureTrak files","text":"
A Primavera SureTrak installation stores project data as a database consisting of a number of individual files. In a typical SureTrak installation files for a number of different projects live in a single projects directory. A SureTrak user can back up an individual project to create an STX file, which is a compressed archive containing all of the files from a single project.
"},{"location":"howto-read-suretrak/#reading-stx-files","title":"Reading STX files","text":"
The simplest way to read an STX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.stx\");\n
You can work directly with the SureTrakSTXFileReader
by replacing UniversalProjectReader
with SureTrakSTXFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the SureTrakSTXFileReader
class.
"},{"location":"howto-read-suretrak/#reading-a-suretrak-directory","title":"Reading a SureTrak directory","text":"
If you are working with a directory containing SureTrak project data you have two options. If you know that the directory only contains a single project, you can use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-suretrak-directory\");\n
If the directory happens to contain multiple projects the UniversalProjectReader
will simply read the first one it finds, in alphabetic order.
If you know that the directory you are working with contains multiple projects, you will need to use the SureTrakDatabaseReader
class.
import java.util.List;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.suretrak.SureTrakDatabaseReader;\n\n// ...\n\n// Find a list of the project names\nString directory = \"my-suretrak-directory\";\nList<String> projectNames = SureTrakDatabaseReader.listProjectNames(directory);\n\n// Tell the reader which project to work with\nP3DatabaseReader reader = new SureTrakDatabaseReader();\nreader.setProjectName(projectNames.get(0));\n\n// Read the project\nProjectFile project = reader.read(directory);\n
As the example above shows, the SureTrakDatabaseReader
class provides a method which lists the names of the SureTrak projects it finds in a directory. You can then select which project you want to load, and call the setProjectName
method of the reader to make this selection. You can then call the read
method passing in the name of the directory, and the reader will extract data for the selected project.
"},{"location":"howto-read-synchro/","title":"How To: Read Synchro Scheduler files","text":"
Synchro Scheduler writes SP files.
"},{"location":"howto-read-synchro/#reading-sp-files","title":"Reading SP files","text":"
The simplest way to read an SP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.sp\");\n
You can work directly with the SynchroReader
by replacing UniversalProjectReader
with SynchroReader
, although this offers no particular advantage as there are no additional configuration settings available on the SynchroReader
class.
"},{"location":"howto-read-turboproject/","title":"How To: Read TurboProject files","text":"
TurboProject writes schedule data to PEP files.
"},{"location":"howto-read-turboproject/#reading-pep-files","title":"Reading PEP files","text":"
The simplest way to read a PEP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pep\");\n
You can work directly with the TurboProjectReader
by replacing UniversalProjectReader
with TurboProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the TurboProjectReader
class.
"},{"location":"howto-read-xer/","title":"How To: Read XER files","text":"
The XER file format has long been read and written by Primavera P6. Although an XML file format (PMXML) is now also supported, the XER file format is still widely used.
"},{"location":"howto-read-xer/#reading-xer-files","title":"Reading XER files","text":"
The simplest way to read an XER file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#using-primaveraxerfilereader","title":"Using PrimaveraXERFileReader","text":"
You can work directly with the PrimaveraXERFileReader
class by replacing UniversalProjectReader
with PrimaveraXERFileReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-xer/#ignore-errors","title":"Ignore Errors","text":"
By default P6 ignores records it can't successfully read from an XER file. MPXJ takes the same approach, and in most cases if it doesn't receive the data it expects for a particular record it will ignore the problematic item.
This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the PrimaveraXERFileReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.xer\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-xer/#encoding","title":"Encoding","text":"
By default MPXJ assumes that XER files are encoded using Windows-1252. The UniversalProjectReader
understands Unicode Byte Order Marks (BOM) and will adjust the encoding appropriately if a BOM is present. If you have an XER file with an unusual encoding, you can manually set the encoding used by the reader.
Two methods are provided to do this: setCharset
and setEncoding
. The setCharset
method takes an instance of the Charset
class, while the setEncoding
method takes the name of an encoding. Examples of these methods are shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\n\n// Use a Charset instance\nreader.setCharset(Charset.forName(\"GB2312\"));\nProjectFile project = reader.read(\"my-sample.xer\");\n\n// Use an encoding name\nreader.setEncoding(\"GB2312\");\nproject = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#multiple-projects","title":"Multiple Projects","text":"
An XER file can contain multiple projects. By default MPXJ reads the first project it finds in the file which has been marked as the \"exported\" project, otherwise it will simply read the first project it finds. You can however use MPXJ to list the projects contained in an XER file, as shown below:
import net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nFileInputStream is = new FileInputStream(\"my-sample.xer\");\nMap<Integer, String> projects = reader.listProjects(is);\nSystem.out.println(\"ID\\tName\");\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(entry.getKey()+\"\\t\"+entry.getValue());\n}\n
The call to listProjects
returns a Map
whose key is the project ID, and the values are project short names.
Once you have decided which of these projects you want to work with, you can call setProjectID
to tell the reader which project to open, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setProjectID(123);\nProjectFile file = reader.read(\"my-sample.xer\");\n
Alternatively you can ask MPXJ to read all of the projects contained in the file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nInputStream is = new FileInputStream(\"my-sample.xer\");\nList<ProjectFile> files = reader.readAll(is);\n
The call to the readAll
method returns a list of ProjectFile
instances corresponding to the projects in the XER file.
"},{"location":"howto-read-xer/#link-cross-project-relations","title":"Link Cross-Project Relations","text":"
An XER file can contain multiple projects with relations between activities which span those projects. By default these cross-project relations are ignored. However, if you set the linkCrossProjectRelations
reader attribute to true
, MPXJ will attempt to link these relations across projects:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setLinkCrossProjectRelations(true);\nInputStream is = new FileInputStream(\"my-sample.xer\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-xer/#activity-wbs","title":"Activity WBS","text":"
In the original implementation of the XER file handling code, MPXJ would assign each task representing a Primavera Activity its own distinct WBS value. This does not match Primavera's behaviour where all of a WBS element's child activities will have the same WBS value as the parent WBS element. MPXJ's default behaviour now matches Primavera, but should you wish to you can revert to the original behaviour by calling the setMatchPrimaveraWBS
as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setMatchPrimaveraWBS(false);\nProjectFile file = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all of the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-xer/#reading-additional-attributes","title":"Reading Additional Attributes","text":"
A data-driven approach is used to extract the attributes used by MPXJ from the XER file. You can if you wish change the way attributes are read from the file, or add support for additional attributes. This assumes that you know the column name of the attributes you want to work with in the XER file. To make changes you will need to retrieve the maps which define which MPXJ attributes are used to store which columns from the XER file:
PrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nMap<FieldType, String> resourceFieldMap = reader.getResourceFieldMap();\nMap<FieldType, String> wbsFieldMap = reader.getWbsFieldMap();\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nMap<FieldType, String> assignmentFieldMap = reader.getAssignmentFieldMap();\n
These maps will contain the default mapping between columns and MPXJ attributes. You can modify these existing mappings, or add new ones, for example:
//\n// Change the field used to store rsrc_id\n//\nactivityFieldMap.remove(TaskField.NUMBER1);\nactivityFieldMap.put(TaskField.NUMBER2, \"rsrc_id\");\n\n//\n// Read an Activity column called an_example_field and store it in TEXT10\n//\nactivityFieldMap.put(TaskField.TEXT10, \"an_example_field\");\n
When reading new columns from the XER file, if these columns have a type other than String, it is important to register the type of the column to ensure that it is converted correctly. You will also need to ensure that the MPXJ attribute you are writing this new value to can receive the data type you are assigning to it (for example, you must store a date in a date attribute, you can't store a date in an integer attribute).
For example, if we are reading an integer column called an_example_id
and store it in the NUMBER2
attribute, we will need to take the following steps:
PrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nMap<String, XerFieldType> fieldTypeMap = reader.getFieldTypeMap();\nfieldTypeMap.put(\"an_example_id\", XerFieldType.INTEGER);\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nactivityFieldMap.put(TaskField.NUMBER2, \"an_example_id\");\n
"},{"location":"howto-start-java/","title":"Gettsing Started with Java","text":"
MPXJ is built to work with versions of Java from 1.8 onwards. For many people, the easiest way to get started with MPXJ and its dependencies is to use Maven. Just include the following in your POM to register MPXJ as a dependency of your project:
<dependency>\n <groupId>net.sf.mpxj</groupId>\n <artifactId>mpxj</artifactId>\n <version>10.11.0</version>\n</dependency>\n
The traditional method of downloading the MPXJ distribution as a zip file can also be used. Distributions can be found at GitHub and SourceForge.
The zip files contain all of the source, the MPXJ JAR file in the root of the zip file, with the libraries on which MPXJ depends being found in the lib
directory of the zip file. These libraries will need to be available on your classpath in order to use all of the MPXJ functionality. The script
directory in the zip file contains a batch file and a shell script which show how this can be done.
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start-python/","title":"Getting Started with Python","text":"
MPXJ is available as a Python Package, which can be installed using pip
:
pip install mpxj\n
You can find some documentation for the Package here. You'll need Java installed to make use of this package.
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start-ruby/","title":"Getting Started with Ruby","text":"
MPXJ is available as a RubyGem, which can be installed using gem
:
gem install mpxj\n
or included in you Gemfile
and installed using bundler
.
Note that the Ruby version of MPXJ is just a wrapper around the Java library, and provides read-only access to schedule data. You will need Java installed to make use of this Gem. You can find some documentation for the Gem [here] (https://rubygems.org/gems/mpxj)
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start/","title":"MPXJ Basics","text":"
The MPXJ library allows various formats of Microsoft Project file formats, and file formats from other project planning applications to be read and written using a single consistent API in Java, .Net, Python or any other related languages, and provides read-only access as a Ruby gem.
MPXJ is based around a \"neutral\" data structure which is used to represent project data, coupled with a set of format-specific reader and writer classes which understand how to read from and write to the various supported file formats.
The diagram below illustrates the key entities represented by the MPXJ data structure.
MPXJ currently allows project data to be read from a wide variety of schedule file formats and databases. You can find details of the individual file formats supported elsewhere in the documentation. By far the easiest way to read schedule data is to use the \"universal project reader\" which can determine for itself the type of file you have passed to it.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\n
A similar arrangement exists for the writer classes, although there is not a \"universal project writer\" as such:
net.sf.mpxj.mpx.MPXWriter
: writes Microsoft MPX filesnet.sf.mpxj.mspdi.MSPDIWriter
: writes Microsoft MSPDI (XML) filesnet.sf.mpxj.planner.PlannerWriter
: writes Planner (XML) filesnet.sf.mpxj.sdef.SDEFWriter
: writes SDEF filesnet.sf.mpxj.primavera.PrimaveraPMFileWriter
: writes Primavera PMXML (XML) filesnet.sf.mpxj.json.JsonWriter
: writes JSON files (primarily used to support the Ruby version of MPXJ)All of these classes implement the ProjectWriter interface. If you know which type of file you are working with, you can use these writers directly, for example:
ProjectWriter writer = new MPXWriter();\nwriter.write(project, \"example.mpx\");\n
"},{"location":"howto-start/#tasks-and-resources","title":"Tasks and Resources","text":"
Once you've read your project file, what next? The first things of interest are the tasks and resources which are present in the file.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\nfor (Resource resource : project.getAllResources())\n{\n System.out.println(\"Resource: \" + resource.getName()\n + \" (Unique ID=\" + resource.getUniqueID() + \")\");\n}\n
The code fragment above shows how we can retrieve a collection containing all of the resources present in the file, and iterate through them printing the resource name, ID and unique ID.
Many of the entities represented in MPXJ have some concept of a unique ID. Tasks and resources have two ID fields, the unique ID, which as its name suggests never changes and uniquely identifies a task or a resource, and the ID. The ID of a task or a resource is the sequential number which typically appears next to the task or resource when displayed in Microsoft Project. If the task or resource is moved up or down the list, this number will change depending on the position in the list. The unique ID never changes.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\nfor (Task task : project.getAllTasks())\n{\n System.out.println(\"Task: \" + task.getName() + \" ID=\" + task.getID()\n + \" Unique ID=\" + task.getUniqueID());\n}\n
The code fragment above retrieves all tasks present in the file and prints details of their names, IDs, and unique IDs.
Methods are provided on the project to locate both tasks and resource using either their ID or their Unique ID, as the examples below illustrate.
Resource r = project.getResourceByUniqueID(Integer.valueOf(99));\nTask t = project.getTaskByUniqueID(Integer.valueOf(99));\n
The methods shown above for retrieving all tasks present in a project file ignores the hierarchical task structure which Microsoft Project allows users to create. To understand the hierarchical task structure, the following methods are used to descend through the hierarchy, starting from the top.
List<Task> tasks = project.getChildTasks();\nTask task = tasks.get(0);\ntasks = task.getChildTasks();\n
These methods are used in the following code fragment to print out an indented list representing the task hierarchy in the file.
public void listHierarchy(ProjectFile file)\n{\n for (Task task : file.getChildTasks())\n {\n System.out.println(\"Task: \" + task.getName());\n listHierarchy(task, \" \");\n }\n\n System.out.println();\n}\n\nprivate void listHierarchy(Task task, String indent)\n{\n for (Task child : task.getChildTasks())\n {\n System.out.println(indent + \"Task: \" + child.getName());\n listHierarchy(child, indent + \" \");\n }\n}\n
As well as the hierarchical relationships between tasks, there is also a temporal relationship between them: this is typically used to indicate when a task can start in relation to the completion of an earlier task. The code fragment below shows the predecessor relationships between tasks.
for (Task task : file.getAllTasks())\n{\n List<Relation> predecessors = task.getPredecessors();\n if (predecessors != null && !predecessors.isEmpty())\n {\n System.out.println(task.getName() + \" predecessors:\");\n for (Relation relation : predecessors)\n {\n System.out.println(\" Task: \" + file.getTaskByUniqueID(relation.getTaskUniqueID()).getName());\n System.out.println(\" Type: \" + relation.getType());\n System.out.println(\" Lag: \" + relation.getDuration());\n }\n }\n}\n
"},{"location":"howto-start/#resource-assignments","title":"Resource Assignments","text":"
Tasks and resources are related by resource assignments. There is a method available on the ProjectFile class which will retrieve all resource assignments in the file. This is used by the code fragment below to provide an overview of all assignments.
for (ResourceAssignment assignment : file.getAllResourceAssignments())\n{\n Task task = assignment.getTask();\n String taskName;\n if (task == null)\n {\n taskName = \"(null task)\";\n }\n else\n {\n taskName = task.getName();\n }\n\n Resource resource = assignment.getResource();\n String resourceName;\n if (resource == null)\n {\n resourceName = \"(null resource)\";\n }\n else\n {\n resourceName = resource.getName();\n }\n\n System.out.println(\"Assignment: Task=\" + taskName + \" Resource=\" + resourceName);\n}\n
Resource assignments can also be retrieved on a task-by-task basis, as the code fragment below illustrates.
for (Task task : file.getAllTasks())\n{\n System.out.println(\"Assignments for task \" + task.getName() + \":\");\n\n for (ResourceAssignment assignment : task.getResourceAssignments())\n {\n Resource resource = assignment.getResource();\n String resourceName;\n\n if (resource == null)\n {\n resourceName = \"(null resource)\";\n }\n else\n {\n resourceName = resource.getName();\n }\n\n System.out.println(\" \" + resourceName);\n }\n}\n
Finally, resource assignments can be viewed on a resource-by-resource basis, as the following code fragment shows.
for (Resource resource : file.getAllResources())\n{\n System.out.println(\"Assignments for resource \" + resource.getName() + \":\");\n\n for (ResourceAssignment assignment : resource.getTaskAssignments())\n {\n Task task = assignment.getTask();\n System.out.println(\" \" + task.getName());\n }\n}\n
"},{"location":"howto-start/#calendars","title":"Calendars","text":"
Calendars are used to define working and non-working time, and are one of the more complex structures defined as part of a project. They are in turn used to define the time period over which a task is scheduled. There are two types of calendar: base calendars and resource calendars. Each base calendar provides a complete definition of the working and non working time for each day of the week. Resource calendars are associated with individual resources. Each resource calendar is derived from a base calendar; resource calendars may be unmodified in which case it will appear to be identical to the underlying base calendar, or the resource calendar may modify the working and non-working days. In this case these changes are \"overlaid\" on top of the working and non-working times defined by the base calendar. The calendars defined in a project can be retrieved using the method call shown below.
List<ProjectCalendar> calendars = file.getCalendars();\n
Normally a task without resource assignments will be scheduled with reference to the \"Standard\" (default) calendar defined as part of the project. This is retrieved using the method calls shown below.
ProjectCalendar defaultCalendar = file.getDefaultCalendar();\n
It is also possible to associate a specific calendar with an individual task. The method call below shows the calendar associated with a task being retrieved.
ProjectCalendar taskCalendar = task.getCalendar();\n
Bearing in mind that one calendar may be derived from another, care must be taken when choosing the methods called on a calendar instance: some methods are used to retrieve attributes defined as part of that specific calendar only, while others are used to descend through the hierarchy of calendars until an \"actual\" value is retrieved. For example the getDays method will retrieve an array of flags indicating the working/non-working/default state of each day of the week as defined by the current calendar. The getDay method however will test the current calendar to see if it is a working or non-working day. If the flag in the current calendar is set to \"default\", the method will use the base calendar from which the current calendar is derived to determine if the day is working or non-working.
As noted above a calendar contains a set of flags which represent each day of the week, these indicate the day of the week is working non-working, or \"default\". Where a day is set as \"default\", the working time for that day is taken from the underlying base calendar, if it is a resource calendar, or uses the default values provided by Microsoft Project if it is a base calendar.
If a particular day is defined as a working day, then the calendar will also contain a set of working hours for that day. The working hours for a day are defined by an instance of the ProjectCalendarHours class. This contains a collection of LocalTimeRange
instances which defined the start and end times of each working period during the day.
Alongside the flags which control whether a day is working or non-working, and the working hours for each day, each calendar defines a set of exceptions which are used to \"override\" the default working or non-working hours for individual days or entire date ranges. Methods are provided to allow a list of all exceptions defined by a calendar can be retrieved, or to retrieve the exception which covers an individual date. Calendar exceptions are represented by instances of the ProjectCalendarException class.
"},{"location":"howto-start/#timephased-data","title":"Timephased Data","text":"
Although resource assignments on their own describe which resources are assigned to which tasks, and how much work they are going to do, this does not necessarily tell us how much work a resource will be doing on any particular date. In order to find this information, you will need to consult the timephased resource assignment data.
Each resource assignment has a pair of methods allowing you to retrieve timephased data, as shown by the example code below.
List<TimephasedResourceAssignment> planned = assignment.getTimephasedPlanned();\nList<TimephasedResourceAssignment> complete = assignment.getTimephasedComplete();\n
Timephased resource assignment data is represented by instances of the TimephasedResourceAssignment class. This class is designed to provide a compact representation of the work carried out over ranges of days, rather than having to represent the work carried out on each individual day using a single class instance per day. Each TimephasedResourceAssignment defines four attributes: a start date, an end date, a total amount of work, and an amount of work per day.
For example, you may retrieve an instance of the TimephasedResourceAssignment class whose start and end date defines a five day period. The total work for the period is 40 hours, and the work per day is defined as 8 hours. This indicates that for the period in question, on each working day within the date range, 8 hours of work will be carried out. It is important to remember that non-working days are ignored, so for example if we have a 7 day period which spans a weekend, the total work could still be 40 hours, and the work per day 8 hours: only the 5 working days are allocated work, the non-working weekend days have zero hours of work performed.
The two lists defined above will contain multiple TimephasedResourceAssignment instances where different numbers of hours are worked on different days. Each contiguous range of dates where the same number of hours are worked in a day will be represented by one TimephasedResourceAssignment instance.
The two lists of timephased data represent completed (actual) work, and planned work respectively. These lists may overlap by a single day if they are being used to show a partially completed day's work. For example, during a normal 8 hour working day, if 4 hours of work has been completed, and 4 hours remains, then the list of completed timephased data will end with 4 hours of work which have been completed, and the planned work list will start with the 4 hours remaining on the same day.
"},{"location":"howto-use-calendars/","title":"How To: Use Calendars","text":"
Calendars are the foundation on which schedules are built. They determine when work can be carried out, and when work is not possible. Given some tasks we need to plan, and knowing how much work each task will require, a calendar can be used to decide when work on each task could start and how much elapsed time will be required to complete the tasks.
"},{"location":"howto-use-calendars/#calendars-in-mpxj","title":"Calendars in MPXJ","text":"
Let's see how calendars work in MPXJ. First let's try creating one. As it happens, the ProjectFile
class provides a convenience method addDefaultBaseCalendar
to create a default calendar. The calendar it creates is modelled on the Standard
calendar you'd see in Microsoft Project if you created a new project. This default calendar defines Monday to Friday as working days, with 8 working hours each day (8am to noon, then 1pm to 5pm).
ProjectFile file = new ProjectFile();\nProjectCalendar calendar = file.addDefaultBaseCalendar();\nSystem.out.println(\"The calendar name is \" + calendar.getName());\n
As you can see from the code above, the calendar also has a name which we can set to distinguish between different calendars.
"},{"location":"howto-use-calendars/#working-days","title":"Working Days","text":"
Let's see what the calendar can tell us. First we'll use the DayOfWeek
enumeration to retrieve the working/non-working state for each day.
for (DayOfWeek day : DayOfWeek.values()) {\n String dayType = calendar.getCalendarDayType(day).toString();\n System.out.println(day + \" is a \" + dayType + \" day\");\n}\n
Running the code shown above will produce output like this:
MONDAY is a WORKING day\nTUESDAY is a WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a NON_WORKING day\nSUNDAY is a NON_WORKING day\n
We can use the setWorkingDay
method to change our pattern of working day. Let's make Saturday a working day for our team, and make Monday a non-working day to compensate.
calendar.setWorkingDay(DayOfWeek.SATURDAY, true);\ncalendar.setWorkingDay(DayOfWeek.MONDAY, false);\n
Now if we use the loop we saw previously to inspect the week days, we'll see this output:
MONDAY is a NON_WORKING day\nTUESDAY is a WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a WORKING day\nSUNDAY is a NON_WORKING day\n
"},{"location":"howto-use-calendars/#working-hours","title":"Working Hours","text":"
So far, all we have done is set a flag which tells us whether a day is working or non-working. How do we know the working times on those days? We can use the getCalendarHours
method to find that information.
The getCalendarHours
method returns a List
of LocalTimeRange
instances. LocalTimeRange
is a simple immutable class which represents a span of time between a start time and an end time as an inclusive range. Let's try printing these LocalTimeRange
instances to our output to see what we get:
List<LocalTimeRange> hours = calendar.getCalendarHours(Day.TUESDAY);\nhours.forEach(System.out::println);\n
Here's the output:
[LocalTimeRange start=08:00 end=12:00]\n[LocalTimeRange start=13:00 end=17:00]\n
Let's add a method to format the hours of a day a little more concisely for display:
private String formatLocalTimeRanges(List<LocalTimeRange> hours) {\n return hours.stream()\n .map(h -> h.getStart() + \"-\" + h.getEnd())\n .collect(Collectors.joining(\", \"));\n}\n
So now our output looks like this:
08:00-12:00, 13:00-17:00\n
Let's use this method to take a look at the whole week again:
for (Day day : Day.values()) {\n String dayType = calendar.getCalendarDayType(day).toString();\n System.out.println(day\n + \" is a \" + dayType + \" day (\"\n + formatLocalTimeRanges(calendar.getCalendarHours(day)) + \")\");\n}\n
Here's the output:
MONDAY is a NON_WORKING day ()\nTUESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nWEDNESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nTHURSDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nFRIDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSATURDAY is a WORKING day ()\nSUNDAY is a NON_WORKING day ()\n
The one thing we're missing now is that although we have set Saturday to be a working day, it doesn't have any working hours. MPXJ has some constants which can be used to help us add some working hours:
hours = calendar.getCalendarHours(Day.SATURDAY);\nhours.add(ProjectCalendarDays.DEFAULT_WORKING_MORNING);\nhours.add(ProjectCalendarDays.DEFAULT_WORKING_AFTERNOON);\n
Now when we examine our week this is what we see:
MONDAY is a NON_WORKING day ()\nTUESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nWEDNESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nTHURSDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nFRIDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSATURDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSUNDAY is a NON_WORKING day ()\n
The version of MPXJ at the time of writing (12.0.0) has a limitation that if setCalendarDayType
is used to make a day into a working day, we don't automatically add working hours for it. This behaviour is likely to change with the next major version of MPXJ.
What if we want to supply some working hours different from the defaults we've used so far? To set our own working hours we just need to create as many LocalTimeRange
instances as we need using a pair of LocalTime
instances for each one to represent the start and end times.
LocalTime startTime = LocalTime.of(9, 0);\nLocalTime finishTime = LocalTime.of(14, 30);\nhours = calendar.getCalendarHours(DayOfWeek.SATURDAY);\nhours.clear();\nhours.add(new LocalTimeRange(startTime, finishTime));\n
Now when we look at the working hours for Saturday, this is what we see:
SATURDAY is a WORKING day (09:00-14:30)\n
Now we've seen how we can create our own ranges of working time for a day, let's tackle a slightly more challenging case: dealing with midnight. Our first step is to take a look at the actual amount of working time we've set up on Saturday. To do this we call the getWork
method, as shown below.
Duration duration = calendar.getWork(Day.SATURDAY, TimeUnit.HOURS);\nSystem.out.println(duration);\n
This getWork
method determines the total amount of work on the given day, and returns this in the format we specify. In this case we've asked for hours, and we'll be receiving the result as a Duration
object. Duration
simply combines the duration amount with an instance of the TimeUnit
enumeration so we always know the units of the duration amount.
Running the code above give us this output:
5.5h\n
As you can see, the toString
method of Duration
give us a nicely formatted result, complete with an abbreviation for the units.
Let's try to change Saturday to be 24 hour working. First we'll configure a midnight to midnight date range:
startTime = LocalTime.MIDNIGHT;\nfinishTime = LocalTime.MIDNIGHT;\nhours.clear();\nhours.add(new LocalTimeRange(startTime, finishTime));\nSystem.out.println(formatLocalTimeRanges(calendar.getCalendarHours(DayOfWeek.SATURDAY)));\n
This looks reasonable:
00:00-00:00\n
Now let's see how much work this represents:
duration = calendar.getWork(DayOfWeek.SATURDAY, TimeUnit.HOURS);\nSystem.out.println(duration);\n
24.0h\n
So we have our 24 hours of work on Saturday!
"},{"location":"howto-use-calendars/#exceptions","title":"Exceptions","text":"
After working a few of these 24 hour days on Saturdays, we might be in need of a vacation! How can we add this to our calendar?
So far we've been working with the DayOfWeek
class to make changes to days of the week, rather than any specific date. Now we'll need to work with a specific date, and add an \"exception\" for this date. The terminology here can be slightly confusing when coming from a programming background, but the term exception is often used by scheduling applications in the context of making ad-hoc adjustments to a calendar.
LocalDate exceptionDate = LocalDate.of(2022, 5, 10);\n\nboolean workingDate = calendar.isWorkingDate(exceptionDate);\nSystem.out.println(exceptionDate + \" is a \"\n + (workingDate ? \"working\" : \"non-working\") + \" day\");\n
In the code above we're creating a LocalDate
instance to represent the date we want to add an exception for. The code uses the isWorkingDate
method to determine whether or not the given date is a working day. Before we add the exception, here's the output we get:
2022-05-10 is a working day\n
Now we can create our exception.
ProjectCalendarException exception = calendar.addCalendarException(exceptionDate);\nexception.setName(\"A day off\");\n
The code above illustrates adding an exception for a single day. The code above also shows that optionally an exception can be named, this can make it easier to understand the purpose of each exception. Now if we re-run our code which displays whether our chosen date is a working day, this is what we see:
2022-05-10 is a non-working day\n
We have successfully added an exception to turn this date into a day off!
Perhaps we were being a little too generous in giving ourselves the entire day off, perhaps in this case we should make this a half day instead. To do that, we just need to add a time range to the exception:
startTime = LocalTime.of(8, 0);\nfinishTime = LocalTime.of(12, 0);\nexception.add(new LocalTimeRange(startTime, finishTime));\n
Now if we look at our chosen date, this is what we see:
2022-05-10 is a working day\n
Let's take a closer look at what's happening on that day:
System.out.println(\"Working time on Tuesdays is normally \"\n + calendar.getWork(DayOfWeek.TUESDAY, TimeUnit.HOURS) + \" but on \"\n + exceptionDate + \" it is \"\n + calendar.getWork(exceptionDate, TimeUnit.HOURS));\n
The code above shows how we use the getWork
method which takes a DayOfWeek
as an argument to look at what the default working hours are on a Tuesday, then we use the getWork
method which takes a LocalDate
instance as an argument to see what's happening on the specific Tuesday of our exception. Here's the output we get:
Working time on Tuesdays is normally 8.0h but on 2022-05-10 it is 4.0h\n
We can see the effect of adding a LocalTimeRange
to our exception: we've gone from an exception which changes a working day into a non-working day to an exception which just changes the number of working hours in the day. This same approach can be used to change a date which falls on a day that's typically non-working (for example a Sunday) into a working day, just by adding an exception with some working hours.
We can also use a single exception to affect a number of days. First let's write a little code to see the number of working hours over a range of days:
private void dateDump(ProjectCalendar calendar, LocalDate startDate, LocalDate endDate)\n{\n for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1)) {\n System.out.println(date + \"\\t\" + calendar.getWork(date, TimeUnit.HOURS));\n }\n}\n
Running this code with our calendar as its stands produces this output for the example week we're using:
2022-05-23 0.0h\n2022-05-24 8.0h\n2022-05-25 8.0h\n2022-05-26 8.0h\n2022-05-27 8.0h\n
Let's add an exception which covers Tuesday to Thursday that week (24th to 26th), and changes the working hours, so there are now only four hours of work per day (9am to 12pm):
LocalDate exceptionStartDate = LocalDate.of(2022, 5, 24);\nLocalDate exceptionEndDate = LocalDate.of(2022, 5, 26);\nexception = calendar.addCalendarException(exceptionStartDate, exceptionEndDate);\nstartTime = LocalTime.of(9, 0);\nfinishTime = LocalTime.of(13, 0);\nexception.add(new LocalTimeRange(startTime, finishTime));\n
Here we can see that we're using a different version of the addCalendarException
method which takes a start and an end date, rather that just a single date. Running our code again to print out the working hours for each day now gives us this output:
2022-05-23 0.0h\n2022-05-24 4.0h\n2022-05-25 4.0h\n2022-05-26 4.0h\n2022-05-27 8.0h\n
As we can see, we've changed multiple days with this single exception.
"},{"location":"howto-use-calendars/#working-weeks","title":"Working Weeks","text":"
So far we've looked at using ProjectCalendarException
, which can make one change (add working hours, change working hours, or make days non-working) and apply that change to one day or a contiguous range of days. What if we want to make more complex changes to the working pattern of a calendar?
Let's imagine that our project has a three week \"crunch\" period at the beginning of October where we will need to work 16 hour days, Monday through Friday, and 8 hour days at weekends. (I hope this is a fictional example and you'd don't have to work at such a high intensity in real life!). We could construct this work pattern using exceptions: we'd need six in total, one for each of the three sets of weekend days, and one for each of the three sets of week days.
An alternative way to do this is to set up a new working week, using the ProjectCalendarWeek
class. \"Working Week\" is perhaps a slightly misleading name, as a ProjectCalendarWeek
can be set up for an arbitrary range of dates, from a few days to many weeks. What it represents is the pattern of working an non-working time over the seven days of a week, and this pattern is applied from the start to the end of the date range we configure.
The ProjectCalendar
we've been working with so far is actually already a form of working week (they share a common parent class). The main differences between the two are that a ProjectCalendarWeek
allows us to specify the range of dates over which it is effective, and a ProjectCalendarWeek
does not have exceptions: exceptions are only added to a ProjectCalendar
.
For a fresh start, we'll create a new ProjectCalendar
instance. With this we'll add a new working week definition and give it a name, to make it easily identifiable. Now we'll set the dates for which this work pattern is valid (in this case the first three weeks of October). Finally we mark every day as a working day. Here's how our example looks in code:
LocalDate weekStart = LocalDate.of(2022, 10, 1);\nLocalDate weekEnd = LocalDate.of(2022, 10, 21);\ncalendar = file.addDefaultBaseCalendar();\nProjectCalendarWeek week = calendar.addWorkWeek();\nweek.setName(\"Crunch Time!\");\nweek.setDateRange(new LocalDateRange(weekStart, weekEnd));\nArrays.stream(DayOfWeek.values()).forEach(d -> week.setWorkingDay(d, true));\n
Next we can set up our weekend 9am to 5pm working pattern:
startTime = LocalTime.of(9, 0);\nfinishTime = LocalTime.of(17, 0);\nLocalTimeRange weekendHours = new LocalTimeRange(startTime, finishTime);\nArrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)\n .stream().forEach(d -> week.addCalendarHours(d).add(weekendHours));\n
Finally we can set up our weekday 5am to 9pm pattern:
startTime = LocalTime.of(5, 0);\nfinishTime = LocalTime.of(21, 0);\nLocalTimeRange weekdayHours = new LocalTimeRange(startTime, finishTime);\nArrays.asList(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY,\n DayOfWeek.THURSDAY, DayOfWeek.FRIDAY)\n .stream().forEach(d -> week.addCalendarHours(d).add(weekdayHours));\n
As ProjectCalendar
and ProjectCalendarWeek
are both derived from the same parent class, we can use the same code we did previously to examine how our new ProjectCalendarWeek
instance looks:
MONDAY is a WORKING day (05:00-21:00)\nTUESDAY is a WORKING day (05:00-21:00)\nWEDNESDAY is a WORKING day (05:00-21:00)\nTHURSDAY is a WORKING day (05:00-21:00)\nFRIDAY is a WORKING day (05:00-21:00)\nSATURDAY is a WORKING day (09:00-17:00)\nSUNDAY is a WORKING day (09:00-17:00)\n
To see the effect that our new working week has had on the calendar, let's first take a look at the week running up to the start of our crunch period. Using the same code we worked with previously to present working hours for a range of dates we see this output:
2022-09-24 0.0h\n2022-09-25 0.0h\n2022-09-26 8.0h\n2022-09-27 8.0h\n2022-09-28 8.0h\n2022-09-29 8.0h\n2022-09-30 8.0h\n
So starting from Saturday 24th we can see that we have that standard working pattern: weekends are non-working (zero working hours), and week days have 8 hours of working time.
Now let's look at the first week of our crunch period:
2022-10-01 8.0h\n2022-10-02 8.0h\n2022-10-03 16.0h\n2022-10-04 16.0h\n2022-10-05 16.0h\n2022-10-06 16.0h\n2022-10-07 16.0h\n
We can see that the crunch is in full effect, we're working 8 hour days at the weekend, and 16 hour days for the rest of the week - not something I'd like to try for any length of time!
To summarise: the ProjectCalendar
instance itself defines the default working and non-working pattern for the seven week days. Additional working weeks can be added to the calendar which override this pattern for specific date ranges.
"},{"location":"howto-use-calendars/#recurring-exceptions","title":"Recurring Exceptions","text":"
So far we've seen how exceptions can be used to override the default working pattern established by a calendar for either a single day, or for a contiguous range of days. We've also seen how an entirely new seven-day working pattern can be applied across a range of dates by using working weeks. But what if we want to represent a regularly occurring exception which will change our default working pattern such as, for example, Christmas Day or Thanksgiving? To deal with this we can use recurring exceptions.
A recurring exception can be created simply by passing an instance of RecurringData
to the addCalendarException
method.
RecurringData recurringData = new RecurringData();\nexception = calendar.addCalendarException(recurringData);\n
Let's create a simple recurence for 1st January for five years:
recurringData.setRecurrenceType(RecurrenceType.YEARLY);\nrecurringData.setOccurrences(5);\nrecurringData.setDayNumber(Integer.valueOf(1));\nrecurringData.setMonthNumber(Integer.valueOf(1));\nrecurringData.setStartDate(LocalDate.of(2023, 1, 1));\nSystem.out.println(recurringData);\n
The toString
method on the RecurringData
class tries to describe the recurrence as best it can, here's the output we'll see from the code above:
[RecurringData Yearly on the 1 January From 2023-01-01 For 5 occurrences]\n
The example above shows a very simple configuration. Full details of how to use RecurringData
are provided elsewhere as they are beyond the scope of this section.
Before we move on from recurring exceptions, one useful feature of the ProjectCalendarException
class is the getExpandedExceptions
method. This will convert a recurring exception into a list of individual exceptions representing each date or range of dates the recurring exception will affect the calendar. You may find this useful if you need to display or pass this data on for consumption elsewhere.
"},{"location":"howto-use-calendars/#calendar-hierarchies","title":"Calendar Hierarchies","text":"
Now we've seen how to set up an individual calendar, perhaps we could go ahead and create calendars for all of the people who will be working on our project? What we'd quickly find is that a considerable amount of the information in each calendar will be the same: the same working week pattern, the same public holidays and so on. We could set all of this up programmatically of course, but wouldn't it be great if we could change this kind of detail in just one place, and have all of our other calendars inherit it?
"},{"location":"howto-use-calendars/#creating-a-calendar-hierarchy","title":"Creating a Calendar Hierarchy","text":"
As it happens, we can do this as our calendars can be organised into a hierarchy, with each \"child\" calendar inheriting its configuration from a \"parent\" calendar and overriding that configuration as required rather like a class hierarchy in a programing language). This will allow us to have one shared \"base\" calendar for everyone, with derived calendars used for individuals on our team where we need to add variation, for example personal vacation time and so on.
ProjectFile file = new ProjectFile();\nProjectCalendar parentCalendar = file.addDefaultBaseCalendar();\nLocalDate christmasDay = LocalDate.of(2023, 12, 25);\nparentCalendar.addCalendarException(christmasDay);\n
In the example above we've used the familiar addDefaultBaseCalendar
method to create a simple calendar, and called addCalendarException
to add an exception for Christmas Day 2023.
ProjectCalendar childCalendar = file.addDefaultDerivedCalendar();\nchildCalendar.setParent(parentCalendar);\nSystem.out.println(christmasDay + \" is a working day: \"\n + childCalendar.isWorkingDate(christmasDay));\n
Now we've created childCalendar
, using a method we've not seen before, addDefaultBaseCalendar
(we'll talk about this method in more detail in a minute), and we've used the new calendar's setParent
method to attach parentCalendar
as its parent. We can see the effect of this when we check to see if Christmas Day 2023 is a working day. This is a Monday so by default it will be a working day, but as childCalendar
is inheriting from parentCalendar
it picks up the exception defined in parentCalendar
and makes Christmas Day a non-working day.
Here's the output when our code is executed:
2023-12-25 is a working day: false\n
We can also do the same thing with day types:
parentCalendar.setCalendarDayType(DayOfWeek.TUESDAY, DayType.NON_WORKING);\nSystem.out.println(\"Is \" + DayOfWeek.TUESDAY + \" a working day: \" \n + childCalendar.isWorkingDay(DayOfWeek.TUESDAY));\n
In the example above we've set Tuesday to be a non-working day in the parent calendar, and we can see that this is inherited by the child calendar. Here's the output we see when we execute our code:
Is TUESDAY a working day: false\n
So what's special about the \"derived calendar\" we've just created (childCalendar
), why is it different to the normal calendar, and what's the difference between the addDefaultBaseCalendar
and addDefaultDerivedCalendar
methods?
The answer to this question lies in the DayType
enumeration. Let's take a look at the day types for parentCalendar
.
SUNDAY is a NON_WORKING day\nMONDAY is a WORKING day\nTUESDAY is a NON_WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a NON_WORKING day\n
So far so good, we have a mixture of working an non-working days, and we can see that as part of our last example we set Tuesday to be a non-working day. Now let's take a look at childCalendar
:
SUNDAY is a DEFAULT day\nMONDAY is a DEFAULT day\nTUESDAY is a DEFAULT day\nWEDNESDAY is a DEFAULT day\nTHURSDAY is a DEFAULT day\nFRIDAY is a DEFAULT day\nSATURDAY is a DEFAULT day\n
Ah-ha! Here we can see that the DayType
enumeration actually has a third value alongside WORKING
and NON_WORKING
: DEFAULT
. The DEFAULT
value simply means that we should inherit the parent calendar's settings for this particular day: so whether the day is working, non-working, what the working hours are, and so on.
We can override the day type we're inheriting from the base calendar:
childCalendar.setCalendarDayType(DayOfWeek.TUESDAY, DayType.WORKING);\nLocalTime startTime = LocalTime.of(9, 0);\nLocalTime finishTime = LocalTime.of(12, 30);\nchildCalendar.addCalendarHours(DayOfWeek.TUESDAY).add(new LocalTimeRange(startTime, finishTime));\n
In the code above we're explicitly setting Tuesday to be a working day, rather than inheriting the settings for Tuesday from the parent calendar, then we're adding the working hours we want for Tuesday.
Earlier we said we come back and look at the addDefaultDerivedCalendar
method in a little more detail. The main difference between addDefaultDerivedCalendar
and addDefaultBaseCalendar
is that the calendar created by addDefaultDerivedCalendar
has no working hours defined, and all day types are set to DEFAULT
so everything is inherited from the parent calendar.
"},{"location":"howto-use-calendars/#working-with-a-calendar-hierarchy","title":"Working with a Calendar Hierarchy","text":"
In general when working with a calendar hierarchy, if we use a calendar to determine working/non-working time, working hours, and so on for a given date, anything configured in a child calendar will always override what we find in the parent calendar. So for example if we have exceptions or working weeks configured in a child calendar, these will override anything found in a parent calendar.
If we're asking the calendar a question about a particular day (rather than a date), for example Monday, Tuesday and so on, we'll use information from the child calendar if the day type is WORKING
or NON_WORKING
, otherwise we'll work our way up the calendar hierarchy until we find the first ancestor calendar which does not specify the day type as DEFAULT
, and we'll use the configuration for the day in question from that calendar.
This brings us on to an interesting question: how do we know if we ask the calendar for a piece of information, whether that's come from the calendar whose method we've just called, or if the response we've received has come from another calendar somewhere further up the calendar hierarchy?
As it happens there are only a small number of attributes for which this is relevant. These are summarised by the table below.
Attribute Set Get Get with Hierarchy Day Type setCalendarDayType
getCalendarDayType
getDayType
Hours addCalendarHours
getCalendarHours
getHours
Minutes Per Day setCalendarMinutesPerDay
getCalendarMinutesPerDay
getMinutesPerDay
Minutes Per Week setCalendarMinutesPerWeek
getCalendarMinutesPerWeek
getMinutesPerWeek
Minutes Per Month setCalendarMinutesPerMonth
getCalendarMinutesPerMonth
getMinutesPerWeek
Minutes Per Year setCalendarMinutesPerYear
getCalendarMinutesPerYear
getMinutesPerYear
The first column give us the name of the attribute, and the second column give the name of the method we'd call to set that attribute for the current calendar. The third column gives us the name of the method we'd use to retrieve the attribute from the current calendar only (i.e this will ignore any parent calendars). Finally the last column gives us the name of the method we'd call to retrieve the attribute from the current calendar, or inherit that attribute from a parent calendar if it is not present in the current calendar.
We haven't looked at the Minutes Per X attributes so far. The values they contain are used when calculating working time. One interesting point to note is that if no calendars in a hierarchy define these values the default values will be retrieved from from the ProjectFile
configuration, which is represented by the ProjectConfig
class.
"},{"location":"howto-use-calendars/#how-deep-is-your-hierarchy","title":"How deep is your Hierarchy?","text":"
MPXJ will allow you to create an arbitrarily deep hierarchy of calendars if you wish by establishing parent-child relationships between the calendars you create. Most schedule application file formats will only support a limited hierarchy of calendars, which you will see when you read files of this type when using MPXJ. The notes below briefly outlines how calendar hierarchies operate in some of the applications MPXJ can work with.
If you are using MPXJ to create or modify schedule data, when you write the results to a file MPXJ will attempt to ensure that the calendars it writes to the file format you have chosen reflect what the target application is expecting. This means that MPXJ may end up \"flattening\" or otherwise simplifying a set of calendars and their hierarchy to ensure that they are read correctly by the target application and are \"functionally equivalent\" in use.
"},{"location":"howto-use-calendars/#microsoft-project","title":"Microsoft Project","text":"
Microsoft Project uses two tiers of calendars. The first tier of calendars are referred to as \"base calendars\", one of which is marked as the default calendar for the project. Work is scheduled based on the default calendar, unless a task explicitly selects a different base calendar to use when being scheduled, or resources with their own calendars have been assigned to the task. Each resource will have its own calendar, which is always derived from a base calendar.
Note that, as you might expect, material resources don't have a calendar!
"},{"location":"howto-use-calendars/#primavera-p6","title":"Primavera P6","text":"
The situation with P6 is a little more complicated, although it's still a two tier arrangement. P6 has the concept of Global calendars (broadly similar to base calendars in Microsoft Project). These can be assigned to activities in any project. Global calendars are never derived from other calendars.
You can also have Project calendars which, as their name suggests, can only be assigned to activities in the project to which they belong. Project calendars can be derived from a Global Calendar, or they can have no parent calendar.
Finally you can have two types of resource calendar: Shared, or Personal. These can either be derived from a Global calendar, or can have no parent. A Shared resource calendar can be assigned to multiple resources, but a Personal resource calendar can only be assigned to a single resource.
When reading a P6 schedule, the ProjectCalendar
method getType
can be used to retrieve the calendar type (Global, Shared, or Personal), while the getPersonal
method returns a Boolean flag indicating if the calendar is a Personal resource calendar.
"},{"location":"howto-use-calendars/#others","title":"Others","text":"
ConceptDraw, Planner, SureTrak and TurboProject all support some form of calendar hierarchy, although Planner is the only one which definitely supports an arbitrarily deep nested calendar structure.
"},{"location":"howto-use-calendars/#calendar-container","title":"Calendar Container","text":"
So far we've looked at creating and configuring calendars, and lining them together in a hierarchy. If we've just read a schedule in from a file, how can we examine the calendars it contains? Let's set up some calendars and take a look:
ProjectFile file = new ProjectFile();\nProjectCalendar calendar1 = file.addCalendar();\ncalendar1.setName(\"Calendar 1\");\n\nProjectCalendar calendar2 = file.addCalendar();\ncalendar2.setName(\"Calendar 2\");\n\nProjectCalendar calendar3 = file.addCalendar();\ncalendar2.setName(\"Calendar 3\");\n
Our sample code above creates three calendars, each with a distinct name. To see what calendars our file contains we can use the ProjectFile
method getCalendars
:
file.getCalendars().forEach(c -> System.out.println(c.getName()));\n
Which gives us the following output, as we'd expect:
Calendar 1\nCalendar 2\nCalendar 3\n
The getCalendars
method returns an object which implements the List<ProjectCalendar>
interface, but it also does more for us than just that. The actual object being returned is a ProjectCalendarContainer
, which is in charge of managing the calendars in the file and making it easy to access them.
The typical way this is done is through the use of the calendar's Unique ID attribute. Each calendar has an Integer
Unique ID, typically this is read as part of the calendar information from a schedule file, or if you are creating a schedule yourself, the default is for the Unique ID to be automatically populated. Let's see:
file.getCalendars().forEach(c -> System.out.println(c.getName() \n + \" (Unique ID: \" + c.getUniqueID() + \")\"));\n
Here's what we get:
Calendar 1 (Unique ID: 1)\nCalendar 2 (Unique ID: 2)\nCalendar 3 (Unique ID: 3)\n
Let's use a Unique ID to retrieve a calendar:
ProjectCalendar calendar = file.getCalendars().getByUniqueID(2);\nSystem.out.println(calendar.getName());\n
Here's the result of running this code:
Calendar 2\n
The ProjectCalendarContainer
class also allows us to retrieve calendars by name, although that's not recommended as MPXJ doesn't enforce presence or uniqueness constraints on calendar names.
Most of the time accessing a calendar from some other part of MPXJ is handled for you, for example to retrieve a resource's calendar you just need to call the Resource
method getCalendar
rather than having to use ProjectCalendarContainer
to retrieve it by Unique ID.
"},{"location":"howto-use-calendars/#calendar-relationships","title":"Calendar Relationships","text":"
The ProjectCalendar
class provides a variety of methods to allow us to explore how it relates to other calendars and the rest of the schedule.
As we've been discussing the hierarchy of calendars, the first method we can try is isDerived
, which will return true
if this calendar has been derived from a parent calendar. Alongside this we can also use the getParent
method to retrieve this calendar's parent. We can traverse a hierarchy of calendars using this method until getParent
returns null
at which point we know we have reached a \"base\" calendar and can go no further.
Calendars can also be assigned to both Tasks and Resources. The getTasks
and getResources
methods will each retrieve a list of the tasks and resources which explicitly use this calendar.
Finally, earlier in this section we mentioned the idea of the default calendar for a project. We can set or retrieve the default calendar using the ProjectFile
methods setDefaultCalendar
and getDefaultCalendar
, as illustrated below.
ProjectFile file = new ProjectFile();\nProjectCalendar calendar = file.addDefaultBaseCalendar();\nfile.setDefaultCalendar(calendar);\nSystem.out.println(\"The default calendar name is \"\n + file.getDefaultCalendar().getName());\n
As the name suggests, the default calendar will be used for all date, time, duration and work calculations if no other calendar has been assigned explicitly.
"},{"location":"howto-use-external-projects/","title":"How To: Use External Projects","text":"
From a schedule in Microsoft Project you can work with data from other project files in three ways: Subprojects, External Predecessors, and Resource Pools.
"},{"location":"howto-use-external-projects/#subprojects","title":"Subprojects","text":"
Microsoft Project allows you to manage larger projects by breaking them down into Subprojects. From one MPP file, a link can be added to another MPP file forming a parent-child relationship. The child MPP file will appear as a summary task in the location you've selected within the parent file. When this summary task is expanded the tasks from the child MPP file will appear seamlessly as tasks in the parent file.
"},{"location":"howto-use-external-projects/#identifying-subproject-tasks","title":"Identifying Subproject Tasks","text":"
If you use MPXJ to read an MPP file that contains a Subproject, initially you won't see anything different to a file which just contains ordinary tasks: the Subproject will just appear as a normal summary task whose attributes will roll up the details from the Subproject. If you want you can just work with the task as-is, you only need to so something different if you want to work with the contents of the Subproject.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.Task;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n...\n\nProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfor (Task task : file.getTasks())\n{\n if (task.getExternalProject())\n {\n System.out.println(task.getName() + \" is a subproject\");\n System.out.println(\"Path to the file is: \" +\n task.getSubprojectFile());\n System.out.println(\"GUID of this project is: \" +\n task.getSubprojectGUID());\n System.out.println(\"Offset used when displaying Unique ID values is: \" +\n task.getSubprojectTasksUniqueIDOffset());\n }\n}\n
The example above illustrates how we can identify a Subproject by using a task's External Project attribute. Once we have identified that we have a Subproject we can determine where the file is located, using the Subproject File attribute, and the GUID of this project, using the Subproject GUID attribute.
The last attribute we're looking at in this example is the Subproject Tasks Unique ID Offset. When Microsoft Project provides a combined view of two or more MPP files using Subprojects, one issue is that the Unique ID values in each project will no longer be unique. To get around this problem Microsoft Project adds an offset to the Unique ID values of the tasks it displays from each Subproject to ensure that each one has a distinct value. This offset is the value we're retrieving using the getSubprojectTasksUniqueIDOffset
method.
"},{"location":"howto-use-external-projects/#reading-subproject-data","title":"Reading Subproject Data","text":"
If you wish, you can use UniversalProjectReader
directly to load the external project, as the example below illustrates:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nString filePath = externalProjectTask.getSubprojectFile();\nProjectFile externalProjectFile = new UniversalProjectReader().read(filePath);\n
The code above assumes that the file is located on a readable filesystem at the exact path specified by the Subproject File attribute.
Note that these examples assume that the file is on a filesystem which is directly readable. For MPP files exported from Project Server, it is likely that the path to an external project will be in the form <>\\FileName
which represents a project hosted by Project Server. MPXJ cannot open this type of external project.
An alternative to writing your own code to do this would be to use the method provided by MPXJ, as illustrated below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nProjectFile externalProjectFile = externalProjectTask.getSubprojectObject();\n
The advantage of this approach, apart from using less code, is that MPXJ will attempt to find the file in locations other than the full path provided in Subproject File. By default the other place MPXJ will look is in the working directory of the current process, however this behaviour can be configured as the example below illustrates:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfile.getProjectConfig().setSubprojectWorkingDirectory(new File(\"/path/to/dir\"));\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nProjectFile externalProjectFile = externalProjectTask.getSubprojectObject();\n
In the code above we're calling the setSubprojectWorkingDirectory
method to give MPXJ details of a directory to look in when attempting to read an external project.
Note that if MPXJ can't load the external project for any reason, the getSubprojectObject
method will return null
.
"},{"location":"howto-use-external-projects/#expanding-subproject-data","title":"Expanding Subproject Data","text":"
In Microsoft Project, when a Subproject task is expanded it behaves just like any other summary task by revealing the child tasks it contains. We can reproduce this behavior using the code shown in the sample below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nSystem.out.println(\"Has child tasks? \" + externalProjectTask.hasChildTasks());\nexternalProjectTask.expandSubproject();\nSystem.out.println(\"Has child tasks? \" + externalProjectTask.hasChildTasks());\n
The expandSubproject
method attempts to open the external project, and if successful attaches the tasks from the external project as children of the external project task. You are then able to access the tasks from the parent project along with the tasks from the external project as part of the same MPXJ ProjectFile instance.
Note that when using the expandSubproject
method, the setSubprojectWorkingDirectory
method on ProjectConfig
can be used to tell MPXJ where to find the external projects in the same way we did when using the getSubprojectObject
method.
You can also do this globally and expand all Subproject tasks in a project by using the expandSubprojects
method on the project file itself:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfile.expandSubprojects(false);\n
Remember that all the \"expand subproject\" functionality described in the notes above is doing is attaching the tasks from one ProjectFile
instance as child tasks of a task in another ProjectFile
instance. This will allow you to recursively descend through the tasks in a project and any subprojects. However, these tasks still belong to separate ProjectFile
instances, so calling the getTasks()
method on the top level ProjectFile
instance will only return the tasks from that project, and will not include tasks from any subprojects.
"},{"location":"howto-use-external-projects/#external-predecessors","title":"External Predecessors","text":"
The second way an external project can be referenced in a Microsoft Project schedule is through the use of an external predecessor task. Project allows you to enter the task ID for a predecessor in the form myproject.mpp\\123
which selects the task with ID 123
in myproject.mpp
as the predecessor of the task in the schedule you are working on.
When you use an external predecessor task like this, Project includes a \"placeholder\" task in your current schedule which represents the task in the external project and has a copy of all of the relevant attributes of the task from the external project. In many cases this placeholder task is all you need to work with the schedule.
When you are working with MPXJ, how can you identify that you are looking at a placeholder task representing an external predecessor? The sample code below illustrates this:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfor (Task task : file.getTasks())\n{\n if (task.getExternalTask())\n {\n System.out.println(task.getName() + \" is an external predecessor\");\n System.out.println(\"The path to the file containing this task is: \"\n + task.getSubprojectFile());\n System.out.println(\"The ID of the task in this file is: \"\n + task.getSubprojectTaskID());\n System.out.println(\"The Unique ID of the task in this file is: \"\n + task.getSubprojectTaskUniqueID());\n }\n}\n
As the code above illustrates, if the getExternalTask
method return true, the task is an external predecessor. As illustrated by the code there are three relevant attributes: Subproject File (the location of the external project this predecessor belongs to), and the Subproject Task ID and Subproject Task Unique ID which are the ID and Unique ID of the task in the schedule it comes from.
As with a task representing an external project, you can retrieve the project for an external predecessor task using the getSubprojectObject
method. Note however that the expandSubproject
method will have no effect as the external predecessor task does not represent an entire project!
"},{"location":"howto-use-external-projects/#predecessors-and-successors-from-subprojects","title":"Predecessors and Successors from Subprojects","text":"
As we saw in a previous section, when working with Microsoft Project you can configure a project with a number of subprojects. When this is the case you can also create predecessor or successor relationships between tasks in any of these projects. When you open your MPP file in Microsoft Project, and all of the subprojects can also be opened, then Microsoft Project will present you with a unified view of the tasks and their relationships, even though the relationships cross different files. However, if you open your project but do not have the subproject files available, you will see placeholder external tasks representing the predecessor or successor tasks from the missing subproject files.
When reading the file using MPXJ, you will encounter the same situation: opening your MPP file without any of the subprojects being available you will see placeholder external tasks for predecessor and successor tasks from the subproject files. As we have already seen, the expandSubprojects
method can be used to expand all subprojects, if the files they represent are available, allowing you to traverse the hierarchy of tasks. The expandSubprojects
method also offers some additional functionality: when you pass true
to this method, MPXJ will attempt to replace any predecessor or successor relationships which include placeholder external tasks with relationships which refer to the original task from a subproject, and those placeholder external tasks will be removed from the project entirely. This functionality is intended to replicate what you would see if you opened your file in Microsoft Project and all subprojects were successfully loaded.
As noted previously, the expandSubprojects
method is only stitching together a set of individual ProjectFile
instances so the tasks they contain can be traversed seamlessly, and in this case the predecessor and successor relationships between those tasks no longer use placeholder external tasks. This is still not a single unified ProjectFile
instance so care should be taken when working with this data to bear in mind that it comes from a number of separate files.
"},{"location":"howto-use-external-projects/#resource-pools","title":"Resource Pools","text":"
The final way an external project can be used from a Microsoft Project schedule is as a resource pool. A resource pool schedule allows you to capture details of all of your organisation's resources in one place, then refer to them from multiple schedules. Setting up a resource pool like this should ensure that your resource utilisation across different projects is accurately captured as the utilisation detail in the resource pool is updated by the projects using those resources.
The full path for a project's resource pool can be retrieved using the getResourcePoolFile
method as illustrated below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nString path = file.getProjectProperties().getResourcePoolFile();\n
In a similar manner to the other external project examples given in previous sections, MPXJ can also open and read the resource pool file for you:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nProjectFile resourcePool = file.getProjectProperties().getResourcePoolObject();\n
"},{"location":"howto-use-external-projects/#mspdi-files","title":"MSPDI Files","text":"
Much of the detail noted above is also applicable to MSPDI files, but with the following exceptions:
getSubprojectObject
method on the task, or you can call the expandSubproject
or expandSubprojects
methods documented in the previous sections to show the tasks contained in the Subproject as part of the main project.Note that although Microsoft Project will write external predecessor information to an MSPDI file, it will fail to load these correctly when the MSPDI file is reopened.
"},{"location":"howto-use-fields/","title":"How To: Use Fields","text":"
Once you've read a schedule using MPXJ, and you have a ProjectFile
instance with tasks, resources and resource assignments, how do you access the data represented as fields in each of these entities? If you're creating or updating a schedule, how can you assign values to fields? This section explains the different approaches you can take in each of these cases.
"},{"location":"howto-use-fields/#setter-and-getter-methods","title":"Setter and Getter Methods","text":"
Let's start by creating a task we can use to demonstrate some of these approaches:
ProjectFile file = new ProjectFile();\nTask task = file.addTask();\n
When you already know exactly which field you need to access, you can work with the data these fields contain in a type-safe way by using the setter and getter methods provided by each class, for example:
task.setName(\"Task 1\");\n\nString name = task.getName();\nSystem.out.println(\"Task name: \" + name);\n
Here's the output from the sample code:
Task name: Task 1\n
Here we can see that we are able to set the name of the task using a String
, and when we call the getter method we'll be returned the name as a String
. How about working with a field that has a type other than a String?
LocalDateTime startDate = LocalDateTime.of(2022, 5, 10, 8, 0);\ntask.setStart(startDate);\n\nSystem.out.println(\"Start date: \" + task.getStart());\n
Here's the output from the sample code:
Start date: 2022-05-10T08:00\n
We're setting and retrieving the task's start date using a LocalDateTime
instance. For almost all of the fields supported by tasks, resources, and resource assignments you'll find a pair of getter and setter methods allowing you to access and modify the field with a convenient type safe interface.
"},{"location":"howto-use-fields/#field-enumerations","title":"Field Enumerations","text":"
What if we don't know ahead of time which fields we need to access? For example, what if our application allows users to choose which fields to display for each task? In this case we can use a data-driven approach to read and write fields, as shown in the example below.
task = file.addTask();\ntask.set(TaskField.NAME, \"Task 2\");\n\nname = (String)task.get(TaskField.NAME);\nSystem.out.println(\"Task name: \" + name);\n\nstartDate = LocalDateTime.of(2022, 5, 11, 8, 0);\ntask.set(TaskField.START, startDate);\n\nSystem.out.println(\"Start date: \" + task.getStart());\n
Here's the output from this sample code:
Task name: Task 2\nStart date: 2022-05-11T08:00\n
What are the TaskField
values in the example above? TaskField
is an enumeration representing all of the fields of a Task
instance. This type of enumeration is not unique to tasks, there are four main enumerations available:
ProjectField
: fields available from ProjectProperties
ResourceField
: fields available from a Resource
TaskField
: fields available from a Task
AssignmentField
: fields available from a ResourceAssignment
The ProjectProperties
, Resource
, Task
and ResourceAssignment
classes noted above actually all implement the FieldContainer
interface. This is the interface that gives us the get
and set
methods we've seen in the examples above. FieldContainer
also provides us with one more interesting method: getCachedValue
. What is this, and why is it different to the get
method? Let's take a step back and look at calculated values to understand where getCachedValue
fits in.
"},{"location":"howto-use-fields/#calculated-fields","title":"Calculated Fields","text":"
Some of the fields available from each of these classes can actually contain a calculated value. For example: the Task
field \"Start Variance\" represents the difference between the Baseline Start date and the Start date of a task. Some schedules may provide this value for us when we read the data they contain, others may not. If we don't have this value when we read our schedule data, but we do have a Baseline Start and Start date available to us, then we can perform the calculation ourselves to produce the Start Variance value. The example below illustrates this:
// Set up the sample project\nProjectFile file = new ProjectFile();\n\n// We need at least a default calendar to calculate variance\nfile.setDefaultCalendar(file.addDefaultBaseCalendar());\n\n// Create tasks\nTask task1 = file.addTask();\nTask task2 = file.addTask();\n\n// Set up example dates\nLocalDateTime baselineStart = LocalDateTime.of(2022, 5, 1, 8, 0);\nLocalDateTime startDate = LocalDateTime.of(2022,5, 10, 8, 0);\n\n// Update task1 using methods\ntask1.setStart(startDate);\ntask1.setBaselineStart(baselineStart);\n\n// Update task2 using TaskField enumeration\ntask2.set(TaskField.START, startDate);\ntask2.set(TaskField.BASELINE_START, baselineStart);\n\n// Show the variance being retrieved by method and TaskField enumeration\nSystem.out.println(\"Task 1\");\nSystem.out.println(\"Start Variance from method: \"\n + task1.getStartVariance());\nSystem.out.println(\"Start Variance from get: \"\n + task1.get(TaskField.START_VARIANCE));\nSystem.out.println();\n\nSystem.out.println(\"Task 2\");\nSystem.out.println(\"Start Variance from method: \"\n + task2.getStartVariance());\nSystem.out.println(\"Start Variance from get: \"\n + task2.get(TaskField.START_VARIANCE));\n
Here's the output from running this code:
Task 1\nStart Variance from method: 6.0d\nStart Variance from get: 6.0d\n\nTask 2\nStart Variance from method: 6.0d\nStart Variance from get: 6.0d\n
Regardless of how we set up the data, both the getStartVariance
method and the call to get(TaskField.START_VARIANCE)
trigger the calculation and produce the expected Start Variance value.
Rather than immediately discarding the Start Variance value we've just calculated, this value is cached as part of the data held by the task, and will be returned next time we use the getStartVariance
method or we call get(TaskField.START_VARIANCE)
.
"},{"location":"howto-use-fields/#cached-values","title":"Cached Values","text":"
The getCachedValue
method allows us to retrieve a field without attempting to calculate a value. It's not a method you'd normally expect to use, but it's worth mentioning for completeness. Let's take a look at this using a new example:
// Set up the sample project with a default calendar\nProjectFile file = new ProjectFile();\nfile.setDefaultCalendar(file.addDefaultBaseCalendar());\n\n// Set up example dates\nLocalDateTime baselineStart = LocalDateTime.of(2022, 5, 1, 8, 0);\nLocalDateTime startDate = LocalDateTime.of(2022,5, 10, 8, 0);\n\n// Create a task\nTask task = file.addTask();\ntask.setStart(startDate);\ntask.setBaselineStart(baselineStart);\n\nSystem.out.println(\"Start Variance using getCachedValue(): \" \n + task.getCachedValue(TaskField.START_VARIANCE));\nSystem.out.println(\"Start Variance using get(): \" \n + task.get(TaskField.START_VARIANCE));\nSystem.out.println(\"Start Variance using getCachedValue(): \" \n + task.getCachedValue(TaskField.START_VARIANCE));\n
The output from this code is:
Start Variance using getCachedValue(): null\nStart Variance using get(): 6.0d\nStart Variance using getCachedValue(): 6.0d\n
What we can see happening here is that using the getCachedValue
method initially returns null
as the Start Variance is not present, and MPXJ doesn't attempt to calculate it. When we use the get
method, MPXJ sees that it doesn't have a value for this field and knows how to calculate it, and returns the expected result. Finally if we use the getCachedValue
method again, as we've now calculated this value and cached it, the method returns the Start Variance.
In summary, getCachedValue
will never attempt to calculate values for fields which are not already present. This can be useful if you want to read a schedule using MPXJ, but retrieve only the fields which were in the original schedule, not calculated or inferred by MPXJ.
"},{"location":"howto-use-fields/#fieldtype","title":"FieldType","text":"
Earlier in this section we noted that there were four main enumerations representing the fields which particular classes can contain.
ProjectField
ResourceField
TaskField
AssignmentField
What I didn't mention then is that each of these enumerations implements the FieldType
interface which defines a common set of methods for each of these enumerations. The most interesting of these methods are:
name()
getName()
getFieldTypeClass()
getDataType()
The name()
method retrieves the name of the enumeration value exactly as it appears in the code. The getName()
method returns a localized version of the name, suitable for display to end users (currently English is the default and only supported locale).
The getFieldTypeClass()
method returns a value from the FieldTypeClass
enumeration which will help you to determine which kind of object this FieldType
belongs to (for example task, resource, and so on). Finally the getDataType()
method will return a value from the DataType
enumeration which indicates the data type you will receive from the get
method when accessing this field, and the type to pass to the set
method when updating the field.
Here's some example code to make this a little clearer:
FieldType type = TaskField.START_VARIANCE;\n\nSystem.out.println(\"name(): \" + type.name());\nSystem.out.println(\"getName(): \" + type.getName());\nSystem.out.println(\"getFieldTypeClass(): \" + type.getFieldTypeClass());\nSystem.out.println(\"getDataType():\" + type.getDataType());\n
In this case we're using the Task Start Variance field as an example. Here's the output:
name(): START_VARIANCE\ngetName(): Start Variance\ngetFieldTypeClass(): TASK\ngetDataType(): DURATION\n
Returning to our earlier example of how we might allow a user to select fields we will display, we can use the data type of the selected field to determine how we format the value for display.
private String getValueAsText(FieldContainer container, FieldType type)\n{\n Object value = container.get(type);\n if (value == null)\n {\n return \"\";\n }\n\n String result;\n switch (type.getDataType())\n {\n case CURRENCY:\n {\n result = new DecimalFormat(\"\u00a30.00\").format(value);\n break;\n }\n\n case DATE:\n {\n result = DateTimeFormatter.ofPattern(\"dd/MM/yyyy\").format((LocalDateTime)value);\n break;\n }\n\n case BOOLEAN:\n {\n result = ((Boolean)value).booleanValue() ? \"Yes\" : \"No\";\n break;\n }\n\n default:\n {\n result = value.toString();\n break;\n }\n }\n\n return result;\n}\n
The sample code above implements a generic method which can work with any class implementing the FieldContainer
interface (for example, Task
, Resource
and so on). Given the particular field the user has asked us to display (passed in via the type
argument), we retrieve the value from the container as an Object
, then use the data type to decide how best to format the value for display. (This is obviously a contrived example - I wouldn't recommend creating new instances of DecimalFormat
and DateTimeFormatter
each time you need to format a value!)
"},{"location":"howto-use-fields/#custom-fields","title":"Custom Fields","text":"
So far we've seen how simple fields like Name and Start can be accessed and modified using both field-specific and generic methods. Name and Start are examples of standard fields which might be provided and managed by schedule applications, and have a well understood meaning. What if we have some additional data we want to capture in our schedule, but that data doesn't fit into any of these standard fields?
Microsoft Project's solution to this problem is Custom Fields. By default Microsoft Project provides a number of general purpose fields with names like \"Text 1\", \"Text 2\", \"Date 1\", \"Date 2\" and so on, which can be used to relevant vales as part of the schedule. If we look for methods like setText1
or setDate1
we won't find them, so how can we work with these fields?
The answer is quite straightforward, for each of these custom fields you'll find getter and setter methods which take an integer value, for example:
task.setText(1, \"This is Text 1\");\nString text1 = task.getText(1);\nSystem.out.println(\"Text 1 is: \" + text1);\n
If you're working with the generic get
and set
methods, the situation is more straightforward as each individual field has its own enumeration, as shown below:
task.set(TaskField.TEXT1, \"This is also Text 1\");\ntext1 = (String)task.get(TaskField.TEXT1);\nSystem.out.println(\"Text 1 is: \" + text1);\n
For Task
, Resource
and ResourceAssignment
the following custom fields are available for use:
Task
and Resource
only)Microsoft Project allows users to configure custom fields. This facility can be used to do something as simple as provide an alias for the field, allowing it to be displayed with a meaningful name rather than something like \"Text 1\" or \"Date 1\". Alternatively there are more complex configurations available, for example constraining the values that can be entered for a field by using a lookup table, or providing a mask to enforce a particular format.
Information about custom field configurations can be obtained from the CustomFieldsContainer
. The sample code below provides a simple illustration of how we can query this data.
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nCustomFieldContainer container = file.getCustomFields();\nfor (CustomField field : container)\n{\n FieldType type = field.getFieldType();\n String typeClass = type.getFieldTypeClass().toString();\n String typeName = type.name();\n String alias = field.getAlias();\n System.out.println(typeClass + \".\" + typeName + \"\\t\" + alias);\n}\n
Depending on how the custom fields in your schedule are configured, you'll see output like this:
TASK.TEXT1 Change Request Reason\nTASK.NUMBER1 Number of Widgets Required\nRESOURCE.DATE1 Significant Date\n
In the source above, the first thing we're retrieving from each CustomField
instance is the FieldType
, which identifies the field we're configuring. The values we retrieve here will be from one of the enumerations we've touched on previously in this section, for example TaskField
, ResourceField
and so on.
The next thing we're doing in our sample code is to create a representation of the parent type to which this field belongs, followed by the name of the field itself (this is what's providing us with the value TASK.TEXT1
for example). Finally we're displaying the alias which has been set by the user for this field.
It's important to note that for schedules from Microsoft Project, there won't necessarily be a CustomField
entry for all of the custom fields in use in a schedule. For example, if a user has added values to the \"Text 1\" field for each of the tasks in their schedule, but have not configured Text 1 in some way (for example by setting an alias or adding a lookup table) there won't be an entry for \"Text 1\" in the CustomFieldContainer
.
As well as iterating through the collection of CustomField
instances for the current schedule, you can directly request the CustomField
instance for a specific field, as shown below:
CustomField fieldConfiguration = container.get(TaskField.TEXT1);\n
One common use-case for the configuration data help in CustomFieldContainer
is to locate particular information you are expecting to find in the schedule. For example, let's say that you know that the schedule you're reading should have a field on each task which users have named \"Number of Widgets Required\", and you want to read that data. You can determine which field you need by using a method call similar to the one shown below:
FieldType fieldType = container.getFieldTypeByAlias(\n FieldTypeClass.TASK,\n \"Number of Widgets Required\");\n
Note that the first argument we need to pass identifies which parent entity we're expecting to find the field in. The CustomFieldContainer
will have entries from all field containers (tasks, resources, resource assignments and so on) so this is used to locate the correct one - particularly useful if, for example, a task and a resource might both have a field with the same alias! Remember: this method will return null
if we don't have a field with the alias you've provided.
Once we have the FieldType
of the field we're looking for, we can use this to retrieve the value using the get
method as we've seen earlier in this section:
Task task = file.getTaskByID(Integer.valueOf(1));\nObject value = task.get(fieldType);\n
Finally, there are a couple of convenience methods to make retrieving a field by its alias easier. The first is that each \"container\" class for the various entities also provides a getFieldTypeByAlias
method. If you know ahead of time you're looking for a field in a particular entity, this will simplify your code somewhat. The example below illustrates this: as we're looking for a task field we can go straight to the TaskContainer
and ask for the field with the alias we're looking for:
fieldType = file.getTasks().getFieldTypeByAlias(\"Number of Widgets Required\");\n
Lastly, you can actually retrieve the value of a field directly from the parent entity using its alias, as shown below:
value = task.getFieldByAlias(\"Number of Widgets Required\");\n
This is not recommended where you are iterating across multiple tasks to retrieve values: it's more efficient to look up the FieldType
once before you start, then use that to retrieve the value you are interested in from each task.
"},{"location":"howto-use-fields/#populated-fields","title":"Populated Fields","text":"
So far we've touched on how to can read and write fields in examples where we are targeting specific fields. If we're reading a schedule whose contents are unknown to us, how can we tell which fields are actually populated? A typical use-case for this might be where we need to read a schedule, then present the user with the ability to select the columns they'd like to see in a tabular display of the schedule contents. If you look at the various enumerations we have mentioned previously in this section (TaskField
, ResourceField
and so on) you can see that there are a large number of possible fields a user could choose from, so ideally we only want to show a user fields which actually contain non-default values.
To solve this problem we need to use the appropriate getPopulatedFields
method for each of the entities we're interested in.
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nSet<ProjectField> projectFields = file.getProjectProperties().getPopulatedFields();\nSet<TaskField> taskFields = file.getTasks().getPopulatedFields();\nSet<ResourceField> resourceFields = file.getResources().getPopulatedFields();\nSet<AssignmentField> assignmentFields = file.getResourceAssignments().getPopulatedFields();\n
In the example above we're opening a sample file, then for each of the main classes which implement the FieldContainer
interface, we'll query the container which holds those classes and call its getPopulatedFields
method. In each case this will return a Set
containing the enumeration values representing fields which have non-default values.
If you need to you can retrieve all of this information in one go:
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nSet<ProjectField> allFields = file.getPopulatedFields();\n
The set returned by the project's getPopulatedFields
will contain all the populated fields from all entities which implement the FieldContainer
interface. You'll need to remember to look at the FieldTypeClass
value of each field in the resulting set to determine which entity the field belongs to. The following section provides more detail on this.
"},{"location":"howto-use-fields/#user-defined-fields","title":"User Defined Fields","text":"
In an earlier section we touched briefly on how Microsoft Project uses a fixed set of \"custom fields\" to allow you to store arbitrary data as part of the schedule. A more common approach in other applications is to allow you to create your own fields to represent the data you need to store - that way you can have exactly the fields you need, without needing to worry if you can fit your data into the fixed set of custom fields. In fact Microsoft Project also supports this concept, in the form of Enterprise Custom Fields, although these are only available if you are working with a schedule hosted in Project Server (Project 365).
As you can imagine MPXJ can't provide dedicated getter and setter methods for these fields as it doesn't know ahead of time what they are - they're user defined! Instead we rely on the get
and set
methods to work with these fields.
When a schedule is read by MPXJ, each user defined field is represented internally by an instance of the UserDefinedField
class. This class implements the FieldType
interface, and so can be used with the get
and set
methods to read and write these values.
You can see which user defined fields exist in a project using code similar to the example below:
for (UserDefinedField field : project.getUserDefinedFields())\n{\n System.out.println(\"name(): \" + field.name());\n System.out.println(\"getName(): \" + field.getName());\n System.out.println(\"getFieldTypeClass(): \" + field.getFieldTypeClass());\n System.out.println(\"getDataType():\" + field.getDataType()); \n}\n
As well as using the getUserDefinedFields
method on the project to see which fields are defined, the getPopulatedFields
methods discussed in an earlier section will also return UserDefinedField
instances if these fields have values in the schedule. Information about UserDefinedField
instances is also available in the CustomFieldContainer
. This means that when you read a schedule and you are expecting certain user defined fields to be present, you can use the getFieldTypeByAlias
or getFieldByAlias
methods to find the fields you are interested in by name, as described in an earlier section.
If you import schedules data from an application which supports user defined fields and export to a Microsoft Project file format (MPX or MSPDI), MPXJ will automatically map any user defined fields to unused custom fields. Note that as there are only a finite number of custom field available, it is possible that not all user defined fields will be available when the resulting file is opened in Microsoft Project.
"},{"location":"howto-use-universal/","title":"How To: Use the Universal Project Reader","text":"
As you may have seen elsewhere in this documentation, the preferred way to read from most sources of schedule data is to use the UniversalProjectReader
:
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\n
This is very convenient as you don't need to know ahead of time what type of schedule file you are working with, UniversalProjectReader
will figure this out for you. The drawback to this approach is that for a number of schedule types, the reader class for that type may provide additional configuration options to guide the way schedule data is read. In the example above, you can see that there is no opportunity to provide any extra configuration to the reader class selected by UniversalProjectReader
.
To get around this issue, UniversalProjectReader
provides access to \"project reader proxy\" classes. These proxy classes implement the UniversalProjectReader.ProjectReaderProxy
interface and provide access to the reader class which UniversalProjectReader
has selected to read the project data at the point just before schedule data has been read.
You can use these proxy classes to, for example, choose whether or not to continue reading the type of schedule contained in the supplied file or stream, or you can change the reader's settings before continuing to read the schedule. The example code below illustrates both these situations.
UniversalProjectReader upr = new UniversalProjectReader();\n\n// Retrieve the proxy\ntry (UniversalProjectReader.ProjectReaderProxy proxy = upr.getProjectReaderProxy(file))\n{\n // Retrieve the reader class\n ProjectReader reader = proxy.getProjectReader();\n\n // Determine if we want to continue processing this file type.\n // In this example we are ignoring SDEF files.\n if (reader instanceof SDEFReader)\n { \n return;\n }\n\n // Provide configuration for specific reader types.\n // In this example we are changing the behavior of the Phoenix reader.\n if (reader instanceof PhoenixReader)\n {\n ((PhoenixReader)reader).setUseActivityCodesForTaskHierarchy(false);\n }\n\n // Finally, we read the schedule\n ProjectFile project = proxy.read();\n\n // Now we can work with the schedule data...\n}\n
The first thing to notice is that the proxy class is being used within a \"try with resources\" statement. This is important as the UniversalProjectReader
may have a number of resources open (streams, temporary files, and so on) which need to be released once you have finished with the proxy class. UniversalProjectReader.ProjectReaderProxy
implements the AutoCloseable
interface, so you can either arrange to explicitly call the close
method yourself at an appropriate point, or you can use try with resources to ensure this happens automatically.
The initial line of the try
statement calls getProjectReaderProxy
to retrieve the proxy. This method can be called with either a file name, a File
instance, or an InputStream
. Within the try
block, the first thing we do is retrieve the reader class instance which the UniversalProjectReader
has selected to read our schedule data.
The next two stanzas of code use instanceof
to determine the type of the reader selected: in the first stanza we're choosing not to continue if we've been provided with an SDEF file. In the second stanza, if we are dealing with a Phoenix schedule, we're choosing to change the default behavior of the reader.
Finally at the end of the try
block we're calling the read
method of the proxy to read the schedule. The proxy also provides a readAll
method: if the source data contains multiple schedules you can use this method to read them all.
Note that we're using the read
or readAll
methods provided by the proxy class, we're not attempting to use the methods provided on the reader class itself. This is important as the UniversalProjectReader
may have located the schedule within a larger set of data, for example within a Zip file or sub-directory. The proxy class already has this context, whereas you won't necessarily have this information if you tried to use the reader class methods directly.
"},{"location":"howto-write-mpx/","title":"How To: Write MPX files","text":"
Versions of Microsoft Project up to Project 98 could read and write MPX files as a data interchange format. Versions of Project after Project 98 until Project 2010 can only read MPX files. Versions of Microsoft Project after 2010 cannot read MPX files. Other third party project planning applications continue to use MPX as a data interchange format.
The sample code below illustrates how to write data to an MPX file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXWriter;\n\n// ...\n\nMPXWriter writer = new MPXWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/","title":"How To: Write MSPDI files","text":"
Since Microsoft Project 2002, Microsoft Project has been able to read and write an XML-based data interchange format called MSPDI.
"},{"location":"howto-write-mspdi/#writing-mspdi-files","title":"Writing MSPDI files","text":"
The sample code below illustrates how to write data to an MSPDI file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#using-mspdiwriter","title":"Using MSPDIWriter","text":""},{"location":"howto-write-mspdi/#microsoft-project-compatible-output","title":"Microsoft Project Compatible Output","text":"
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
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setMicrosoftProjectCompatibleOutput(false);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#save-version","title":"Save Version","text":"
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\nProject2003\nProject2007\nProject2010\nProject2013\nProject2016\n
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;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\nimport net.sf.mpxj.mspdi.SaveVersion;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setSaveVersion(SaveVersion.Project2002);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#timephased-data","title":"Timephased Data","text":"
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:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setWriteTimephasedData(true);\nwriter.write(projectFile, outputFileName);\n
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;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setWriteTimephasedData(true);\nwriter.setSplitTimephasedAsDays(false);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-planner/","title":"How To: Write Planner files","text":"
Gnome Planner is a simple cross platform planning tool. MPXJ can be used to write a schedule as a Planner file, which the Gnome Planner application can open.
The sample code below illustrates how to write data to a Planner file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.planner.PlannerWriter;\n\n// ...\n\nPlannerWriter writer = new PlannerWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-pmxml/","title":"How To: Write PMXML files","text":"
The XML file format supported by Primavera P6 for import and export is known as PMXML.
The sample code below illustrates how to write data to a PMXML file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileWriter;\n\n// ...\n\nPrimaveraPMFileWriter writer = new PrimaveraPMFileWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-pmxml/#using-primaverapmfilewriter","title":"Using PrimaveraPMFileWriter","text":""},{"location":"howto-write-pmxml/#baselines","title":"Baselines","text":"
By default baselines are not written to PMXML files. If the ProjectFile
instance you are writing contains a baseline, this can be included in the PMXML file by calling the setWriteBaselines
method as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileWriter;\n\n// ...\n\nPrimaveraPMFileWriter writer = new PrimaveraPMFileWriter();\nwriter.setWriteBaselines(true);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-sdef/","title":"How To: Write SDEF files","text":"
SDEF is the Standard Data Exchange Format, as defined by the USACE (United States Army Corps of Engineers). SDEF is a fixed column format text file, used to import a project schedule up into the QCS (Quality Control System) software from USACE. The specification for the file format can be found here.
The sample code below illustrates how to write data to an SDEF file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFWriter;\n\n// ...\n\nSDEFWriter writer = new SDEFWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-sdef/#using-sdefwriter","title":"Using SDEFWriter","text":""},{"location":"howto-write-sdef/#charset","title":"Charset","text":"
By default SDEF files are written using the US_ASCII
charset. The setCharset
method on the SDEFWriter
class can be used to change this if required:
import java.nio.charset.StandardCharsets;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFWriter;\n\n// ...\n\nSDEFWriter writer = new SDEFWriter();\nwriter.setCharset(StandardCharsets.UTF_8);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-xer/","title":"How To: Write XER files","text":"
XER files have been imported and exported by Primavera software since the earliest days of P6 and this format is still often the preferred way to move schedule data between instances of P6 even today.
The sample code below illustrates how to write data to an XER file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileWriter;\n\n// ...\n\nPrimaveraXERFileWriter writer = new PrimaveraXERFileWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-xer/#using-primaveraxerfilewriter","title":"Using PrimaveraXERFileWriter","text":""},{"location":"howto-write-xer/#encoding","title":"Encoding","text":"
By default XER files written by MPXJ are encoded using the Windows-1252 character set. If you need to use a different encoding, the setCharset
or setEncoding
methods can be used to achieve this, as illustrated by the code below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileWriter;\n\n// ...\n\nPrimaveraXERFileWriter writer = new PrimaveraXERFileWriter();\n\n// Use a Charset instance\nwriter.setCharset(Charset.forName(\"GB2312\"));\nwriter.write(projectFile, outputFileName);\n\n// Use an encoding name\nwriter.setEncoding(\"GB2312\");\nwriter.write(projectFile, outputFileName);\n
"},{"location":"maven-reports/","title":"Maven Reports","text":"
Reports generated from the Maven project, including Javadocs, can be found here.
"},{"location":"mpp-field-guide/","title":"MPP Field Guide","text":""},{"location":"mpp-field-guide/#mpp-field-guide","title":"MPP Field Guide","text":"
The tables below provide an indication of which fields are populated when different MPP file versions are read using MPXJ The tables are not hand-crafted: they have been generated from test data and are therefore may be missing some details.
"},{"location":"mpp-field-guide/#project","title":"Project","text":""},{"location":"mpp-field-guide/#core-fields","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 AM Text \u2713 \u2713 \u2713 \u2713 Activity ID Increment \u2713 \u2713 \u2713 \u2713 Activity ID Increment Based On Selected Activity \u2713 \u2713 \u2713 \u2713 Activity ID Prefix \u2713 \u2713 \u2713 \u2713 Activity ID Suffix \u2713 \u2713 \u2713 \u2713 Application Version \u2713 \u2713 \u2713 \u2713 Author \u2713 \u2713 \u2713 \u2713 Auto Add New Resources and Tasks \u2713 \u2713 \u2713 \u2713 Auto Filter \u2713 \u2713 Auto Link \u2713 \u2713 \u2713 \u2713 Bar Text Date Format \u2713 \u2713 \u2713 \u2713 Calculate Float on Finish Date of Each Project \u2713 \u2713 \u2713 \u2713 Calculate Multiple Paths Using Total Float \u2713 \u2713 \u2713 \u2713 Category \u2713 \u2713 \u2713 \u2713 Comments \u2713 \u2713 \u2713 \u2713 Company \u2713 \u2713 \u2713 \u2713 Compute Start to Start Lag From Early Start \u2713 \u2713 \u2713 \u2713 Consider Assignments In Other Project With Priority Equal or Higher Than \u2713 \u2713 \u2713 \u2713 Content Status \u2713 \u2713 \u2713 Content Type \u2713 \u2713 \u2713 Creation Date \u2713 \u2713 \u2713 \u2713 Critical Activity Type \u2713 \u2713 \u2713 \u2713 Critical Slack Limit \u2713 \u2713 Currency Code \u2713 \u2713 \u2713 Currency Digits \u2713 \u2713 \u2713 \u2713 Currency Symbol \u2713 \u2713 \u2713 \u2713 Currency Symbol Position \u2713 \u2713 \u2713 \u2713 Current Date \u2713 \u2713 \u2713 \u2713 Custom Properties \u2713 \u2713 \u2713 \u2713 Date Format \u2713 \u2713 \u2713 \u2713 Date Order \u2713 \u2713 \u2713 \u2713 Date Separator \u2713 \u2713 \u2713 \u2713 Days per Month \u2713 \u2713 \u2713 \u2713 Decimal Separator \u2713 \u2713 \u2713 \u2713 Default Calendar Unique ID \u2713 \u2713 \u2713 \u2713 Default End Time \u2713 \u2713 \u2713 \u2713 Default Overtime Rate \u2713 \u2713 \u2713 Default Standard Rate \u2713 \u2713 \u2713 Default Start Time \u2713 \u2713 \u2713 \u2713 Default Work Units \u2713 \u2713 \u2713 \u2713 Document Version \u2713 \u2713 \u2713 Editable Actual Costs \u2713 \u2713 Editing Time \u2713 \u2713 \u2713 \u2713 File Application \u2713 \u2713 \u2713 \u2713 File Type \u2713 \u2713 \u2713 \u2713 Finish Date \u2713 \u2713 \u2713 \u2713 Fiscal Year Start \u2713 \u2713 \u2713 \u2713 Fiscal Year Start Month \u2713 \u2713 \u2713 \u2713 Full Application Name \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 Honor Constraints \u2713 \u2713 \u2713 \u2713 Hyperlink Base \u2713 \u2713 \u2713 \u2713 Keywords \u2713 \u2713 \u2713 \u2713 Language \u2713 \u2713 \u2713 Last Author \u2713 \u2713 \u2713 \u2713 Last Printed \u2713 \u2713 \u2713 \u2713 Last Saved \u2713 \u2713 \u2713 \u2713 Level All Resources \u2713 \u2713 \u2713 \u2713 Leveling Priorities \u2713 \u2713 \u2713 \u2713 Limit Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 MPP File Type \u2713 \u2713 \u2713 \u2713 MPX Code Page \u2713 \u2713 \u2713 \u2713 MPX Delimiter \u2713 \u2713 \u2713 \u2713 MPX File Version \u2713 \u2713 \u2713 \u2713 MPX Program Name \u2713 \u2713 \u2713 \u2713 Manager \u2713 \u2713 \u2713 \u2713 Maximum Percentage to Overallocate Resources \u2713 \u2713 \u2713 \u2713 Microsoft Project Server URL \u2713 \u2713 \u2713 \u2713 Minutes per Day \u2713 \u2713 \u2713 \u2713 Minutes per Month \u2713 \u2713 \u2713 \u2713 Minutes per Week \u2713 \u2713 \u2713 \u2713 Minutes per Year \u2713 \u2713 \u2713 \u2713 Multiple Critical Paths \u2713 \u2713 \u2713 New Task Start Is Project Start \u2713 \u2713 \u2713 \u2713 New Tasks Are Manual \u2713 \u2713 \u2713 New Tasks Estimated \u2713 \u2713 \u2713 \u2713 Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 PM Text \u2713 \u2713 \u2713 \u2713 Presentation Format \u2713 \u2713 \u2713 Preserve Minimum Float When Leveling \u2713 \u2713 \u2713 \u2713 Preserve Scheduled Early and Late Dates \u2713 \u2713 \u2713 \u2713 Project File Path \u2713 \u2713 \u2713 Project Title \u2713 \u2713 \u2713 \u2713 Relationship Lag Calendar \u2713 \u2713 \u2713 \u2713 Resource Pool File \u2713 \u2713 \u2713 Revision \u2713 \u2713 \u2713 \u2713 Schedule From \u2713 \u2713 \u2713 \u2713 Short Application Name \u2713 \u2713 \u2713 \u2713 Show Project Summary Task \u2713 \u2713 \u2713 \u2713 Split In Progress Tasks \u2713 \u2713 \u2713 \u2713 Start Date \u2713 \u2713 \u2713 \u2713 Status Date \u2713 \u2713 \u2713 Subject \u2713 \u2713 \u2713 \u2713 Template \u2713 \u2713 \u2713 \u2713 Thousands Separator \u2713 \u2713 \u2713 \u2713 Time Format \u2713 \u2713 \u2713 \u2713 Time Separator \u2713 \u2713 \u2713 \u2713 Total Slack Calculation Type \u2713 \u2713 \u2713 \u2713 Updating Task Status Updates Resource Status \u2713 \u2713 \u2713 \u2713 Use Expected Finish Dates \u2713 \u2713 \u2713 \u2713 WBS Code Separator \u2713 \u2713 \u2713 \u2713 Week Start Day \u2713 \u2713 \u2713 \u2713 When Scheduling Progressed Activities Use \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Date \u2713 \u2713 \u2713 Baseline2 Date \u2713 \u2713 Baseline3 Date \u2713 \u2713 Baseline4 Date \u2713 \u2713 Baseline5 Date \u2713 \u2713 Baseline6 Date \u2713 \u2713 Baseline7 Date \u2713 \u2713 Baseline8 Date \u2713 \u2713 Baseline9 Date \u2713 \u2713 Baseline10 Date \u2713 \u2713 Baseline Calendar Name \u2713 \u2713 \u2713 \u2713 Baseline Date \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#task","title":"Task","text":""},{"location":"mpp-field-guide/#core-fields_1","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 % Complete \u2713 \u2713 \u2713 \u2713 % Work Complete \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 Activity Codes \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 Actual Duration \u2713 \u2713 \u2713 \u2713 Actual Duration Units \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Board Status ID \u2713 Budget Cost \u2713 \u2713 \u2713 Budget Work \u2713 \u2713 \u2713 Calendar Unique ID \u2713 \u2713 \u2713 Complete Through \u2713 \u2713 \u2713 \u2713 Constraint Date \u2713 \u2713 \u2713 \u2713 Constraint Type \u2713 \u2713 \u2713 \u2713 Contact \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 \u2713 Critical \u2713 \u2713 \u2713 \u2713 Deadline \u2713 \u2713 \u2713 Duration \u2713 \u2713 \u2713 \u2713 Duration Units \u2713 \u2713 \u2713 Duration Variance \u2713 \u2713 \u2713 \u2713 Early Finish \u2713 \u2713 \u2713 \u2713 Early Start \u2713 \u2713 \u2713 \u2713 Earned Value Method \u2713 \u2713 Effort Driven \u2713 \u2713 \u2713 \u2713 Estimated \u2713 \u2713 \u2713 Expanded \u2713 \u2713 \u2713 \u2713 Expense Items \u2713 \u2713 \u2713 \u2713 External Project \u2713 \u2713 \u2713 External Task \u2713 \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 Finish Slack \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 \u2713 Fixed Cost \u2713 \u2713 \u2713 \u2713 Fixed Cost Accrual \u2713 \u2713 \u2713 \u2713 Free Slack \u2713 \u2713 \u2713 GUID \u2713 \u2713 Hide Bar \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink SubAddress \u2713 \u2713 \u2713 \u2713 ID \u2713 \u2713 \u2713 \u2713 Ignore Resource Calendar \u2713 \u2713 \u2713 Late Finish \u2713 \u2713 \u2713 \u2713 Late Start \u2713 \u2713 \u2713 \u2713 Level Assignments \u2713 \u2713 \u2713 \u2713 Leveling Can Split \u2713 \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 \u2713 Manual Duration \u2713 Manual Duration Units \u2713 Marked \u2713 \u2713 \u2713 Milestone \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 Null \u2713 \u2713 \u2713 Outline Level \u2713 \u2713 \u2713 \u2713 Outline Number \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 \u2713 Parent Task Unique ID \u2713 \u2713 \u2713 Physical % Complete \u2713 \u2713 \u2713 Preleveled Finish \u2713 \u2713 \u2713 \u2713 Preleveled Start \u2713 \u2713 \u2713 \u2713 Priority \u2713 \u2713 \u2713 \u2713 Project \u2713 \u2713 \u2713 Recalc Outline Codes \u2713 \u2713 Recurring \u2713 \u2713 \u2713 \u2713 Recurring Data \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Duration \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resume \u2713 \u2713 \u2713 \u2713 Resume No Earlier Than \u2713 \u2713 \u2713 Rollup \u2713 \u2713 \u2713 \u2713 Scheduled Duration \u2713 Scheduled Finish \u2713 Scheduled Start \u2713 Splits \u2713 \u2713 \u2713 Sprint ID \u2713 Start \u2713 \u2713 \u2713 \u2713 Start Slack \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 \u2713 Steps \u2713 \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 \u2713 Subproject File \u2713 \u2713 \u2713 Subproject GUID \u2713 \u2713 Subproject Task ID \u2713 \u2713 \u2713 Subproject Task Unique ID \u2713 \u2713 \u2713 Subproject Tasks Unique ID Offset \u2713 \u2713 \u2713 Summary \u2713 \u2713 \u2713 \u2713 Summary Progress \u2713 \u2713 \u2713 Task Calendar GUID \u2713 \u2713 Task Mode \u2713 Task Name \u2713 \u2713 \u2713 \u2713 Total Slack \u2713 \u2713 \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 WBS \u2713 \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_1","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Duration \u2713 \u2713 \u2713 Baseline1 Duration Units \u2713 \u2713 Baseline1 Estimated Duration \u2713 Baseline1 Estimated Finish \u2713 Baseline1 Estimated Start \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Fixed Cost \u2713 \u2713 \u2713 Baseline1 Fixed Cost Accrual \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Duration \u2713 \u2713 \u2713 Baseline2 Duration Units \u2713 \u2713 Baseline2 Estimated Duration \u2713 Baseline2 Estimated Finish \u2713 Baseline2 Estimated Start \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Fixed Cost \u2713 \u2713 \u2713 Baseline2 Fixed Cost Accrual \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Duration \u2713 \u2713 \u2713 Baseline3 Duration Units \u2713 \u2713 Baseline3 Estimated Duration \u2713 Baseline3 Estimated Finish \u2713 Baseline3 Estimated Start \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Fixed Cost \u2713 \u2713 \u2713 Baseline3 Fixed Cost Accrual \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Duration \u2713 \u2713 \u2713 Baseline4 Duration Units \u2713 \u2713 Baseline4 Estimated Duration \u2713 Baseline4 Estimated Finish \u2713 Baseline4 Estimated Start \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Fixed Cost \u2713 \u2713 \u2713 Baseline4 Fixed Cost Accrual \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Duration \u2713 \u2713 \u2713 Baseline5 Duration Units \u2713 \u2713 Baseline5 Estimated Duration \u2713 Baseline5 Estimated Finish \u2713 Baseline5 Estimated Start \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Fixed Cost \u2713 \u2713 \u2713 Baseline5 Fixed Cost Accrual \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Duration \u2713 \u2713 \u2713 Baseline6 Duration Units \u2713 \u2713 Baseline6 Estimated Duration \u2713 Baseline6 Estimated Finish \u2713 Baseline6 Estimated Start \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Fixed Cost \u2713 \u2713 \u2713 Baseline6 Fixed Cost Accrual \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Duration \u2713 \u2713 \u2713 Baseline7 Duration Units \u2713 \u2713 Baseline7 Estimated Duration \u2713 Baseline7 Estimated Finish \u2713 Baseline7 Estimated Start \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Fixed Cost \u2713 \u2713 \u2713 Baseline7 Fixed Cost Accrual \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Duration \u2713 \u2713 \u2713 Baseline8 Duration Units \u2713 \u2713 Baseline8 Estimated Duration \u2713 Baseline8 Estimated Finish \u2713 Baseline8 Estimated Start \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Fixed Cost \u2713 \u2713 \u2713 Baseline8 Fixed Cost Accrual \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Duration \u2713 \u2713 \u2713 Baseline9 Duration Units \u2713 \u2713 Baseline9 Estimated Duration \u2713 Baseline9 Estimated Finish \u2713 Baseline9 Estimated Start \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Fixed Cost \u2713 \u2713 \u2713 Baseline9 Fixed Cost Accrual \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Deliverable Finish \u2713 Baseline10 Duration \u2713 \u2713 \u2713 Baseline10 Duration Units \u2713 \u2713 Baseline10 Estimated Duration \u2713 Baseline10 Estimated Finish \u2713 Baseline10 Estimated Start \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Fixed Cost \u2713 \u2713 \u2713 Baseline10 Fixed Cost Accrual \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 Baseline Deliverable Finish \u2713 Baseline Deliverable Start \u2713 Baseline Duration \u2713 \u2713 \u2713 \u2713 Baseline Duration Units \u2713 \u2713 \u2713 Baseline Estimated Duration \u2713 Baseline Estimated Finish \u2713 Baseline Estimated Start \u2713 Baseline Finish \u2713 \u2713 \u2713 \u2713 Baseline Fixed Cost \u2713 \u2713 \u2713 Baseline Fixed Cost Accrual \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 \u2713 \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 \u2713 \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 \u2713 \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 \u2713 \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 \u2713 \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 \u2713 \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 \u2713 \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 \u2713 \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 \u2713 \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#enterprise-fields","title":"Enterprise Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 \u2713 Enterprise Duration2 Units \u2713 \u2713 Enterprise Duration3 Units \u2713 \u2713 Enterprise Duration4 Units \u2713 \u2713 Enterprise Duration5 Units \u2713 \u2713 Enterprise Duration6 Units \u2713 \u2713 Enterprise Duration7 Units \u2713 \u2713 Enterprise Duration8 Units \u2713 \u2713 Enterprise Duration9 Units \u2713 \u2713 Enterprise Duration10 Units \u2713 \u2713 Enterprise Project Date1 \u2713 Enterprise Project Date2 \u2713 Enterprise Project Date3 \u2713 Enterprise Project Date4 \u2713 Enterprise Project Number2 \u2713 Enterprise Project Number4 \u2713 Enterprise Project Number5 \u2713 Enterprise Project Number22 \u2713 Enterprise Project Text1 \u2713 \u2713 \u2713 Enterprise Project Text2 \u2713 \u2713 Enterprise Project Text3 \u2713 \u2713 Enterprise Project Text4 \u2713 \u2713 Enterprise Project Text5 \u2713 Enterprise Project Text6 \u2713 \u2713 Enterprise Project Text8 \u2713 Enterprise Project Text9 \u2713 Enterprise Project Text10 \u2713 Enterprise Project Text11 \u2713 Enterprise Project Text12 \u2713 Enterprise Project Text13 \u2713 Enterprise Project Text14 \u2713 Enterprise Project Text15 \u2713 Enterprise Project Text16 \u2713 Enterprise Project Text17 \u2713 Enterprise Project Text18 \u2713 Enterprise Project Text19 \u2713 Enterprise Project Text21 \u2713 Enterprise Project Text40 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#resource","title":"Resource","text":""},{"location":"mpp-field-guide/#core-fields_2","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Accrue At \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Availability Data \u2713 \u2713 \u2713 Available From \u2713 \u2713 \u2713 Available To \u2713 \u2713 \u2713 Booking Type \u2713 \u2713 Budget \u2713 \u2713 Budget Cost \u2713 \u2713 \u2713 Budget Work \u2713 \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 Calendar GUID \u2713 \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 Code \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Center \u2713 Cost Per Use \u2713 \u2713 \u2713 Cost Rate A \u2713 \u2713 \u2713 Cost Rate B \u2713 \u2713 \u2713 Cost Rate C \u2713 \u2713 \u2713 Cost Rate D \u2713 \u2713 \u2713 Cost Rate E \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Default Units \u2713 \u2713 \u2713 \u2713 Email Address \u2713 \u2713 \u2713 GUID \u2713 \u2713 Generic \u2713 \u2713 \u2713 Group \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink SubAddress \u2713 \u2713 \u2713 ID \u2713 \u2713 \u2713 \u2713 Initials \u2713 \u2713 \u2713 \u2713 Material Label \u2713 \u2713 \u2713 Max Units \u2713 \u2713 \u2713 Name \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 Overallocated \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Rate \u2713 \u2713 \u2713 Overtime Rate Units \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Peak \u2713 \u2713 \u2713 \u2713 Phonetics \u2713 Regular Work \u2713 \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Standard Rate \u2713 \u2713 \u2713 Standard Rate Units \u2713 \u2713 \u2713 Subproject Unique Resource ID \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 Unit of Measure Unique ID \u2713 \u2713 \u2713 Windows User Account \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 Workgroup \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_2","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields_1","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 \u2713 \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 \u2713 \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 \u2713 \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 \u2713 \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 \u2713 \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 \u2713 \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 \u2713 \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 \u2713 \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 \u2713 \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#enterprise-fields_1","title":"Enterprise Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Enterprise \u2713 \u2713 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 \u2713 Enterprise Duration2 Units \u2713 \u2713 Enterprise Duration3 Units \u2713 \u2713 Enterprise Duration4 Units \u2713 \u2713 Enterprise Duration5 Units \u2713 \u2713 Enterprise Duration6 Units \u2713 \u2713 Enterprise Duration7 Units \u2713 \u2713 Enterprise Duration8 Units \u2713 \u2713 Enterprise Duration9 Units \u2713 \u2713 Enterprise Duration10 Units \u2713 \u2713 Enterprise Unique ID \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#resource-assignment","title":"Resource Assignment","text":""},{"location":"mpp-field-guide/#core-fields_3","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Actual Cost \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Assignment Delay \u2713 \u2713 \u2713 Assignment GUID \u2713 \u2713 Assignment Resource GUID \u2713 \u2713 Assignment Task GUID \u2713 \u2713 Assignment Units \u2713 \u2713 \u2713 \u2713 Budget Cost \u2713 \u2713 Budget Work \u2713 \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 Confirmed \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Rate Table \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink Subaddress \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 Linked Fields \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Owner \u2713 \u2713 Percent Work Complete \u2713 \u2713 \u2713 \u2713 Rate Source \u2713 \u2713 \u2713 \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resource Request Type \u2713 \u2713 Resource Unique ID \u2713 \u2713 \u2713 \u2713 Response Pending \u2713 \u2713 \u2713 Resume \u2713 \u2713 \u2713 Start \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 Task Unique ID \u2713 \u2713 \u2713 \u2713 Team Status Pending \u2713 \u2713 \u2713 Timephased Actual Overtime Work \u2713 \u2713 \u2713 Timephased Actual Work \u2713 \u2713 \u2713 Timephased Work \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 Variable Rate Units \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Contour \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_3","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Budget Cost \u2713 \u2713 Baseline1 Budget Work \u2713 \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 \u2713 Baseline2 Budget Work \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 \u2713 Baseline3 Budget Work \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 \u2713 Baseline4 Budget Work \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 \u2713 Baseline5 Budget Work \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 \u2713 Baseline6 Budget Work \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 \u2713 Baseline7 Budget Work \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 \u2713 Baseline8 Budget Work \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 \u2713 Baseline9 Budget Work \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 \u2713 Baseline10 Budget Work \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 \u2713 Baseline Budget Work \u2713 \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Finish \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 Timephased Baseline1 Cost \u2713 \u2713 \u2713 Timephased Baseline1 Work \u2713 \u2713 \u2713 Timephased Baseline2 Cost \u2713 \u2713 Timephased Baseline2 Work \u2713 \u2713 Timephased Baseline3 Cost \u2713 \u2713 Timephased Baseline3 Work \u2713 \u2713 Timephased Baseline4 Cost \u2713 \u2713 Timephased Baseline4 Work \u2713 \u2713 Timephased Baseline5 Cost \u2713 \u2713 Timephased Baseline5 Work \u2713 \u2713 Timephased Baseline6 Cost \u2713 \u2713 Timephased Baseline6 Work \u2713 \u2713 Timephased Baseline7 Cost \u2713 \u2713 Timephased Baseline7 Work \u2713 \u2713 Timephased Baseline8 Cost \u2713 \u2713 Timephased Baseline8 Work \u2713 \u2713 Timephased Baseline9 Cost \u2713 \u2713 Timephased Baseline9 Work \u2713 \u2713 Timephased Baseline10 Cost \u2713 \u2713 \u2713 Timephased Baseline10 Work \u2713 \u2713 \u2713 Timephased Baseline Cost \u2713 \u2713 \u2713 Timephased Baseline Work \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields_2","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"store/","title":"Store","text":"
Yes, MPXJ has merchandise! For a small range of MPXJ branded clothing, please visit the MPXJ store. All purchases made from the store help to suport the development of MPXJ.
Thank you!
"},{"location":"support/","title":"Support","text":"
Support and feature requests can be opened on MPXJ's issue tracker. I will respond to these as time permits.
For more pressing issues, commercial support is available via my company Timephased. I can also provide consultancy around the use of MPXJ and implementation services. Please contact me directly for further details.
"},{"location":"supported-formats/","title":"Supported Formats","text":"
MPX: The MPX file format can be read by versions of Microsoft Project up to and including Microsoft Project 2010, and written by versions up to Microsoft Project 98. MPXJ allows MPX files to be created, read and written. See this Microsoft support article for a definition of the file format.
MPP: The MPP file format is Microsoft's proprietary way of storing project data. MPXJ supports read only access to MPP files produced by Microsoft Project 98, Microsoft Project 2000, Microsoft Project 2002, Microsoft Project 2003, Microsoft Project 2007, Microsoft Project 2010, Microsoft Project 2013, Microsoft Project 2016, and Microsoft Project 2019. MPP template files, with the suffix MPT are also supported.
MSPDI: The MSPDI file format is Microsoft's XML file format for storing project data. Versions of Microsoft Project from 2002 onwards can read and write MSPDI files. MPXJ allows MSPDI files to be created, read, and written. The MSDPI file format has remained broadly unchanged since it was introduced, although several versions of Microsoft Project have tweaked the file format slightly, and have their own updated documentation. Documentation is available online here. Documentation for the Project 2003 MSPDI file format can be downloaded as part of the Office 2003 XML Reference Schemas package. Documentation for the Project 2007 MSPDI file format can be downloaded as part of the Project 2007 SDK. Documentation for the Project 2010 MSPDI file format can be downloaded as part of the Project 2010 Reference: Software Development Kit. Documentation for the Project 2013 MSPDI file format can be downloaded as part of the Project 2013 SDK.
MPD: The MPD file format is an Access database used to store one or more projects. The database schema used in these databases is also close to that used by Microsoft Project Server. MPXJ can read projects stored in an MPD file using a JDBC connection. It is possible that MPXJ could also read the same data from a Microsoft Project Server database using the same approach, but this is not something I've tested.
PLANNER: Planner is an Open Source project management tool which uses an XML file format to store project data. MPXJ can read and write the Planner file format.
PRIMAVERA P6: Primavera P6 is an industry-leading tool favoured by users with complex planning requirements. It can export project data in the form of XER or PMXML files, both of which MPXJ can read. It is also possible for MPXJ to connect directly to the P6 database via JDBC to read project data. MPXJ can also write PMXML and XER files to allow data to be exported in a form which can be consumed by P6. The PMXML schema forms part of the P6 distribution media, which can be downloaded from the Oracle e-Delivery site.
PRIMAVERA P3: Primavera P3 (Primavera Project Planner) is the forerunner of P6. It holds projects in Btrieve database files which MPXJ can read from a directory or from a zip archive. MPXJ can also read P3 data from PRX backup files.
PRIMAVERA SURETRAK: SureTrak holds projects in Btrieve database files which MPXJ can read from a directory or from a zip archive. MPXJ can also read SureTrak data from STX backup files.
POWERPROJECT: Asta Powerproject is a planning tool used in a number of industries, particularly construction. Powerproject can save data to PP files or to MDB database files, and MPXJ can read both of these formats.
PHOENIX: Phoenix Project Manager is an easy-to-use critical path method scheduling tool aimed primarily at the construction industry. Phoenix writes PPX files which MPXJ can read.
FASTTRACK: Fasttrack Schedule is general purpose planning tool. FastTrack writes FTS files which MPXJ can read.
GANTTPROJECT: GanttProject is an open source general purpose planning tool. GanttProject writes GAN files which MPXJ can read.
TURBOPROJECT: TurboProject is general purpose planning tool. TurboProject writes PEP files which MPXJ can read.
CONECPTDRAW PROJECT: ConceptDraw PROJECT is general purpose planning tool. ConceptDraw PROJECT writes CDPX, CDPZ and CDPTZ files which MPXJ can read.
SYNCHRO SCHEDULER: Synchro Scheduler is general purpose planning tool. Synchro Scheduler writes SP files which MPXJ can read.
GANTT DESIGNER: Gantt Designer is a simple Gantt chart drawing tool. Gantt Designer writes GNT files which MPXJ can read.
SDEF: SDEF is the Standard Data Exchange Format, as defined by the USACE (United States Army Corps of Engineers). SDEF is a fixed column format text file, used to import a project schedule up into the QCS (Quality Control System) software from USACE. MPXJ can read and write SDEF files. The specification for the file format can be found here.
SCHEDULE_GRID: Schedule grid files are produced when a schedule is exported from Sage 100 Contractor. MPXJ can read schedule grid files.
PROJECT COMMANDER: Project Commander files are the native file format used by the Project Commander application. Project Commander writes PC files which MPXJ can read.
DELTEK OPEN PLAN: Open Plan allows export of schedules to BK3 files, which MPXJ can read.
"},{"location":"users/","title":"MPXJ Users","text":"
Here is a list of organisations and projects currently using, or believed to be using MPXJ. Feel free to contact me if you would like to be featured in this list.
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":"
Welcome to MPXJ! This library enables you to read project plans (sometimes known as schedules or programmes) from a variety of file formats and databases, and can also write that information to a variety of file formats.
The library is based on data structures which follow the way schedule data is represented by Microsoft Project, extended to accommodate features and concepts from other applications.
"},{"location":"#sponsors","title":"Sponsors","text":"
Work to build and maintain MPXJ is kindly supported by my sponsors:
Head over to my sponsors page if you'd like to see your name and logo here!
"},{"location":"#file-formats","title":"File Formats","text":"
MPXJ can read file formats including MPX, MPP, MSPDI, MPD, Planner, Primavera P6 PMXML and XER, Primavera P3, SureTrak, Asta Powerproject, Asta Easyplan, Phoenix, Fasttrack, GanttProject, TurboProject, ConceptDraw PROJECT, Synchro, Gantt Designer, SDEF, Sage 100 Contractor Schedule Grid, Project Commander and Deltek Open Plan BK3.
MPXJ can also write schedule data as MPX, MSPDI, PMXML, XER, Planner and SDEF files.
More details of the supported file formats can be found here.
"},{"location":"#languages","title":"Languages","text":"
MPXJ is written and maintained in Java, however this is no barrier to using its functionality in other languages. Thanks to IKVM, MPXJ is available for .Net, allowing it to be used from any .Net language.
There is also now a Ruby Gem which provides native Ruby access to read from schedule files using MPXJ, and a Python package which wraps the Java library to provide full read/write access to schedule files.
You may be able to leverage MPXJ from other languages too, for example the PHP/Java Bridge can be used to expose the complete MPXJ API in PHP.
"},{"location":"#contact","title":"Contact","text":"
Having problems? Need support? All the details you need can be found on the support page.
Using MPXJ successfully somewhere? I'd love to hear from you about your experiences. Do tell me what's missing or what could be better - I can use this feedback to guide future development work. It would also be great to add a link to your website from the MPXJ users page.
Finally, if you're deriving value from MPXJ, please consider sponsoring me to ensure I can continue enhancing and maintaining the library. Thank you!
"},{"location":"#licensing","title":"Licensing","text":"
MPXJ is distributed under the terms of the GNU LGPL a copy of which can be found in the root of the distribution. Please read this license carefully! It will cost you nothing to use MPXJ commercially or non-commercially, but you must comply with the terms of the license.
Please see the legal folder within the distribution for details of the licences for the third party libraries used by MPXJ.
"},{"location":"#acknowledgements","title":"Acknowledgements","text":"
This library includes functionality provided by:
This library has been built with the assistance of:
"},{"location":"CHANGELOG/","title":"Changelog","text":""},{"location":"CHANGELOG/#1292-unreleased","title":"12.9.2 (unreleased)","text":""},{"location":"CHANGELOG/#1291-2024-04-17","title":"12.9.1 (2024-04-17)","text":"
UniversalProjectReader
would raise an exception when handling an unknown file type."},{"location":"CHANGELOG/#1290-2024-04-11","title":"12.9.0 (2024-04-11)","text":"
UniversalProjectReader
to add getProjectReaderProxy
methods to allow access to the instance of the reader class which will be used to read a schedule, prior to the schedule being read. This will allow the reader to be configured, or schedule to be ignored without reading its content.ProjectReader.setProperties
method. This method was originally implemented to allow settings to be passed to reader classes when using UniversalProjectReader
. You can now use UniversalProjectReader.getProjectReaderProxy
to achieve this.from
method to all Builder
classes to allow initialisation from existing objects.CostAccount.Builder
class now provides two notes
methods to allow formatted or unformatted notes to be added to cost accounts.CostAccount
method getDescription()
has been marked as deprecated. Use the getNotes()
or getNotesObject()
method instead.CustomFieldValueItem
methods getParent
and setParent
have been marked as deprecated. Use the getParentUniqueID
and setParentUniqueID
methods instead."},{"location":"CHANGELOG/#1281-2024-03-11","title":"12.8.1 (2024-03-11)","text":"
"},{"location":"CHANGELOG/#1280-2024-03-04","title":"12.8.0 (2024-03-04)","text":"
Relation.Builder
class.Relation(Task,Task,RelationType,Duration)
constructor as deprecated, use the Relation.Builder
class instead.RelationContainer.addPredecessor(Task,Task,RelationType,Duration)
method as deprecated, use the RelationContainer.addPredecessor(Relation.Builder)
method instead.Task.addPredecessor(Task,RelationType,Duration)
method as deprecated, use the Task.addPredecessor(Relation.Builder)
method instead.Relation
class and ensure that it is read from and written to P6 schedules.readAll
method on reader classes to ensure that if the reader is unable to read any schedule data, an empty list is returned rather than a list containing null
."},{"location":"CHANGELOG/#1270-2024-02-07","title":"12.7.0 (2024-02-07)","text":"
ProjectCalendar.getPreviousWorkFinish
method when called with a time which was already at the end of a period of work.proj_node_flag
is set for the root WBS node when writing XER files."},{"location":"CHANGELOG/#1260-2024-01-22","title":"12.6.0 (2024-01-22)","text":"
ResourceAssignment.getEffectiveCalendar
method.ResourceAssignment.getCalendar
method, use getEffectiveCalendar
method instead.TimephasedUtility.segmentBaselineWork
and segmentBaselineCost
methods which take a ProjectCalendar
instance as the first argument rather than a ProjectFile
instance.TimephasedUtility.segmentBaselineWork
and segmentBaselineCost
methods which take a ProjectFile
instance as the first argument.ProjectCalendar.getDate()
method which just takes a date and a duration as its arguments. This method handles both positive and negative durations.ProjectCalendar.getDate()
method as deprecated. Use the new version instead."},{"location":"CHANGELOG/#1250-2023-12-18","title":"12.5.0 (2023-12-18)","text":"
ProjectProperties
Relationship Lag Calendar attribute for PMXML files.ProjectProperties
custom properties map are now deprecated. These properties now have individual getter and setter methods available on the ProjectProperties
class. Note: this may be a breaking change if you were creating schedules from scratch, populating the custom properties map, then writing PMXML or XER files. In this case you will need to update your code, for all other use cases your code will continue to work unchanged until the next major version of MPXJ.ProjectProperties
attributes Baseline Type Name, Baseline Type Unique ID, and Last Baseline Update Date for baseline projects in PMXML files.ProjectProperties
creation date attribute with the PMXML date added attribute.CustomFieldContainer.remove
method to allow field configurations to be removed.UserDefinedFieldContainer.remove
method to ensure that any associated field configuration is removed from the CustomFieldContainer
."},{"location":"CHANGELOG/#1240-2023-11-23","title":"12.4.0 (2023-11-23)","text":"
ProjectProperties
.ActivityCodeValue
instances when reading Asta PP files.ProjectFile.expandSubprojects
method which takes a boolean
argument indicating if external tasks should be removed. Passing true
to this method will recreate predecessor and successor relationships using the original tasks rather than the placeholder external tasks, and will remove the external tasks.ProjectFile.expandSubprojects()
method as deprecated, use the new version which takes a boolean
argument instead.ProjectProperties
name attribute is set correctly when reading XER files and P6 databases.ProjectEntityContainer
method renumberUniqueIDs
has been marked as deprecated.ProjectEntityContainer
method getNextUniqueID
has been marked as deprecated. Use ProjectFile.getUniqueIdObjectSequence(class).getNext()
instead.ProjectEntityContainer
method updateUniqueIdCounter
has been marked as deprecated as it is no longer required.ProjectFile
method updateUniqueIdCounters
has been marked as deprecated as it is no longer required.ObjectSequence
method reset
has been marked as deprecated as it is no longer required.Location
instance using the Builder
class, a Unique ID will be generated if one is not supplied.Location.Builder
constructor has been marked a deprecated. Use the constructor which requires a ProjectFile
instance instead.ExpenseItem.Builder
class.ExpenseItem(task)
constructor as deprecated, use the ExpenseItem.Builder
class instead.ExpenseItem
setter methods a deprecated. The ExpenseItem
class will be immutable in the next major release.UnitOfMeasure.Builder()
constructor as deprecated, use the UnitOfMeasure.Builder(ProjectFile)
constructor instead.Step.Builder
class.Step(task)
constructor as deprecated, use the Step.Builder
class instead.Step
setter methods a deprecated. The Step
class will be immutable in the next major release.NotesTopic
constructor as deprecated, use the NotesTopic.Builder(ProjectFile)
constructor instead.ExpenseCategory.Builder
class.ExpenseCategory
constructor as deprecated, use the ExpenseCategory.Builder
class instead.CostAccount.Builder
class.CostAccount
constructor as deprecated, use the CostAccount.Builder
class instead.ActivityCodeValue.Builder
class.ActivityCodeValue
constructor as deprecated, use the ActivityCodeValue.Builder
class instead.ActivityCodeValue.setParent
method as deprecated, use the ActivityCodeValue.Builder
class instead.ActivityCode.addValue
method as deprecated, use the ActivityCodeValue.Builder
class instead to create an ActivityCodeValue
instance and add it directly to the list held by the parent ActivityCode
.ActivityCode.Builder
class.ActivityCode
constructor as deprecated, use the ActivityCode.Builder
class instead.Relation
instances are now stored in RelationContainer
, successors are generated dynamically. You will only notice a difference if you are iterating over the RelationContainer
collection directly, in which case you will only see predecessors."},{"location":"CHANGELOG/#1230-2023-11-07","title":"12.3.0 (2023-11-07)","text":"
"},{"location":"CHANGELOG/#1220-2023-10-12","title":"12.2.0 (2023-10-12)","text":"
UnitOfMeasure
class to represent the unit of measure for a material resource. The unit of measure corresponds to the current \"material label\" attribute of a resource. The Resource.getMaterialLabel()
method will now retrieve the label from the UnitOfMeasure
instance associated with the resource. The Resource.setMaterialLabel()
method is now deprecated, the Resource.setUnitOfMeasure()
or Resource.setUnitOfMeasureUniqueID()
methods should be used instead.setIgnoreErrors
method to the Primavera database reader class, and MSPDI, Schedule Grid, and SDEF file reader classes. The current default behavior of ignoring data type parse errors is unchanged. Calling setIgnoreErrors(false)
on one of these reader classes will ensure that an exception is raised when a data type parse error is encountered.ProjectFile.getIgnoredErrors()
method. The default behavior for MPXJ reader classes is to ignore data type parse errors. If any errors have been ignored when reading a schedule, details of these errors can be retrieved by calling the ProjectFile.getIgnoredErrors()
method.Resource.getMaxUnits()
method will return the resource's Max Units attribute for the current date. To retrieve the Max Units for a different date, use the AvailabilityTable.getEntryByDate()
method.Resource.setMaxUnits()
method as deprecated. The Max Units attribute is derived from the resource's availability table. Changes to Max Units should now be made by modifying the availability table.Resource.getAvailableFrom()
method will return the resource's Available From attribute for the current date. To retrieve the Available From attribute for a different date, use the AvailabilityTable.availableFrom()
method.Resource.setAvailableFrom()
method as deprecated. The Available From attribute is derived from the resource's availability table. Changes to the Available From attribute should now be made by modifying the availability table.Resource.getAvailableTo()
method will return the resource's Available To attribute for the current date. To retrieve the Available To attribute for a different date, use the AvailabilityTable.availableTo()
method.Resource.setAvailableTo()
method as deprecated. The Available To attribute is derived from the resource's availability table. Changes to the Available To attribute should now be made by modifying the availability table."},{"location":"CHANGELOG/#1213-2023-09-25","title":"12.1.3 (2023-09-25)","text":"
"},{"location":"CHANGELOG/#1212-2023-09-21","title":"12.1.2 (2023-09-21)","text":"
ProjectProperties.getCustomProperties()
returns an empty Map rather than returning null
if no custom properties have been configured."},{"location":"CHANGELOG/#1211-2023-08-23","title":"12.1.1 (2023-08-23)","text":"
"},{"location":"CHANGELOG/#1210-2023-08-22","title":"12.1.0 (2023-08-22)","text":"
TimeUnitDefaultsContainer
argument rather than a ProjectFile
for greater flexibility. Marked methods taking a ProjectFile
argument as deprecated.null
actual start date for actual duration calculation when reading PMXML files (Contributed by Andrew Marks)."},{"location":"CHANGELOG/#1202-2023-07-25","title":"12.0.2 (2023-07-25)","text":"
"},{"location":"CHANGELOG/#1201-2023-07-21","title":"12.0.1 (2023-07-21)","text":"
"},{"location":"CHANGELOG/#1200-2023-06-29","title":"12.0.0 (2023-06-29)","text":"
java.time.LocalDateTime
, java.time.LocalDate
and java.time.LocalTime
respectively, rather than java.util.Date
as they were originally.ToDateTime
and ToNullableDateTime
extension methods have been provided to convert java.time.LocalDateTime
, java.time.LocalDate
, java.time.LocalTime
to DateTime
instances.ToJavaLocalDateTime
, ToJavaLocalDate
and ToJavaLocalTime
extension methods have been provided to convert DateTime
instances to java.time.LocalDateTime
, java.time.LocalDate
, and java.time.LocalTime
.net.sf.mpxj.Day
has been replaced by java.time.DayOfWeek
."},{"location":"CHANGELOG/#1154-2023-06-27","title":"11.5.4 (2023-06-27)","text":"
PrimaveraXERFileReader.setIgnoreErrors
method to change the behavior."},{"location":"CHANGELOG/#1153-2023-06-19","title":"11.5.3 (2023-06-19)","text":"
java.sql.Date
values are correctly formatted when writing XER files."},{"location":"CHANGELOG/#1152-2023-06-08","title":"11.5.2 (2023-06-08)","text":"
"},{"location":"CHANGELOG/#1151-2023-05-24","title":"11.5.1 (2023-05-24)","text":"
"},{"location":"CHANGELOG/#1150-2023-05-19","title":"11.5.0 (2023-05-19)","text":"
getBarName
and setBarName
methods. This is populated with the name of the bar to which a task belongs when reading an Asta Powerproject schedule.null
rather than as a zero duration."},{"location":"CHANGELOG/#1140-2023-05-08","title":"11.4.0 (2023-05-08)","text":"
getResourcePoolFile
and setResourcePoolFile
methods.getResourcePoolObject
method to allow the resource pool file to be located and readgetSubprojectGUID
and setSubprojectGUID
methods.getExternalProject
and setExternalProject
methods.getSubprojectObject
which allows the caller to retrieve a ProjectFile instance representing the external project linked to a task.expandSubproject
. For task which represent an external project, this method automatically loads the external project and attaches the tasks it contains as children of the current task. This is analogous to the behavior in Microsoft Project where a subproject is expanded to reveal the tasks it contains.expandSubprojects
which identifies any tasks in the project which represent an external project and expands them, linking the tasks from the external project as children of the task in the parent project. Note that the method works recursively so multiple levels of external tasks will be expanded.internal_name
attribute of a UserdefinedField
is generated if not present.setSubprojectName
as deprecated. Use the setSubProjectFile
method instead.getSubprojectName
as deprecated. Use getSubprojectFile
instead.setExternalTaskProject
as deprecated. Use the setSubprojectFile
method instead.getExternalTaskProject
as deprecated. Use the getSubprojectFile
method instead.getSubProjects
as deprecated. Use the subproject attributes on individual tasks instead.getSubProject
and setSubProject
as deprecated. Use the subproject attributes instead."},{"location":"CHANGELOG/#1132-2023-04-29","title":"11.3.2 (2023-04-29)","text":"
"},{"location":"CHANGELOG/#1131-2023-04-21","title":"11.3.1 (2023-04-21)","text":"
"},{"location":"CHANGELOG/#1130-2023-04-12","title":"11.3.0 (2023-04-12)","text":"
PrimaveraXERFileWriter
to allow MPXJ to write XER files.ActivityCode
class to ensure that both the scope Project ID and EPS ID can be represented when reading a P6 schedule. (Potentially breaking change if you were using this class).WorkContour.isDefault()
method to allow \"built in\" resource curves/work contours to be distinguished from user defined curves.ProjectFile.getNotesTopics()
method.critical_drtn_hr_cnt
field is expressed a decimal rather than an integer."},{"location":"CHANGELOG/#1120-2023-03-13","title":"11.2.0 (2023-03-13)","text":"
Duration
rather than as an Integer
. (Potentially breaking change if you were using this property directly).TaskType
is now a simple enum with all Microsoft Project specific functionality moved into TaskTypeHelper
. (Potentially breaking change if you were using the TaskType
methods getInstance
or getValue
in your code)TaskType
enum has been updated to more closely match P6. The main changes are that the P6 type \"Fixed Units\" now maps to TaskType.FIXED_WORK
and the \"Fixed Duration & Units\" type now maps to a new enumeration value TaskType.FIXED_DURATION_AND_UNITS
."},{"location":"CHANGELOG/#1110-2023-02-15","title":"11.1.0 (2023-02-15)","text":"
ActivityCode
class.getChildCodes
method to ActivityCode
and ActivityCodeValue
to make it easier to traverse activity code values hierarchically.setDescription
method to Step
class to make it simpler to add a plan text description."},{"location":"CHANGELOG/#1100-2023-02-08","title":"11.0.0 (2023-02-08)","text":"
UserDefinedField
. They will no longer be mapped to custom field instances.UserDefinedField
.UserDefinedField
type implements the FieldType
interface and so can be used with the FieldContainer
get
and set
methods to work with the contents of the user defined fields.ProjectFile.getUserDefinedFields()
method has been added to provide access to all user defined fields defined in the project.CustomFieldContainer
returned by ProjectFile.getCustomFields()
will contain entries for all UserDefinedField
instances.getFieldTypeByAlias
and getFieldByAlias
methods will retrieve user defined fields by name.ProjectFile.getPopulatedFields()
to retrieve details of all populated fields across the project. This avoids the caller having to individually retrieve the populated fields from the tasks container, resource container and so on.getPopulatedFields
methods to return a Set
of FieldType
rather than a Set
of TaskField
, ResourceField
etc.getPopulatedFields
methods will include instances of UserDefinedField
in the returned collection if relevant.ENTERPRISE_CUSTOM_FIELDn
values have been removed from the TaskField
, ResourceField
, AssignmentField
and ProjectField
enumerations.getEnterpriseCustomField
and setEnterpriseCustomField
methods have been removed from ProjectProperties
, Task,
Resourceand
ResourceAssignment`."},{"location":"CHANGELOG/#10162-2023-01-29","title":"10.16.2 (2023-01-29)","text":"
"},{"location":"CHANGELOG/#10161-2023-01-26","title":"10.16.1 (2023-01-26)","text":"
WorkContourContainer
. This container is accessed using the ProjectFile.getWorkContours()
method."},{"location":"CHANGELOG/#10160-2023-01-24","title":"10.16.0 (2023-01-24)","text":"
GanttBarCommonStyle
and GanttBarStyle
classes to use a FieldType
instance rather than a TaskField
instance to allow more flexibility. (Note: this may be a breaking change if you are currently using these classes.)"},{"location":"CHANGELOG/#10150-2023-01-11","title":"10.15.0 (2023-01-11)","text":"
MPXJ.VERSION
."},{"location":"CHANGELOG/#10141-2022-11-25","title":"10.14.1 (2022-11-25)","text":"
"},{"location":"CHANGELOG/#10140-2022-11-21","title":"10.14.0 (2022-11-21)","text":"
File
instance, ensure a more memory-efficient approach is used."},{"location":"CHANGELOG/#10130-2022-11-16","title":"10.13.0 (2022-11-16)","text":"
"},{"location":"CHANGELOG/#10120-2022-11-01","title":"10.12.0 (2022-11-01)","text":"
CostAccount
method getSequence
and replace with getSequenceNumber
to improve naming consistency.ExpenseCategory
method getSequence
and replace with getSequenceNumber
to improve naming consistency."},{"location":"CHANGELOG/#10110-2022-09-27","title":"10.11.0 (2022-09-27)","text":"
Resource
methods getParentID
and setParentID
. Replaced with getParentResourceUniqueID
and setParentResourceUniqueID
for clarity and consistency.Resource
methods setParent
and getParent
.ChildResourceContainer
interface and ResourceContainer.updateStructure
method to ensure that resources can be accessed hierarchically when reading a schedule.ResourceAssignment
methods getFieldByAlias
and setFieldByAlias
to simplify working with custom fields, and mkae the API consistent with existing methods on Task
and Resource
.TaskContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to task custom fields.ResourceContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to resource custom fields.ResourceAssignmentContainer
methods getCustomFields
and getFieldTypeByAlias
to simplify access to resource assignment custom fields.getCustomFieldsByFieldTypeClass
method to CustomFieldContainer
to allow retrieval of custom field details by parent class.CustomFieldContainer
method getFieldByAlias
to be replaced by getFieldTypeByAlias
to provide a more consistent method name.CustomFieldContainer
method add
.CustomFieldContainer
method getCustomField
, which is replaced by the get
method (which returns null
if the field type is not configured) and the getOrCreate
method (which will return an existing configuration or create a new one if the requested field does not yet have a configuration)."},{"location":"CHANGELOG/#10100-2022-09-13","title":"10.10.0 (2022-09-13)","text":"
setProperties
method to reader classes to allow configuration to be supplied via a Properties
instance rather than having to call setter methods. Properties passed to the UniversalProjectReader
version of this method will be forwarded to the reader class UniversalProjectReader
chooses to reader the supplied file. Properties for multiple reader classes can be included in the Properties
instance, each reader class will ignore irrelevant properties.get
method to Task
, Resource
, ResourceAssignment
and ProjectProperties
as a replacement for the getCurrentValue
method. The new get
method is paired with the existing set
method to provide read and write access to attributes of these classes. This change is intended to improve the interfaces to these classes by making them more consistent, and thus easier to understand.getCurrentValue
method on the Task
, Resource
, ResourceAssignment
and ProjectProperties
classes. Use the new get
method instead.ResourceAssignment
calculated fields are returned correctly when using the getCurrentValue
method.ProjectProperties
calculated fields are returned correctly when using the getCurrentValue
method."},{"location":"CHANGELOG/#1091-2022-08-31","title":"10.9.1 (2022-08-31)","text":"
"},{"location":"CHANGELOG/#1090-2022-08-23","title":"10.9.0 (2022-08-23)","text":"
ResourceAssignment.getEffectiveRate
method to allow the cost rate effective on a given date for a resource assignment to be calculated. For P6 schedules this will take account of the cost rate configuration included as part of the resource assignment.ResourceAssignment.getCostRateTable
method now takes in account any cost rate configuration details from the resource assignment when determining which table to return.setStandardRate
, setOvertimeRate
, and setCostPerUse
have been deprecated. These attributes can now only be set or updated by modifying the resource's cost rate table.ResourceAssignment.getRateIndex
method. The value returned by this method can be used to select the required rate using the CostRateTableEntry,getRate
method.ResourceAssignment.getRole
and ResourceAssignment.setRole
methods.ResourceAssignment.getOverrideRate
and ResourceAssignment.setOverrideRate
methods.ResourceAssignment.getRateSource
and ResourceAssignment.setRateSource
methods."},{"location":"CHANGELOG/#1080-2022-08-17","title":"10.8.0 (2022-08-17)","text":"
CostRateTableEntry.getRate
method.getStandardRateUnits
and getOvertimeRateUnits
are deprecated. Use the getStandardRate
and getOvertimeRate
methods to retrieve a Rate
instance which will include the units for these rates.setStandardRateUnits
and setOvertimeRateUnits
are deprecated. Supply Rate
instances to the setStandardRate
and setOvertimeRate
methods with the required units instead.getStandardRateUnits
and getOvertimeRateUnits
are deprecated. Use the getStandardRate
and getOvertimeRate
methods to retrieve a Rate
instance which will include the units for these rates."},{"location":"CHANGELOG/#1070-2022-08-09","title":"10.7.0 (2022-08-09)","text":"
"},{"location":"CHANGELOG/#1062-2022-06-29","title":"10.6.2 (2022-06-29)","text":"
ProjectCleanUtility
can load dictionary words from distribution jar."},{"location":"CHANGELOG/#1061-2022-06-14","title":"10.6.1 (2022-06-14)","text":"
"},{"location":"CHANGELOG/#1060-2022-06-08","title":"10.6.0 (2022-06-08)","text":"
getUniqueID
and setUniqueID
methods on `CustomField (based on a suggestion by Wes Lund).isWorking
method to ProjectCalendarException
to make it clearer how to determine if the exception changes the dates it is applied to into working or non-working days."},{"location":"CHANGELOG/#1050-2022-05-24","title":"10.5.0 (2022-05-24)","text":"
ProjectCalendarWeek
methods addCalendarHours()
, attachHoursToDay
, removeHoursFromDay
have been removed. Use addCalendarHours(day)
, removeCalendarHours(day)
instead. (Note: this will be a breaking change if you were using the original methods to create or modify a schedule)ProjectCalendar
methods attachHoursToDay
and removeHoursFromDay
have been removed. Use the addCalendarHours
and removeCalendarHours
methods instead. (Note: this will be a breaking change if you were using the original methods to create or modify a schedule)ProjectCalendarHours
and ProjectCalendarException
has been simplified, but there should be no impact for uses of these classes.ProjectCalendarHours
class now implements the List
interface. Methods in this class not part ofthe List
interface have been deprecated in favour of the equivalent List
methods.MPXWriter
to ensure: calendar names are quoted if necessary, all calendars have names, all calendar names are unique.MPXReader
to recognise wk
as a valid time unit.MPXWriter
, PrimaveraPMFileWriter
, SDEFWriter
and PlannerWriter
to ensure any working weeks defined by a calendar are represented by exceptons.MSPDIWriter
to ensure any working weeks defined by a calendar are represented in the \"legacy\" exception definition used by Microsoft Project prior to 2007.SDEFWriter
to ensure: only relevant calendars are written, and derived calendars are flattened.ProjectCalendar
and ProjectCalendarWeek
both now inherit from a new class ProjectCalendarDays
. Note that ProjectCalendar
is no longer a subclass of ProjectCalendarWeek
.getHours
and isWorkingDay
methods have been moved up to ProjectCalendar
from the ProjectCalendarWeek
class.ProjectCalendar
method copy
has been deprecated, without replacement.getWork
method to ProjectCalendar
which calculates the amount of work given a Day
instance.removeWorkWeek
and removeCalendarException
methods to ProjectCalendar
.ProjectCalendar
using the addCalendarException
method which takes a recurringData
instance its argument.ProjectCalendarException
method setRecurringData
has been removed, recurring exceptions should be added using the addCalendarExcepton
method described above. (Note: this will be a breaking change if you were creating recurring exceptions)"},{"location":"CHANGELOG/#1040-2022-05-05","title":"10.4.0 (2022-05-05)","text":"
getParent
, setParent
, and isDerived
from ProjectCalendarWeek
. (Note: this will be a breaking change if you were working with ProjectCalendarWeek
directly).ProjectProperties
methods getDefaultCalendarName()
and setDefaultCalendarName()
have been deprecated. Use getDefaultCalendar()
and setDefaultCalendar()
instead."},{"location":"CHANGELOG/#1030-2022-04-29","title":"10.3.0 (2022-04-29)","text":"
MPXWriter
and MSPDIWriter
to ensure that, when written, calendars are correctly structured in the form required by Microsoft Project.JsonWriter
now includes calendar data as part of its output.ProjectCalendar
methods setMinutesPerDay
, setMinutesPerWeek
, setMinutesPerMonth
and setMinutesPerYear
have been deprecated, use setCalendarMinutesPerDay
, setCalendarMinutesPerWeek
, setCalendarMinutesPerMonth
and setCalendarMinutesPerYear
instead.setResource
has been deprecated and will not be replaced. Use the Resource method setCalendar
or setCalendarUniqueID
to link a calendar with a resource.getResource
has been deprecated. Use the getResources
method instead to retrieve all resources linked with a calendar.Resource
methods addResourceCalendar
, setResourceCalendar
, getResourceCalendar
, setResourceCalendarUniqueID
and getResourceCalendarUniqueID
have been deprecated and replaced by addCalendar
, setCalendar
, getCalendar
, setCalendarUniqueID
and getCalendarUniqueID
respectively."},{"location":"CHANGELOG/#1020-2022-03-06","title":"10.2.0 (2022-03-06)","text":"
StructuredTextParser
to replace original code handling calendar data, project properties and curve data read from XER files and Primavera databases. Can also be used to extract data from Primavera Layout Files (PLF)."},{"location":"CHANGELOG/#1010-2022-01-29","title":"10.1.0 (2022-01-29)","text":"
"},{"location":"CHANGELOG/#1005-2022-01-11","title":"10.0.5 (2022-01-11)","text":"
Task.getActivityCodes()
returns an empty list rather than null
when no activity code values have been assigned."},{"location":"CHANGELOG/#1004-2022-01-07","title":"10.0.4 (2022-01-07)","text":"
ProjectCleanUtility
to provide a \"replace\" strategy alongside the original \"redact\" strategy."},{"location":"CHANGELOG/#1003-2021-12-22","title":"10.0.3 (2021-12-22)","text":"
"},{"location":"CHANGELOG/#1002-2021-12-16","title":"10.0.2 (2021-12-16)","text":"
"},{"location":"CHANGELOG/#1001-2021-12-10","title":"10.0.1 (2021-12-10)","text":"
"},{"location":"CHANGELOG/#1000-2021-12-01","title":"10.0.0 (2021-12-01)","text":"
net45
) and .NET Core 3.1 (netcoreapp3.1
)"},{"location":"CHANGELOG/#983-2021-11-30","title":"9.8.3 (2021-11-30)","text":"
"},{"location":"CHANGELOG/#982-2021-11-01","title":"9.8.2 (2021-11-01)","text":"
"},{"location":"CHANGELOG/#981-2021-10-13","title":"9.8.1 (2021-10-13)","text":"
"},{"location":"CHANGELOG/#980-2021-09-30","title":"9.8.0 (2021-09-30)","text":"
"},{"location":"CHANGELOG/#970-2021-09-28","title":"9.7.0 (2021-09-28)","text":"
"},{"location":"CHANGELOG/#960-2021-09-13","title":"9.6.0 (2021-09-13)","text":"
"},{"location":"CHANGELOG/#952-2021-08-22","title":"9.5.2 (2021-08-22)","text":"
"},{"location":"CHANGELOG/#951-2021-07-01","title":"9.5.1 (2021-07-01)","text":"
"},{"location":"CHANGELOG/#950-2021-06-30","title":"9.5.0 (2021-06-30)","text":"
"},{"location":"CHANGELOG/#940-2021-06-11","title":"9.4.0 (2021-06-11)","text":"
"},{"location":"CHANGELOG/#931-2021-05-18","title":"9.3.1 (2021-05-18)","text":"
"},{"location":"CHANGELOG/#930-2021-05-06","title":"9.3.0 (2021-05-06)","text":"
"},{"location":"CHANGELOG/#926-2021-04-26","title":"9.2.6 (2021-04-26)","text":"
"},{"location":"CHANGELOG/#925-2021-04-20","title":"9.2.5 (2021-04-20)","text":"
"},{"location":"CHANGELOG/#924-2021-04-09","title":"9.2.4 (2021-04-09)","text":"
"},{"location":"CHANGELOG/#923-2021-04-08","title":"9.2.3 (2021-04-08)","text":"
"},{"location":"CHANGELOG/#922-2021-04-07","title":"9.2.2 (2021-04-07)","text":"
"},{"location":"CHANGELOG/#921-2021-04-04","title":"9.2.1 (2021-04-04)","text":"
"},{"location":"CHANGELOG/#920-2021-03-30","title":"9.2.0 (2021-03-30)","text":"
"},{"location":"CHANGELOG/#910-2021-03-11","title":"9.1.0 (2021-03-11)","text":"
"},{"location":"CHANGELOG/#900-2020-02-18","title":"9.0.0 (2020-02-18)","text":"
"},{"location":"CHANGELOG/#851-2021-01-07","title":"8.5.1 (2021-01-07)","text":"
"},{"location":"CHANGELOG/#850-2021-01-06","title":"8.5.0 (2021-01-06)","text":"
"},{"location":"CHANGELOG/#840-2020-12-29","title":"8.4.0 (2020-12-29)","text":"
"},{"location":"CHANGELOG/#835-2020-12-15","title":"8.3.5 (2020-12-15)","text":"
"},{"location":"CHANGELOG/#834-2020-12-10","title":"8.3.4 (2020-12-10)","text":"
"},{"location":"CHANGELOG/#833-2020-11-24","title":"8.3.3 (2020-11-24)","text":"
"},{"location":"CHANGELOG/#832-2020-10-22","title":"8.3.2 (2020-10-22)","text":"
"},{"location":"CHANGELOG/#831-2020-10-14","title":"8.3.1 (2020-10-14)","text":"
"},{"location":"CHANGELOG/#830-2020-10-13","title":"8.3.0 (2020-10-13)","text":"
"},{"location":"CHANGELOG/#820-2020-09-09","title":"8.2.0 (2020-09-09)","text":"
"},{"location":"CHANGELOG/#814-2020-08-31","title":"8.1.4 (2020-08-31)","text":"
"},{"location":"CHANGELOG/#813-2020-06-25","title":"8.1.3 (2020-06-25)","text":"
"},{"location":"CHANGELOG/#812-2020-06-18","title":"8.1.2 (2020-06-18)","text":"
"},{"location":"CHANGELOG/#811-2020-06-17","title":"8.1.1 (2020-06-17)","text":"
"},{"location":"CHANGELOG/#810-2020-06-11","title":"8.1.0 (2020-06-11)","text":"
"},{"location":"CHANGELOG/#808-2020-04-20","title":"8.0.8 (2020-04-20)","text":"
"},{"location":"CHANGELOG/#807-2020-04-17","title":"8.0.7 (2020-04-17)","text":"
"},{"location":"CHANGELOG/#806-2020-03-05","title":"8.0.6 (2020-03-05)","text":"
"},{"location":"CHANGELOG/#805-2020-02-07","title":"8.0.5 (2020-02-07)","text":"
"},{"location":"CHANGELOG/#804-2020-02-06","title":"8.0.4 (2020-02-06)","text":"
"},{"location":"CHANGELOG/#803-2020-01-27","title":"8.0.3 (2020-01-27)","text":"
"},{"location":"CHANGELOG/#802-2020-01-16","title":"8.0.2 (2020-01-16)","text":"
"},{"location":"CHANGELOG/#801-2020-01-05","title":"8.0.1 (2020-01-05)","text":"
"},{"location":"CHANGELOG/#800-2020-01-02","title":"8.0.0 (2020-01-02)","text":"
"},{"location":"CHANGELOG/#798-2019-12-27","title":"7.9.8 (2019-12-27)","text":"
"},{"location":"CHANGELOG/#797-2019-11-25","title":"7.9.7 (2019-11-25)","text":"
"},{"location":"CHANGELOG/#796-2019-11-22","title":"7.9.6 (2019-11-22)","text":"
"},{"location":"CHANGELOG/#795-2019-11-19","title":"7.9.5 (2019-11-19)","text":"
"},{"location":"CHANGELOG/#794-2019-11-08","title":"7.9.4 (2019-11-08)","text":"
"},{"location":"CHANGELOG/#793-2019-09-10","title":"7.9.3 (2019-09-10)","text":"
"},{"location":"CHANGELOG/#792-2019-08-19","title":"7.9.2 (2019-08-19)","text":"
"},{"location":"CHANGELOG/#791-2019-07-01","title":"7.9.1 (2019-07-01)","text":"
"},{"location":"CHANGELOG/#790-2019-07-01","title":"7.9.0 (2019-07-01)","text":"
"},{"location":"CHANGELOG/#784-2019-06-27","title":"7.8.4 (2019-06-27)","text":"
"},{"location":"CHANGELOG/#783-2019-05-24","title":"7.8.3 (2019-05-24)","text":"
"},{"location":"CHANGELOG/#782-2019-05-19","title":"7.8.2 (2019-05-19)","text":"
"},{"location":"CHANGELOG/#781-2019-02-13","title":"7.8.1 (2019-02-13)","text":"
"},{"location":"CHANGELOG/#780-2019-01-18","title":"7.8.0 (2019-01-18)","text":"
"},{"location":"CHANGELOG/#771-2018-10-23","title":"7.7.1 (2018-10-23)","text":"
"},{"location":"CHANGELOG/#770-2018-10-12","title":"7.7.0 (2018-10-12)","text":"
"},{"location":"CHANGELOG/#763-2018-10-04","title":"7.6.3 (2018-10-04)","text":"
"},{"location":"CHANGELOG/#762-2018-08-30","title":"7.6.2 (2018-08-30)","text":"
"},{"location":"CHANGELOG/#761-2018-08-29","title":"7.6.1 (2018-08-29)","text":"
"},{"location":"CHANGELOG/#760-2018-07-13","title":"7.6.0 (2018-07-13)","text":"
"},{"location":"CHANGELOG/#750-2018-06-19","title":"7.5.0 (2018-06-19)","text":"
"},{"location":"CHANGELOG/#744-2018-06-06","title":"7.4.4 (2018-06-06)","text":"
"},{"location":"CHANGELOG/#743-2018-05-25","title":"7.4.3 (2018-05-25)","text":"
"},{"location":"CHANGELOG/#742-2018-04-30","title":"7.4.2 (2018-04-30)","text":"
"},{"location":"CHANGELOG/#741-2018-04-16","title":"7.4.1 (2018-04-16)","text":"
"},{"location":"CHANGELOG/#740-2018-03-23","title":"7.4.0 (2018-03-23)","text":"
"},{"location":"CHANGELOG/#730-2018-03-12","title":"7.3.0 (2018-03-12)","text":"
"},{"location":"CHANGELOG/#721-2018-01-26","title":"7.2.1 (2018-01-26)","text":"
"},{"location":"CHANGELOG/#720-2018-01-18","title":"7.2.0 (2018-01-18)","text":"
"},{"location":"CHANGELOG/#710-2018-01-03","title":"7.1.0 (2018-01-03)","text":"
"},{"location":"CHANGELOG/#703-2017-12-21","title":"7.0.3 (2017-12-21)","text":"
"},{"location":"CHANGELOG/#702-2017-11-20","title":"7.0.2 (2017-11-20)","text":"
"},{"location":"CHANGELOG/#701-2017-11-20","title":"7.0.1 (2017-11-20)","text":"
"},{"location":"CHANGELOG/#700-2017-11-08","title":"7.0.0 (2017-11-08)","text":"
"},{"location":"CHANGELOG/#621-2017-10-11","title":"6.2.1 (2017-10-11)","text":"
"},{"location":"CHANGELOG/#620-2017-10-06","title":"6.2.0 (2017-10-06)","text":"
"},{"location":"CHANGELOG/#612-2017-09-12","title":"6.1.2 (2017-09-12)","text":"
"},{"location":"CHANGELOG/#611-2017-08-30","title":"6.1.1 (2017-08-30)","text":"
"},{"location":"CHANGELOG/#610-2017-07-28","title":"6.1.0 (2017-07-28)","text":"
"},{"location":"CHANGELOG/#600-2017-07-22","title":"6.0.0 (2017-07-22)","text":"
"},{"location":"CHANGELOG/#5140-2017-07-13","title":"5.14.0 (2017-07-13)","text":"
"},{"location":"CHANGELOG/#5130-2017-06-27","title":"5.13.0 (2017-06-27)","text":"
"},{"location":"CHANGELOG/#5120-2017-06-26","title":"5.12.0 (2017-06-26)","text":"
"},{"location":"CHANGELOG/#5110-2017-06-20","title":"5.11.0 (2017-06-20)","text":"
"},{"location":"CHANGELOG/#5100-2017-05-23","title":"5.10.0 (2017-05-23)","text":"
"},{"location":"CHANGELOG/#590-2017-04-27","title":"5.9.0 (2017-04-27)","text":"
"},{"location":"CHANGELOG/#580-2017-04-21","title":"5.8.0 (2017-04-21)","text":"
"},{"location":"CHANGELOG/#571-2017-03-22","title":"5.7.1 (2017-03-22)","text":"
"},{"location":"CHANGELOG/#570-2017-03-20","title":"5.7.0 (2017-03-20)","text":"
"},{"location":"CHANGELOG/#565-2017-03-07","title":"5.6.5 (2017-03-07)","text":"
"},{"location":"CHANGELOG/#564-2017-02-16","title":"5.6.4 (2017-02-16)","text":"
"},{"location":"CHANGELOG/#563-2017-02-08","title":"5.6.3 (2017-02-08)","text":"
"},{"location":"CHANGELOG/#562-2017-02-06","title":"5.6.2 (2017-02-06)","text":"
"},{"location":"CHANGELOG/#561-2017-02-03","title":"5.6.1 (2017-02-03)","text":"
"},{"location":"CHANGELOG/#560-2017-01-29","title":"5.6.0 (2017-01-29)","text":"
"},{"location":"CHANGELOG/#559-2017-01-27","title":"5.5.9 (2017-01-27)","text":"
"},{"location":"CHANGELOG/#558-2017-01-23","title":"5.5.8 (2017-01-23)","text":"
"},{"location":"CHANGELOG/#557-2017-01-13","title":"5.5.7 (2017-01-13)","text":"
"},{"location":"CHANGELOG/#556-2017-01-06","title":"5.5.6 (2017-01-06)","text":"
"},{"location":"CHANGELOG/#555-2017-01-06","title":"5.5.5 (2017-01-06)","text":"
"},{"location":"CHANGELOG/#554-2016-12-01","title":"5.5.4 (2016-12-01)","text":"
"},{"location":"CHANGELOG/#553-2016-11-29","title":"5.5.3 (2016-11-29)","text":"
"},{"location":"CHANGELOG/#552-2016-11-02","title":"5.5.2 (2016-11-02)","text":"
"},{"location":"CHANGELOG/#551-2016-10-14","title":"5.5.1 (2016-10-14)","text":"
"},{"location":"CHANGELOG/#550-2016-10-13","title":"5.5.0 (2016-10-13)","text":"
"},{"location":"CHANGELOG/#540-2016-10-06","title":"5.4.0 (2016-10-06)","text":"
"},{"location":"CHANGELOG/#533-2016-08-31","title":"5.3.3 (2016-08-31)","text":"
"},{"location":"CHANGELOG/#532-2016-08-31","title":"5.3.2 (2016-08-31)","text":"
"},{"location":"CHANGELOG/#531-2016-07-01","title":"5.3.1 (2016-07-01)","text":"
"},{"location":"CHANGELOG/#530-2016-06-10","title":"5.3.0 (2016-06-10)","text":"
"},{"location":"CHANGELOG/#522-2016-03-11","title":"5.2.2 (2016-03-11)","text":"
"},{"location":"CHANGELOG/#521-2016-02-11","title":"5.2.1 (2016-02-11)","text":"
"},{"location":"CHANGELOG/#520-2016-02-08","title":"5.2.0 (2016-02-08)","text":"
"},{"location":"CHANGELOG/#5118-2016-01-25","title":"5.1.18 (2016-01-25)","text":"
"},{"location":"CHANGELOG/#5117-2015-12-30","title":"5.1.17 (2015-12-30)","text":"
"},{"location":"CHANGELOG/#5116-2015-12-18","title":"5.1.16 (2015-12-18)","text":"
"},{"location":"CHANGELOG/#5115-2015-12-16","title":"5.1.15 (2015-12-16)","text":"
"},{"location":"CHANGELOG/#5114-2015-12-09","title":"5.1.14 (2015-12-09)","text":"
"},{"location":"CHANGELOG/#5113-2015-11-26","title":"5.1.13 (2015-11-26)","text":"
"},{"location":"CHANGELOG/#5112-2015-11-16","title":"5.1.12 (2015-11-16)","text":"
"},{"location":"CHANGELOG/#5111-2015-11-12","title":"5.1.11 (2015-11-12)","text":"
"},{"location":"CHANGELOG/#5110-2015-09-09","title":"5.1.10 (2015-09-09)","text":"
"},{"location":"CHANGELOG/#519-2015-08-29","title":"5.1.9 (2015-08-29)","text":"
"},{"location":"CHANGELOG/#518-2015-07-13","title":"5.1.8 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#517-2015-07-13","title":"5.1.7 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#516-2015-07-13","title":"5.1.6 (2015-07-13)","text":"
"},{"location":"CHANGELOG/#515-2015-06-05","title":"5.1.5 (2015-06-05)","text":"
"},{"location":"CHANGELOG/#514-2015-06-03","title":"5.1.4 (2015-06-03)","text":"
"},{"location":"CHANGELOG/#513-2015-05-18","title":"5.1.3 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#512-2015-05-18","title":"5.1.2 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#511-2015-05-18","title":"5.1.1 (2015-05-18)","text":"
"},{"location":"CHANGELOG/#510-2015-05-17","title":"5.1.0 (2015-05-17)","text":"
"},{"location":"CHANGELOG/#500-2015-05-06","title":"5.0.0 (2015-05-06)","text":"
"},{"location":"CHANGELOG/#476-2015-03-18","title":"4.7.6 (2015-03-18)","text":"
"},{"location":"CHANGELOG/#475-2015-02-27","title":"4.7.5 (2015-02-27)","text":"
"},{"location":"CHANGELOG/#474-2015-02-25","title":"4.7.4 (2015-02-25)","text":"
"},{"location":"CHANGELOG/#473-2014-12-23","title":"4.7.3 (2014-12-23)","text":"
"},{"location":"CHANGELOG/#472-2014-12-15","title":"4.7.2 (2014-12-15)","text":"
"},{"location":"CHANGELOG/#471-2014-12-08","title":"4.7.1 (2014-12-08)","text":"
"},{"location":"CHANGELOG/#470-2014-12-04","title":"4.7.0 (2014-12-04)","text":"
"},{"location":"CHANGELOG/#462-2014-11-11","title":"4.6.2 (2014-11-11)","text":"
"},{"location":"CHANGELOG/#461-2014-10-17","title":"4.6.1 (2014-10-17)","text":"
"},{"location":"CHANGELOG/#460-2014-10-17","title":"4.6.0 (2014-10-17)","text":"
"},{"location":"CHANGELOG/#450-2014-03-01","title":"4.5.0 (2014-03-01)","text":"
"},{"location":"CHANGELOG/#440-2013-03-14","title":"4.4.0 (2013-03-14)","text":"
"},{"location":"CHANGELOG/#430-2012-02-08","title":"4.3.0 (2012-02-08)","text":"
"},{"location":"CHANGELOG/#420-2011-06-23","title":"4.2.0 (2011-06-23)","text":"
"},{"location":"CHANGELOG/#410-2011-05-30","title":"4.1.0 (2011-05-30)","text":"
"},{"location":"CHANGELOG/#400-2010-05-25","title":"4.0.0 (2010-05-25)","text":"
"},{"location":"CHANGELOG/#320-2010-01-20","title":"3.2.0 (2010-01-20)","text":"
"},{"location":"CHANGELOG/#310-2009-05-20","title":"3.1.0 (2009-05-20)","text":"
"},{"location":"CHANGELOG/#300-2009-01-25","title":"3.0.0 (2009-01-25)","text":"
"},{"location":"CHANGELOG/#210-2008-03-23","title":"2.1.0 (2008-03-23)","text":"
"},{"location":"CHANGELOG/#200-2007-10-07","title":"2.0.0 (2007-10-07)","text":"
"},{"location":"CHANGELOG/#100-2007-08-30","title":"1.0.0 (2007-08-30)","text":"
"},{"location":"CHANGELOG/#092-2006-03-07","title":"0.9.2 (2006-03-07)","text":"
"},{"location":"CHANGELOG/#091-2006-01-26","title":"0.9.1 (2006-01-26)","text":"
"},{"location":"CHANGELOG/#0025-2005-08-11","title":"0.0.25 (2005-08-11)","text":"
"},{"location":"CHANGELOG/#0024-2005-01-10","title":"0.0.24 (2005-01-10)","text":"
"},{"location":"CHANGELOG/#0023-2004-11-17","title":"0.0.23 (2004-11-17)","text":"
"},{"location":"CHANGELOG/#0022-2004-07-27","title":"0.0.22 (2004-07-27)","text":"
"},{"location":"CHANGELOG/#0021-2004-05-06","title":"0.0.21 (2004-05-06)","text":"
"},{"location":"CHANGELOG/#0020-2004-03-15","title":"0.0.20 (2004-03-15)","text":"
"},{"location":"CHANGELOG/#0019-2003-12-02","title":"0.0.19 (2003-12-02)","text":"
"},{"location":"CHANGELOG/#0018-2003-11-13","title":"0.0.18 (2003-11-13)","text":"
"},{"location":"CHANGELOG/#0017-2003-08-05","title":"0.0.17 (2003-08-05)","text":"
"},{"location":"CHANGELOG/#0016-2003-07-04","title":"0.0.16 (2003-07-04)","text":"
"},{"location":"CHANGELOG/#0015-2003-06-17","title":"0.0.15 (2003-06-17)","text":"
"},{"location":"CHANGELOG/#0014-2003-05-28","title":"0.0.14 (2003-05-28)","text":"
"},{"location":"CHANGELOG/#0013-2003-05-22","title":"0.0.13 (2003-05-22)","text":"
"},{"location":"CHANGELOG/#0012-2003-05-08","title":"0.0.12 (2003-05-08)","text":"
"},{"location":"CHANGELOG/#0011-2003-04-15","title":"0.0.11 (2003-04-15)","text":"
"},{"location":"CHANGELOG/#0010-2003-04-08","title":"0.0.10 (2003-04-08)","text":"
"},{"location":"CHANGELOG/#009-2003-04-03","title":"0.0.9 (2003-04-03)","text":"
"},{"location":"CHANGELOG/#008-2003-03-27","title":"0.0.8 (2003-03-27)","text":"
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#general-questions","title":"General Questions","text":"
Can I use MPXJ to write MPP files?
Not at present. Although it is technically feasible to generate an MPP file, the knowledge we have of the file structure is still relatively incomplete, despite the amount of data we are able to correctly extract. It is therefore likely to take a considerable amount of development effort to make this work, and it is conceivable that we will not be able to write the full set of attributes that MPXJ supports back into the MPP file - simply because we don't understand the format well enough. You are therefore probably better off using MSPDI which does support the full range of data items present in an MPP file.
I'm generating output using MPXJ, and when my end users open the file in Microsoft Project, I want to control the appearance of the project data that they see. Can I do this with MPXJ?
In short, the answer to this question is no. The only file format which allows you to control the appearance of project data when opened in Microsoft Project is MPP. Just to clarify, visual appearance in this context refers to the view that appears when the project opens, the filtering applied to the view, the table data visible, the columns in the table, bar styles, text styles and so on. While MPXJ can read this information from an MPP file, none of the supported output file formats contain these attributes.
When I double click on an MPX file to open it in Microsoft Project, I end up with two copies of the file open. What's happening?
This isn't an issue with MPXJ - but we have an answer for you anyway! The problem is caused by an incorrect setting in Microsoft Windows which controls the way MPX files are opened. To fix the setting, open the Control Panel and click on the \"Folder Options\" icon. Select the \"File Types\" tab and scroll down the list of file types until you find an entry for MPX. Once you have found the entry for MPX, click on it to highlight it, then press the \"Advanced\" button at the bottom right hand side of the dialog. In the list of actions that you are now presented with, click on the word \"open\" to highlight it, then click the \"Edit\" button on the right hand side of the dialog. Finally, ensure that the \"Use DDE\" check box is not checked, and you can now finish by clicking OK on each of the open dialogs to dismiss them. You should now find that double clicking on an MPX file will now only open one copy of the file in Microsoft Project.
I use a version of Java older than Java 8, can I use MPXJ?
The last version of MPXJ which supports versions of Java prior to Java 8 is version 7.9.8.
I use a Java 1.4 JVM, but MPXJ is built with a later version of Java, is there anything I can do which will allow me to use it?
Yes there is. Assuming you are using a version of MPXJ prior to 8.0.0, try using Retroweaver.
"},{"location":"faq/#known-issues-with-mpxj","title":"Known Issues with MPXJ","text":"
I have an MPP file created by MS Project 98, and some Flag field values are incorrect.
The MPP8 file format is rather cryptic, and one part of it that I have yet to really understand fully is how the Flag fields are stored. I've spent a lot of time looking at this and have not made a lot of progress, so at the moment no further work is being undertaken to fix this. Contributions of insights, knowledge or fixed code for this problem are welcome. You'll find a bug for this item logged in the SourgeForge bug tracker.
When I read an MPP file I sometimes see an extra task or resource record.
What you are seeing are \"hidden\" tasks and resources which newer versions of Microsoft Project appear to use as placeholders for summary information about all of the tasks and all of the resources in a project. We're not sure exactly which versions of Project hold data like this, although we think this is only relevant for the MPP9 and MPP12 file formats. We've also noticed that the information in these hidden tasks and resources may not be reliable, so don't place too much emphasis on them in your application.
You can ignore the first resource if it has a null value as its name. The attributes of this resource should actually be a summary of all of the resource combined, e.g. utilisation, actual work, remaining work and so on for the complete set of \"real\" resources.
You can ignore the first task if it has an outline level of zero, this task will be a summary of all the \"real\" tasks in the project. You may also find that the name of this task matches the name of the project.
My localised version of MS Project won't read the MPX files created by MPXJ, or MPXJ won't read the MPX files written by my localised version of MS Project.
Localised versions of MS Project (i.e. those which have been translated for use in a non-English locale) read and write MPX files which include localised text strings. The end result of this is that an English/International version of MS Project can't read MPX files produced by a localised version of MS Project, and vice versa.
MPXJ supports a small number of non-English locales, and can read and write MPX files correctly for those locales. You can also use MPXJ to translate MPX files from one locale to another. The MPXFile.setLocale() method must be called prior to reading or writing an MPX file in order to set the required locale. By default, MPXJ will always produce MPX files for the International/English locale, regardless of the locale for which your operating system if configured.
Supported locales for MPX files currently include German, Spanish, French, Italian, Portuguese, Swedish, and Simplified Chinese. Producing a translation for your locale is very easy, please contact us for details on how you can help us to do this.
When I write an MPX file, changes to the project header settings I've made seem to be lost, what's happening?
One of the first things the MPXWriter's write method does is to determine the current locale and update various project settings (for example, currency and date formats) to match the selected locale. This behaviour can be changed so that the settings in the project are left unmodified by setting the useLocaleDefaults parameter to false when calling the write method (for versions of MPXJ up to and including 3.0.0) or by calling the method setUseLocaleDefaults on the MPXWriter instance before calling the write method (for versions of MPXJ after 3.0.0).
"},{"location":"faq/#unit-tests","title":"Unit Tests","text":"
I am trying to run the MPXJ unit tests and I'm having problems with failures in JAXB functionality. What's happening?
Older versions of JAXB were known to have issues with the JUnit classloader, so running the JUnit test runner with the -noloading command line option, other taking other steps to disable JUnit classloading was recommended. This problem is not believed to affect the more recent version of JAXB now used by MPXJ.
"},{"location":"faq/#net-core","title":".NET Core","text":"
When using MPXJ from .NET Core I get an error similar to No data is available for encoding 437. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
By default .NET Core does not include all of the character encodings which may be used by MPXJ (and which are present by default in .NET Framework). To resolve this issue add the following to your code:
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);\n
"},{"location":"faq/#log4j2","title":"log4j2","text":"
When you start MPXJ, you may see the following message written to the console:
ERROR StatusLogger Log4j2 could not find a logging implementation.\nPlease add log4j-core to the classpath. Using SimpleLogger to log to the console.\n
MPXJ uses Apache POI to read MPP files. Apache POI uses log4j2 to write log messages. By default the only dependency POI has on log4j2 is to its interfaces. If you're not already using log4j2 as part of your code, and you don't explicitly include the rest of the log4j2 implementation jar files, you'll see the warning message shown above. This message can safely be ignored, it's just telling you that any log messages POI produces will be written to the console. If you would like to silence this message, you can supply the following argument to the JVM:
-Dlog4j2.loggerContextFactory=org.apache.logging.log4j.simple.SimpleLoggerContextFactory\n
If you are using the Python version of MPXJ, you can provide the argument as shown below when you initialize jpype
.
jpype.startJVM(\"-Dlog4j2.loggerContextFactory=org.apache.logging.log4j.simple.SimpleLoggerContextFactory\")\n
"},{"location":"field-guide/","title":"Field Guide","text":""},{"location":"field-guide/#field-guide","title":"Field Guide","text":"
The tables below provide an indication of which fields are populated when files of different types are read using MPXJ The tables are not hand-crafted: they have been generated from test data and are therefore may be missing some details.
"},{"location":"field-guide/#project","title":"Project","text":""},{"location":"field-guide/#core-fields","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) AM Text \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Increment \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Increment Based On Selected Activity \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Prefix \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID Suffix \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 Actual Duration \u2713 Actual Start \u2713 Actual Work \u2713 Actuals In Sync \u2713 Application Version \u2713 \u2713 \u2713 \u2713 Author \u2713 \u2713 \u2713 \u2713 \u2713 Auto Add New Resources and Tasks \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Auto Filter \u2713 Auto Link \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Bar Text Date Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calculate Float on Finish Date of Each Project \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calculate Multiple Float Paths \u2713 \u2713 \u2713 Calculate Multiple Float Paths Ending With Activity Unique ID \u2713 Calculate Multiple Paths Using Total Float \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Category \u2713 \u2713 Comments \u2713 \u2713 \u2713 Company \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Compute Start to Start Lag From Early Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Consider Assignments In Other Project With Priority Equal or Higher Than \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Content Status \u2713 Content Type \u2713 Cost \u2713 Creation Date \u2713 \u2713 \u2713 \u2713 \u2713 Critical Activity Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Critical Slack Limit \u2713 \u2713 Currency Code \u2713 \u2713 Currency Digits \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Currency Symbol \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Currency Symbol Position \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Current Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Custom Properties \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Order \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Date Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Days per Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Decimal Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Duration Is Fixed \u2713 Default End Time \u2713 \u2713 \u2713 \u2713 \u2713 Default Overtime Rate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Standard Rate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Start Time \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Default Work Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Document Version \u2713 Duration \u2713 \u2713 Earned Value Method \u2713 Editable Actual Costs \u2713 \u2713 Editing Time \u2713 Export Flag \u2713 \u2713 Extended Creation Date \u2713 File Application \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 File Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fiscal Year Start \u2713 Fiscal Year Start Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Full Application Name \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Honor Constraints \u2713 \u2713 \u2713 Hyperlink Base \u2713 Ignore Relationships To And From Other Projects \u2713 Inserted Projects Like Summary \u2713 Keywords \u2713 \u2713 \u2713 Language \u2713 Last Author \u2713 Last Printed \u2713 Last Saved \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level All Resources \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level Resources Only Within Activity Total Float \u2713 \u2713 Leveling Priorities \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Limit Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Location Unique ID \u2713 MPP File Type \u2713 MPX Code Page \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX Delimiter \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX File Version \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 MPX Program Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Manager \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Maximum Percentage to Overallocate Resources \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Microsoft Project Server URL \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Day \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Month \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Week \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Minutes per Year \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Multiple Critical Paths \u2713 \u2713 Must Finish By \u2713 \u2713 Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Task Start Is Project Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Tasks Are Effort Driven \u2713 \u2713 New Tasks Are Manual \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 New Tasks Estimated \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 PM Text \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Percentage Complete \u2713 Planned Start \u2713 \u2713 \u2713 Presentation Format \u2713 Preserve Minimum Float When Leveling \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Preserve Scheduled Early and Late Dates \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Project Externally Edited \u2713 Project File Path \u2713 Project ID \u2713 \u2713 \u2713 Project Title \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Relationship Lag Calendar \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resource Pool File \u2713 Revision \u2713 \u2713 Schedule From \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Scheduled Finish \u2713 \u2713 \u2713 Short Application Name \u2713 Show Project Summary Task \u2713 Split In Progress Tasks \u2713 \u2713 \u2713 \u2713 Start Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 Status Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Subject \u2713 \u2713 \u2713 \u2713 Template \u2713 Thousands Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Time Format \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Time Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Total Slack Calculation Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 Updating Task Status Updates Resource Status \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Use Expected Finish Dates \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 WBS Code Separator \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Week Start Day \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 When Scheduling Progressed Activities Use \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work \u2713 Work 2 \u2713"},{"location":"field-guide/#baseline-fields","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Date \u2713 Baseline2 Date \u2713 Baseline3 Date \u2713 Baseline4 Date \u2713 Baseline5 Date \u2713 Baseline6 Date \u2713 Baseline7 Date \u2713 Baseline8 Date \u2713 Baseline9 Date \u2713 Baseline10 Date \u2713 Baseline Calendar Name \u2713 \u2713 Baseline Cost \u2713 Baseline Date \u2713 Baseline Duration \u2713 Baseline Finish \u2713 \u2713 Baseline Project Unique ID \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 Baseline Type Name \u2713 Baseline Work \u2713 Last Baseline Update Date \u2713"},{"location":"field-guide/#task","title":"Task","text":""},{"location":"field-guide/#core-fields_1","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) % Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 % Work Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 ACWP \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity Codes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Activity Status \u2713 \u2713 \u2713 Activity Type \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Duration Units \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work (Labor) \u2713 \u2713 \u2713 Actual Work (Nonlabor) \u2713 \u2713 \u2713 Actual Work Protected \u2713 Bar Name \u2713 Bid Item \u2713 Board Status ID \u2713 Budget Cost \u2713 Budget Work \u2713 CV \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Category of Work \u2713 Complete Through \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Constraint Date \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Constraint Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Contact \u2713 \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Critical \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Deadline \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Department \u2713 Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Duration Units \u2713 Duration Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Early Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Early Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Earned Value Method \u2713 Effort Driven \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Estimated \u2713 \u2713 \u2713 \u2713 Expanded \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Expected Finish \u2713 \u2713 Expense Items \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 External Early Start \u2713 \u2713 External Late Finish \u2713 \u2713 External Project \u2713 \u2713 External Task \u2713 \u2713 Feature of Work \u2713 Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fixed Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Fixed Cost Accrual \u2713 \u2713 \u2713 Free Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Hammock Code \u2713 Hide Bar \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink SubAddress \u2713 ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Ignore Resource Calendar \u2713 \u2713 \u2713 \u2713 \u2713 Late Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Late Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Level Assignments \u2713 \u2713 \u2713 Leveling Can Split \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 \u2713 Longest Path \u2713 \u2713 Mail \u2713 Manager \u2713 Manual Duration \u2713 \u2713 Manual Duration Units \u2713 Marked \u2713 \u2713 Milestone \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Null \u2713 \u2713 \u2713 Outline Level \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Outline Number \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Overall Percent Complete \u2713 Overallocated \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Work \u2713 Parent Task Unique ID \u2713 Percent Complete Type \u2713 \u2713 \u2713 Phase of Work \u2713 Physical % Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Planned Cost \u2713 \u2713 \u2713 Planned Duration \u2713 \u2713 \u2713 \u2713 Planned Finish \u2713 \u2713 \u2713 \u2713 Planned Start \u2713 \u2713 \u2713 \u2713 Planned Work \u2713 \u2713 \u2713 Planned Work (Labor) \u2713 \u2713 \u2713 Planned Work (Nonlabor) \u2713 \u2713 \u2713 Preleveled Finish \u2713 \u2713 \u2713 Preleveled Start \u2713 \u2713 \u2713 Primary Resource Unique ID \u2713 \u2713 \u2713 Priority \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Project \u2713 \u2713 \u2713 \u2713 \u2713 Recalc Outline Codes \u2713 Recurring \u2713 \u2713 \u2713 Recurring Data \u2713 Regular Work \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Early Finish \u2713 \u2713 \u2713 Remaining Early Start \u2713 \u2713 \u2713 Remaining Late Finish \u2713 \u2713 \u2713 Remaining Late Start \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Work (Labor) \u2713 \u2713 \u2713 Remaining Work (Nonlabor) \u2713 \u2713 \u2713 Resource Names \u2713 \u2713 Responsibility Code \u2713 Resume \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resume No Earlier Than \u2713 Resume Valid \u2713 Rollup \u2713 \u2713 \u2713 \u2713 Scheduled Duration \u2713 Scheduled Finish \u2713 Scheduled Start \u2713 Secondary Constraint Date \u2713 \u2713 Secondary Constraint Type \u2713 \u2713 Section \u2713 Sequence Number \u2713 \u2713 \u2713 Splits \u2713 \u2713 Sprint ID \u2713 Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Steps \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 \u2713 Subproject File \u2713 \u2713 \u2713 Subproject GUID \u2713 Subproject Task ID \u2713 \u2713 Subproject Task Unique ID \u2713 Subproject Tasks Unique ID Offset \u2713 Summary \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Summary Progress \u2713 Suspend Date \u2713 \u2713 Task Calendar GUID \u2713 Task Mode \u2713 \u2713 Task Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Total Slack \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID Successors \u2713 WBS \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_1","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Duration \u2713 \u2713 \u2713 \u2713 Baseline1 Duration Units \u2713 Baseline1 Estimated Duration \u2713 Baseline1 Estimated Finish \u2713 Baseline1 Estimated Start \u2713 Baseline1 Finish \u2713 \u2713 \u2713 \u2713 Baseline1 Fixed Cost \u2713 Baseline1 Fixed Cost Accrual \u2713 Baseline1 Start \u2713 \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Duration \u2713 \u2713 \u2713 Baseline2 Duration Units \u2713 Baseline2 Estimated Duration \u2713 Baseline2 Estimated Finish \u2713 Baseline2 Estimated Start \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Fixed Cost \u2713 Baseline2 Fixed Cost Accrual \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Duration \u2713 \u2713 \u2713 Baseline3 Duration Units \u2713 Baseline3 Estimated Duration \u2713 Baseline3 Estimated Finish \u2713 Baseline3 Estimated Start \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Fixed Cost \u2713 Baseline3 Fixed Cost Accrual \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Duration \u2713 \u2713 \u2713 Baseline4 Duration Units \u2713 Baseline4 Estimated Duration \u2713 Baseline4 Estimated Finish \u2713 Baseline4 Estimated Start \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Fixed Cost \u2713 Baseline4 Fixed Cost Accrual \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Duration \u2713 \u2713 \u2713 Baseline5 Duration Units \u2713 Baseline5 Estimated Duration \u2713 Baseline5 Estimated Finish \u2713 Baseline5 Estimated Start \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Fixed Cost \u2713 Baseline5 Fixed Cost Accrual \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Duration \u2713 \u2713 \u2713 Baseline6 Duration Units \u2713 Baseline6 Estimated Duration \u2713 Baseline6 Estimated Finish \u2713 Baseline6 Estimated Start \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Fixed Cost \u2713 Baseline6 Fixed Cost Accrual \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Duration \u2713 \u2713 \u2713 Baseline7 Duration Units \u2713 Baseline7 Estimated Duration \u2713 Baseline7 Estimated Finish \u2713 Baseline7 Estimated Start \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Fixed Cost \u2713 Baseline7 Fixed Cost Accrual \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Duration \u2713 \u2713 \u2713 Baseline8 Duration Units \u2713 Baseline8 Estimated Duration \u2713 Baseline8 Estimated Finish \u2713 Baseline8 Estimated Start \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Fixed Cost \u2713 Baseline8 Fixed Cost Accrual \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Duration \u2713 \u2713 \u2713 Baseline9 Duration Units \u2713 Baseline9 Estimated Duration \u2713 Baseline9 Estimated Finish \u2713 Baseline9 Estimated Start \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Fixed Cost \u2713 Baseline9 Fixed Cost Accrual \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 \u2713 Baseline10 Deliverable Finish \u2713 Baseline10 Duration \u2713 \u2713 \u2713 \u2713 Baseline10 Duration Units \u2713 Baseline10 Estimated Duration \u2713 Baseline10 Estimated Finish \u2713 Baseline10 Estimated Start \u2713 Baseline10 Finish \u2713 \u2713 \u2713 \u2713 Baseline10 Fixed Cost \u2713 Baseline10 Fixed Cost Accrual \u2713 Baseline10 Start \u2713 \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Deliverable Finish \u2713 Baseline Deliverable Start \u2713 Baseline Duration \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Duration Units \u2713 Baseline Estimated Duration \u2713 Baseline Estimated Finish \u2713 Baseline Estimated Start \u2713 Baseline Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Fixed Cost \u2713 \u2713 \u2713 Baseline Fixed Cost Accrual \u2713 Baseline Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#custom-fields","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 Outline Code8 \u2713 \u2713 Outline Code8 Index \u2713 Outline Code9 \u2713 \u2713 Outline Code9 Index \u2713 Outline Code10 \u2713 \u2713 Outline Code10 Index \u2713 Start1 \u2713 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"field-guide/#enterprise-fields","title":"Enterprise Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Enterprise Data \u2713 Enterprise Duration1 Units \u2713 Enterprise Duration2 Units \u2713 Enterprise Duration3 Units \u2713 Enterprise Duration4 Units \u2713 Enterprise Duration5 Units \u2713 Enterprise Duration6 Units \u2713 Enterprise Duration7 Units \u2713 Enterprise Duration8 Units \u2713 Enterprise Duration9 Units \u2713 Enterprise Duration10 Units \u2713 Enterprise Project Date1 \u2713 Enterprise Project Date2 \u2713 Enterprise Project Date3 \u2713 Enterprise Project Date4 \u2713 Enterprise Project Number2 \u2713 Enterprise Project Number4 \u2713 Enterprise Project Number5 \u2713 Enterprise Project Number22 \u2713 Enterprise Project Text1 \u2713 \u2713 Enterprise Project Text2 \u2713 Enterprise Project Text3 \u2713 Enterprise Project Text4 \u2713 Enterprise Project Text5 \u2713 Enterprise Project Text6 \u2713 Enterprise Project Text8 \u2713 Enterprise Project Text9 \u2713 Enterprise Project Text10 \u2713 Enterprise Project Text11 \u2713 Enterprise Project Text12 \u2713 Enterprise Project Text13 \u2713 Enterprise Project Text14 \u2713 Enterprise Project Text15 \u2713 Enterprise Project Text16 \u2713 Enterprise Project Text17 \u2713 Enterprise Project Text18 \u2713 Enterprise Project Text19 \u2713 Enterprise Project Text21 \u2713 Enterprise Project Text40 \u2713 \u2713"},{"location":"field-guide/#resource","title":"Resource","text":""},{"location":"field-guide/#core-fields_2","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) % Work Complete \u2713 ACWP \u2713 \u2713 Accrue At \u2713 \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Availability Data \u2713 Available From \u2713 Available To \u2713 BCWS \u2713 Base Calendar \u2713 Booking Type \u2713 \u2713 Budget \u2713 \u2713 Budget Cost \u2713 Budget Work \u2713 CV \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Calendar GUID \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Can Level \u2713 \u2713 Code \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Center \u2713 \u2713 Cost Per Use \u2713 Cost Rate A \u2713 Cost Rate B \u2713 Cost Rate C \u2713 Cost Rate D \u2713 Cost Rate E \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Default Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Description \u2713 Email Address \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Generic \u2713 \u2713 Group \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 Hyperlink Address \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink SubAddress \u2713 ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Initials \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Material Label \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Max Units \u2713 Name \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Overallocated \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Rate \u2713 Overtime Rate Units \u2713 Overtime Work \u2713 \u2713 \u2713 Parent ID \u2713 \u2713 \u2713 \u2713 \u2713 Peak \u2713 \u2713 \u2713 \u2713 \u2713 Per Day \u2713 Phone \u2713 Phonetics \u2713 Pool \u2713 Rate \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resource ID \u2713 \u2713 \u2713 \u2713 Role \u2713 \u2713 \u2713 SV \u2713 Sequence Number \u2713 \u2713 \u2713 Standard Rate \u2713 Standard Rate Units \u2713 Subproject Unique Resource ID \u2713 Supply Reference \u2713 Type \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Unit \u2713 Unit of Measure Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Windows User Account \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 Workgroup \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_2","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 Baseline1 Work \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 Baseline2 Work \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 Baseline3 Work \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 Baseline4 Work \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 Baseline5 Work \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 Baseline6 Work \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 Baseline7 Work \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 Baseline8 Work \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 Baseline9 Work \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 Baseline10 Work \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"field-guide/#custom-fields_1","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"field-guide/#enterprise-fields_1","title":"Enterprise Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Enterprise \u2713 \u2713 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 Enterprise Duration2 Units \u2713 Enterprise Duration3 Units \u2713 Enterprise Duration4 Units \u2713 Enterprise Duration5 Units \u2713 Enterprise Duration6 Units \u2713 Enterprise Duration7 Units \u2713 Enterprise Duration8 Units \u2713 Enterprise Duration9 Units \u2713 Enterprise Duration10 Units \u2713 Enterprise Unique ID \u2713"},{"location":"field-guide/#resource-assignment","title":"Resource Assignment","text":""},{"location":"field-guide/#core-fields_3","title":"Core Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) ACWP \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Assignment Delay \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Assignment GUID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Assignment Resource GUID \u2713 Assignment Task GUID \u2713 Assignment Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 BCWS \u2713 Budget Cost \u2713 \u2713 Budget Work \u2713 \u2713 CV \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Confirmed \u2713 Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Cost Account ID \u2713 \u2713 \u2713 Cost Rate Table \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 Created \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 Hyperlink Screen Tip \u2713 Hyperlink Subaddress \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 Leveling Delay Units \u2713 Linked Fields \u2713 Notes \u2713 \u2713 \u2713 Override Rate \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Owner \u2713 Percent Work Complete \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Planned Cost \u2713 \u2713 \u2713 Planned Finish \u2713 \u2713 \u2713 Planned Start \u2713 \u2713 \u2713 Planned Work \u2713 \u2713 \u2713 Rate Index \u2713 \u2713 Rate Source \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Remaining Early Finish \u2713 \u2713 \u2713 Remaining Early Start \u2713 \u2713 \u2713 Remaining Late Finish \u2713 \u2713 Remaining Late Start \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Resource Request Type \u2713 Resource Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Response Pending \u2713 \u2713 Resume \u2713 \u2713 \u2713 Role Unique ID \u2713 \u2713 \u2713 SV \u2713 Start \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 Task Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Team Status Pending \u2713 \u2713 Timephased Actual Overtime Work \u2713 Timephased Actual Work \u2713 Timephased Work \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Variable Rate Units \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Contour \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713"},{"location":"field-guide/#baseline-fields_3","title":"Baseline Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 Baseline Finish \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713 Timephased Baseline1 Cost \u2713 Timephased Baseline1 Work \u2713 Timephased Baseline2 Cost \u2713 Timephased Baseline2 Work \u2713 Timephased Baseline3 Cost \u2713 Timephased Baseline3 Work \u2713 Timephased Baseline4 Cost \u2713 Timephased Baseline4 Work \u2713 Timephased Baseline5 Cost \u2713 Timephased Baseline5 Work \u2713 Timephased Baseline6 Cost \u2713 Timephased Baseline6 Work \u2713 Timephased Baseline7 Cost \u2713 Timephased Baseline7 Work \u2713 Timephased Baseline8 Cost \u2713 Timephased Baseline8 Work \u2713 Timephased Baseline9 Cost \u2713 Timephased Baseline9 Work \u2713 Timephased Baseline10 Cost \u2713 Timephased Baseline10 Work \u2713 Timephased Baseline Cost \u2713 Timephased Baseline Work \u2713"},{"location":"field-guide/#custom-fields_2","title":"Custom Fields","text":"Field Asta (PP) ConceptDraw PROJECT (CDP) Deltek OpenPlan (BK3) FastTrack (FTS) GanttDesigner (GNT) GanttProject (GAN) Merlin (SQLITE) Microsoft (MPD) Microsoft (MPP) Microsoft (MPX) Microsoft (MSPDI) P3 (BTRIEVE) Phoenix (PPX) Planner (XML) Primavera (PMXML) Primavera (SQLITE) Primavera (XER) Project Commander (PC) ProjectLibre (POD) SDEF (SDEF) Sage (SCHEDULE_GRID) SureTrak (STW) Synchro (SP) TurboProject (PEP) Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"howto-build/","title":"Building MPXJ","text":"
Although MPXJ can be downloaded as a complete package from Maven, GitHub and SourceForge, the development of the library continues between releases and is driven by user requests for new functionality and bug fixes being applied to existing features. Many MPXJ users will work with and ship software based on intermediate versions of MPXJ built from the code on GitHub in order to take advantage of these enhancements before they become available in an official release. This approach is supported by the fact that code is only pushed to the master branch on GitHub if the suite of regression tests have been completed successfully: therefore the quality of the code taken from GitHub at any point can normally be guaranteed to be as good as that in an official release.
In order to take advantage of MPXJ functionality from GitHub, you will need to understand how to build the library, whether you are using it in the form of a Java JAR or a .NET DLL. The following sections explain how to do this.
"},{"location":"howto-build/#obtaining-the-source","title":"Obtaining the source","text":"
The first step in the process of building your own version of MPXJ is to obtain the latest source from GitHub. Instructions for cloning the repository can be found on this page.
"},{"location":"howto-build/#building-the-java-jar","title":"Building the Java JAR","text":"
MPXJ is built using Maven. Once you have a cloned copy of the MPXJ repository, you may wish to update the groupId
, artifactId
or version
attributes in pom.xml
. This will ensure that there is no confusion between the version of MPXJ you build and the official distributions.
If you have a copy of Maven installed, you can issue the following command to build MPXJ:
mvn -DskipTests=true -Dmaven.javadoc.skip=true -Dsource.skip=true package\n
This will generate the mpxj.jar
for you in the Maven target directory, and copies MPXJ's dependencies to the lib
directory. Note that for convenience this skips running the unit tests, javadoc generation and source packaging.
If you are using Maven to manage dependencies for your own project, you can install your newly built version of MPXJ in a local Maven repository:
mvn -DskipTests=true -Dmaven.javadoc.skip=true -Dsource.skip=true install\n
"},{"location":"howto-build/#building-the-net-dlls","title":"Building the .NET DLLs","text":"
Building the .NET versions of MPXJ uses an Ant script to first run Maven to create the Java version, then run IKVM to create a .Net Framework and a .Net Core version.
build.xml
file and ensure that the property named ikvm.net45.dir
is set to point to the location where you have unzipped IKVM.You can now issue the following command:
ant archive\n
The Ant script will recognise that IKVM is present and build the .NET Framework version of MPXJ, with the results found in the src.net\\lib\\net45
folder.
"},{"location":"howto-build/#generating-the-jaxb-code","title":"Generating the JAXB code","text":"
In order to read and write various XML file formats, MPXJ relies on code generated by the JAXB tool xjc
from the XML schema for each file format. Normally you will not need to regenerate this source, but if you are changing the JAXB implementation, or modifying the use of JAXB in some way, then you may need to regenerate this code.
Where I have created an XML schema to support a particular file format, I have included it in the MPXJ distribution in the jaxb
directory. For XML schemas published by product vendors, I have included a note on the home page indicating where these can be located.
If you obtain a copy of the XML schema file you want to work with, you can update the JAXB source using the xjc
target found in the ant build.xml
file. Note that the xjc
target is platform specific, you will need to change the name of xjc
tool to be xjc.bat
, xjc.exe
, or xjc.sh
depending on your operating system. You will also need to set the properties indicated in build.xml
to tell it where to find xjc
and the XML schema file. If you are only regenerating source for one of the XML schemas, you can comment out the others in the Ant script to avoid unnecessary work.
"},{"location":"howto-com/","title":"Getting Started with COM","text":"
The .Net Framework assemblies provided in the DLLs described here are accessible from COM. This should allow you to, for example, write VBA code which utilises MPXJ functionality. To assist with this, for each of the DLLs distributed with MPXJ type libraries in the form of TLB
files are provided in the src.net\\lib\\net45
directory. You will also need to register the MPXJ assemblies in order to use them from COM, using the regasm
assembly registration tool.
For your convenience two batch files have been provided in the src.net\\lib\\net45
directory: mpxj-register-assemblies.bat
and mpxj-unregister-assemblies.bat
. These batch files will register and unregister the MPXJ assemblies respectively. These batch files assume that regasm
is available on the path.
"},{"location":"howto-convert/","title":"Converting Files","text":"
To convert project data between different formats you read the source data using an appropriate Reader class, then write the data using a Writer class which matches the format you want to convert to.
MPXJ can do a lot of the work for you, as the example below illustrates. The UniversalProjectReader
will detect the type of schedule being read and handle it accordingly. The ProjectWriterUtility
will use the extension of the output file to determine the type of file written.
The extensions recognised by the ProjectWriterUtility
class are:
JavaC#Python
package org.mpxj.howto.convert;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\nimport net.sf.mpxj.writer.ProjectWriter;\nimport net.sf.mpxj.writer.ProjectWriterUtility;\n\npublic class ConvertUniversal\n{\n public void convert(String inputFile, String outputFile) throws Exception\n {\n UniversalProjectReader reader = new UniversalProjectReader();\n ProjectFile projectFile = reader.read(inputFile);\n\n ProjectWriter writer = ProjectWriterUtility.getProjectWriter(outputFile);\n writer.write(projectFile, outputFile);\n }\n}\n
using net.sf.mpxj.reader;\nusing net.sf.mpxj.writer;\n\nnamespace MpxjSamples.HowToConvert;\n\npublic class ConvertUniversal\n{\n public void Convert(string inputFile, string outputFile)\n {\n var reader = new UniversalProjectReader();\n var projectFile = reader.read(inputFile);\n\n var writer = ProjectWriterUtility.getProjectWriter(outputFile);\n writer.write(projectFile, outputFile);\n }\n}\n
import jpype\nimport mpxj\n\njpype.startJVM()\n\nfrom net.sf.mpxj.reader import UniversalProjectReader\nfrom net.sf.mpxj.writer import ProjectWriterUtility\n\ndef convert(input_file, output_file):\n reader = UniversalProjectReader();\n project_file = reader.read(input_file);\n writer = ProjectWriterUtility.getProjectWriter(output_file);\n writer.write(project_file, output_file);\n\njpype.shutdownJVM()\n
If you already know the file types you are converting between, you can use the specific Reader and Writer classes, as shown below.
JavaC#Python
package org.mpxj.howto.convert;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\nimport net.sf.mpxj.mpx.MPXWriter;\nimport net.sf.mpxj.reader.ProjectReader;\nimport net.sf.mpxj.writer.ProjectWriter;\n\npublic class ConvertMppToMpx\n{\n public void convert(String inputFile, String outputFile) throws Exception\n {\n ProjectReader reader = new MPPReader();\n ProjectFile projectFile = reader.read(inputFile);\n\n ProjectWriter writer = new MPXWriter();\n writer.write(projectFile, outputFile);\n }\n}\n
using net.sf.mpxj.mpp;\nusing net.sf.mpxj.mpx;\n\nnamespace MpxjSamples.HowToConvert;\n\npublic class ConvertMppToMpx\n{\n public void Convert(string inputFile, string outputFile)\n {\n var reader = new MPPReader();\n var projectFile = reader.read(inputFile);\n\n var writer = new MPXWriter();\n writer.write(projectFile, outputFile);\n }\n}\n
import jpype\nimport mpxj\n\njpype.startJVM()\n\nfrom net.sf.mpxj.mpp import MPPReader\nfrom net.sf.mpxj.mpx import MPXWriter\n\ndef convert(input_file, output_file):\n reader = MPPReader()\n project_file = reader.read(input_file)\n writer = MPXWriter()\n writer.write(project_file, output_file)\n\njpype.shutdownJVM()\n
"},{"location":"howto-dotnet/","title":"Getting Started with .Net","text":"
MPXJ uses a tool called IKVM to convert the original Java version of MPXJ into .Net assemblies. The MPXJ .Net assemblies provided via NuGet and shipped as part of the MPXJ distribution use a \"legacy\" version of IKVM to do this. The \"modern\" version of IKVM allows .Net assemblies to be generated in a different, and ultimately more future-proof way. However there are, at present, some minor disadvantages to using the approach based on the \"modern\" version of IKVM. These disadvantages are being addressed, and ultimately assemblies produced by the \"modern\" version of IKVM will become the default way to include MPXJ in your project.
"},{"location":"howto-dotnet/#mpxj-assemblies-legacy-ikvm","title":"MPXJ assemblies (legacy IKVM)","text":"
For many people the easiest way to work with MPXJ is to use the assemblies generated by the \"legacy\" version of IKVM. This are available via NuGet and also as part of the zip file distribution from GitHub or SourceForge.
MPXJ ships with a set of .Net Framework and .Net Core assemblies, which are managed for you by NuGet or can be found in the src.net\\lib\\net45
and src.net\\lib\\netcoreapp3.1
folders of the distribution respectively.
There are actually three different .Net DLLs available for MPXJ - you only need one of these:
As noted above, in the \"for C#\" and \"for VB\" versions of the MPXJ DLL, getters and setters have been replaced by properties. For example, where you would have previously written code like this:
String text = task.getText();\ntask.setText(text);\n
Now when you work with the \"for C#\" and \"for VB\" versions of the MPXJ DLL, you'll be able to write code in a more familiar style:
String text = task.Text\ntask.Text = text;\n
Also noted above, in the case of the \"for C#\" MPXJ DLL, method names have been modified to begin with an initial capital, so the code will again have a more familiar style. For example, using the original Java method names you'd write something like this:
Task task = projectFile.addTask();\n
Using the \"for C#\" DLL your code will look like this:
Task task = projectFile.AddTask();\n
Once you have selected the version of the MPXJ DLL most suitable for your project, you will need to add its dependencies. If you are using NuGet to manage your dependencies, this is done for you automatically. If you are managing the dependencies manually, the files you need will all be in the relevant sub folder with the src.net\\lib
folder of the MPXJ distribution.
"},{"location":"howto-dotnet/#mpxj-assemblies-modern-ikvm","title":"MPXJ assemblies (modern IKVM)","text":"
The modern version of IKVM provides an extension to modern SDK-style .Net projects which allows you to refer to a Java library using Maven (probably the most common dependency management solution for Java projects). This means that your .Net project will be working directly with the original Java version of the library, which will automatically be translated into .Net assemblies for you as you build your project.
Note that this build process can be time-consuming when your project is first built using this approach, but the results of this translation will be reused, so subsequent builds will be more rapid. You may also see various transient warning messages as this first build completes. These can be ignored and will disappear once your project has finished building.
To include MPXJ in your project using the modern version of IKVM, edit your project file and include the following lines:
<ItemGroup>\n <PackageReference Include=\"IKVM.Maven.Sdk\" Version=\"1.6.8\" />\n</ItemGroup>\n\n<ItemGroup>\n <MavenReference Include=\"net.sf.mpxj:mpxj\" Version=\"12.8.0\"/>\n</ItemGroup>\n
The first <ItemGroup>
you are adding enables IKVM's Maven integration functionality. The second <ItemGroup>
simply refers to the version of MPXJ you'd like to use from Maven.
The advantages of using MPXJ this way are:
The disadvantages of using MPXJ this way are:
As mentioned earlier, work is underway to provide address these disadvantages by providing a \"wrapper\" assembly which hides the \"Java-ness\" of the original MPXJ library.
"},{"location":"howto-dotnet/#net-samples","title":".Net samples","text":"
MPXJ ships with some sample files which can be found in the src.net\\samples
folder of the distribution. These files illustrate how the MPXJ API can be used to manipulate project data. In particular the MpxjQuery
example shows how various elements which make up the project data can be queried. Two versions of this utility are present in src.net\\samples
, one written in C#, and the other written in Visual Basic (VB) to illustrate the basics of using MPXJ in either language. Even if you are developing software in a .Net language you may still find it useful to refer to the Java examples, and indeed the original Java source of MPXJ, to give you an insight into how the API can be used. There is also a standalone repository containing sample .Net code for MPXJ covering use of the library in more depth. This repository can be found here.
"},{"location":"howto-dotnet/#net-and-java-types","title":".Net and Java types","text":"
The .Net version of MPXJ has been generated directly from the Java version using a tool called IKVM. One of the side effects of using IKVM to perform this conversion is that the MPXJ exposes .Net versions of the original Java data types, so for example you will find that the API returns a type called LocalDateTime
rather than a .Net DateTime
, and collections which don't expose the familiar IEnumerable
interface.
To simplify the translation between Java and .Net types, a set of extension methods have been provided. These are included n the NuGet package, and the source can be found in the src.net\\utilities
folder, in a project called MpxjUtilities
. This project contains extension methods which enhance both Java and .Net classes to make it easier to pass data to and from the API. For example the extension method ToIEnumerable
is added to Java collection data types which allows them to be iterated using the familiar foreach
.Net syntax.
To use these extension methods, simply add a reference to the MpxjUtilities
assembly in your own project. The methods themselves are documented in the source, and examples of their use can be seen in the samples provided in the src.net\\samples
folder.
"},{"location":"howto-dotnet/#mpxj-and-the-gac","title":"MPXJ and the GAC","text":"
For your convenience two batch files are provided in the src.net\\lib\\net45
directory: mpxj-gac-install.bat
and mpxj-gac-uninstall.bat
. These batch files install the MPXJ assemblies into the GAC and uninstall the MPXJ assemblies from the GAC using the gacutil
global assembly cache tool. Note that these batch files assume that gacutil
is available on the path.
"},{"location":"howto-read-asta/","title":"How To: Read Asta Powerproject and Easyproject files","text":"
Asta Powerproject and Asta Easyproject both use PP files.
"},{"location":"howto-read-asta/#reading-pp-files","title":"Reading PP files","text":"
The simplest way to read a PP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pp\");\n
You can work directly with the AstaFileReader
by replacing UniversalProjectReader
with AstaFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the AstaFileReader
class.
"},{"location":"howto-read-conceptdraw/","title":"How To: Read ConceptDraw PROJECT files","text":"
ConceptDraw PROJECT writes CDPX, CPDZ and CPDTZ files.
"},{"location":"howto-read-conceptdraw/#reading-cdpx-cpdz-and-cpdtz-files","title":"Reading CDPX, CPDZ and CPDTZ files","text":"
The simplest way to read a CDPX, CPDZ or CPDTZ file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.cdpx\");\n
You can work directly with the ConceptDrawProjectReader
by replacing UniversalProjectReader
with ConceptDrawProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the ConceptDrawProjectReader
class.
"},{"location":"howto-read-fasttrack/","title":"How To: Read FastTrack Schedule files","text":"
FastTrack Schedule writes schedule data to FTS files. Note that MPXJ has only been tested with FTS files produced by FastTrack 10.
"},{"location":"howto-read-fasttrack/#reading-fts-files","title":"Reading FTS files","text":"
The simplest way to read an FTS file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.fts\");\n
You can work directly with the FastTrackReader
by replacing UniversalProjectReader
with FastTrackReader
, although this offers no particular advantage as there are no additional configuration settings available on the FastTrackReader
class.
"},{"location":"howto-read-ganttdesigner/","title":"How To: Read Gantt Designer files","text":"
Gantt Designer writes schedule data to GNT files.
"},{"location":"howto-read-ganttdesigner/#reading-gnt-files","title":"Reading GNT files","text":"
The simplest way to read a GNT file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.gnt\");\n
You can work directly with the GanttDesignerReader
by replacing UniversalProjectReader
with GanttDesignerReader
, although this offers no particular advantage as there are no additional configuration settings available on the GanttDesignerReader
class.
"},{"location":"howto-read-ganttproject/","title":"How To: Read GanttProject files","text":"
GanttProject writes schedule data to GAN files (which are actually just XML files).
"},{"location":"howto-read-ganttproject/#reading-gan-files","title":"Reading GAN files","text":"
The simplest way to read a GAN file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.gan\");\n
You can work directly with the GanttProjectReader
by replacing UniversalProjectReader
with GanttProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the GanttProjectReader
class.
"},{"location":"howto-read-merlin/","title":"How To: Read Merlin files","text":"
Merlin Project is a Mac application. MPXJ provides experimental support for reading some Merlin Project files. The Merlin file format does not necessarily contain a full set of start and finish dates for each task. Merlin calculates these dates when it displays a schedule. At the moment MPXJ lacks this functionality, so you may not find start and finish dates for each task.
"},{"location":"howto-read-merlin/#reading-merlin-files","title":"Reading Merlin files","text":"
The simplest way to read a Merlin file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample-merlin-project\");\n
Note that on a Mac Merlin projects are not single files, but rather they are directories containing multiple files (the Mac Finder normally hides this from you). When using MPXJ to read a Merlin project you pass the directory name to the UniversalProjectReader
class.
You can work directly with the MerlinReader
by replacing UniversalProjectReader
with MerlinReader
, although this offers no particular advantage as there are no additional configuration settings available on the MerlinReader
class.
"},{"location":"howto-read-mpd/","title":"How To: Read MPD files","text":"
Microsoft Project from Project 98 until Project 2003 could read and write schedules as Microsoft Access database files with the extension MPD. Versions of Microsoft Project after 2003 can import projects from MPD databases but cannot create or write to them. Project 98 crates a database with a schema known as MPD8, which MPXJ does not currently support reading. Project 2000 onward uses a schema call MPD9 which MPXJ can read.
Coincidentally, Microsoft Project Server originally shared the same database schema as the MPD9 file format. This means that the MPDDatabaseReader
class may also be used to read data from a Project Server SQL Server database.
"},{"location":"howto-read-mpd/#reading-mpd-files","title":"Reading MPD files","text":"
The simplest way to read an MPD file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpd\");\n
In order for this to work the UniversalProjectReader
assumes that the JDBC-ODBC bridge driver is available. As an MPD file can contain multiple projects, the UniversalProjectReader
assumes that a single project is present in the file with an ID of 1. This is normally the case when a single project is saved as an MPD file.
"},{"location":"howto-read-mpd/#using-mpddatabasereader","title":"Using MPDDatabaseReader","text":"
You can work directly with the MPDDatabaseReader
class by replacing UniversalProjectReader
with MPDDatabaseReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpd/#setting-the-database-connection","title":"Setting the database connection","text":"
Three read
methods are provided by the MPDDatabaseReader
class which allow you to work directly with an MPD file, either by passing in a file name a File
instance or an InputStream
instance. These methods use the JDBC-ODBC bridge driver to open the database. An alternative approach is for you to provide your own database connection. To that end the MPDDatabaseReader
class provides two additional methods: setConnection
and setDataSource
which allows you to supply a JDBC Connection
instance or a JDBC DataSource
instance.
You can of course use this to set up your own JDBC connection to read from the MDB file, however these methods may be more useful if you wish to read data from a Microsoft Project Server database instance, which shares the same schema as the MDB file.
"},{"location":"howto-read-mpd/#selecting-a-project","title":"Selecting a project","text":"
If the MPD file contains multiple projects, you can retrieve details of the available projects using the listProjects
method. This returns a map of project IDs and project names. The sample code below illustrates how to retrieve this list of projects, and select the specific project that you want to read. In this case we read each project in the file in turn.
import java.util.Map;\nimport java.util.Map.Entry;\nimport net.sf.mpxj.mpd.MPDDatabaseReader;\n\nMPDDatabaseReader reader = new MPDDatabaseReader();\nreader.setConnection(connection);\nMap<Integer, String> projects = reader.listProjects();\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(\"Project name: \" + entry.getValue());\n reader.setProjectID(entry.getKey());\n reader.read();\n}\n
"},{"location":"howto-read-mpp/","title":"How To: Read MPP files","text":"
The native Microsoft Project file format is typically has the extension MPP (or MPT for a template file). Although a common file extension uis used, there are actually a number if different variants of the file format. The list below shows the different variants, and the versions of Microsoft Project which produce them:
"},{"location":"howto-read-mpp/#reading-mpp-files","title":"Reading MPP files","text":"
The simplest way to read an MPP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#using-mppreader","title":"Using MPPReader","text":"
You can work directly with the MPPReader
class by replacing UniversalProjectReader
with MPPReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpp/#password-protected-files","title":"Password Protected Files","text":"
When a read password has been set for an MPP file, the contents of the file are partially encrypted. If you attempt to read an MPP file which has been password protected an MPXJException
will be raised, with the message File is password protected
.
MPXJ only supports decryption of password protected MPP9 files. The code below illustrates how you would supply the password:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPassword(\"my secret password\");\nProjectFile project = reader.read(\"my-sample.mpp\");\n
The encryption used by MPP9 files doesn't actually require the password in order to read the contents of the file. If you wish you can set a flag to ignore the MPP9 password protection.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setRespectPasswordProtection(false);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#presentation-data","title":"Presentation Data","text":"
Alongside the schedule data itself, MPXJ also extracts much of the presentation data available in an MPP file, for example table layouts, filters, graphical indicators and so on. If you are not interested in this type of data, you can tell MPXJ not to read it. This will speed up reading MPP files, and slightly reduce memory consumption. To do this you will use the setReadPresentationData
method, as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPresentationData(false);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#properties-only","title":"Properties Only","text":"
Should you wish to simply \"peek\" at the contents of the MPP file by just reading the summary properties from the file, you can use the setReadPropertiesOnly
method as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setReadPropertiesOnly(true);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpp/#raw-timephased-data","title":"Raw timephased data","text":"
When MPXJ reads timephased data from an MPP file it \"normalises\" the data, converting it from the compact format Microsoft Project uses internally into a representation which shows the timephased values day-by-day. This is generally easier to understand, and can be further processed using the methods in the TimephasedUtility
class to show the data over the required timescale.
If you do not want MPXJ to normalise the data, and would prefer instead to work with the raw data directly from the MPP file, you can use the setUseRawTimephasedData
to do this, as shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpp.MPPReader;\n\n// ...\n\nMPPReader reader = new MPPReader();\nreader.setUseRawTimephasedData(true);\nProjectFile project = reader.read(\"my-sample.mpp\");\n
"},{"location":"howto-read-mpx/","title":"How To: Read MPX files","text":"
Versions of Microsoft Project up to Project 98 could read and write MPX files as a data interchange format. Versions of Project after Project 98 until Project 2010 can only read MPX files. Versions of Microsoft Project after 2010 cannot read MPX files. Other third party project planning applications continue to use MPX as a data interchange format.
"},{"location":"howto-read-mpx/#reading-mpx-files","title":"Reading MPX files","text":"
The simplest way to read an MPX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.mpx\");\n
"},{"location":"howto-read-mpx/#using-mpxreader","title":"Using MPXReader","text":"
You can work directly with the MPXReader
class by replacing UniversalProjectReader
with MPXReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mpx/#locale","title":"Locale","text":"
It appears that very early in the life of the MPX file format, Microsoft Project was internationalised to allow versions of the application to be used in languages other than English. One unfortunate side effect of this was that the text used in the MPX file format was also internationalised. Thus rather than having a single file format which could be exchanged globally between any applications, you now need to know which internationalised version of Microsoft Project was used to create the MPX file in order to read it successfully.
Fortunately in most cases MPX files have been generated using the English language version of Microsoft Project, or an application which generates this variant, so the default settings for MPXReader
will work.
If you encounter an MPX file generated by something other than an English version of Microsoft Project, you'll need to explicitly set the locale in order to read the file. The sample below shows how this is done:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nMPXReader reader = new MPXReader();\nreader.setLocale(Locale.GERMAN);\nProjectFile project = reader.read(\"my-sample.mpx\");\n
The following locales are supported by MPXReader
:
You can retrieve a list of supported locales programmatically using the code shown below:
import net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nLocale[] locales = MPXReader.getSupportedLocales();\n
"},{"location":"howto-read-mpx/#ignore-text-models","title":"Ignore Text Models","text":"
You should not normally need to modify this option.
An MPX file consists of a series of sections with each section representing a specific entity, for example tasks, resources, and so on. The set of attributes written for each entity is not fixed, instead at the start of each section the attributes which appear in the file are listed in two forms: as a series of numeric values, and as a series on human-readable attribute names.
Originally MPXJ used to read both of these lists, however it was found that the human-readable attribute names were often not consistent and caused problems when attempting to read MPX files. The default now is that these attributes are ignored. If for some reason you should wish to enable MPXJ's original behaviour and read these files, you would call setIgnoreTextModels
as shown in the example below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXReader;\n\n// ...\n\nMPXReader reader = new MPXReader();\nreader.setIgnoreTextModels(false);\nProjectFile project = reader.read(\"my-sample.mpx\");\n
"},{"location":"howto-read-mspdi/","title":"How To: Read MSPDI files","text":"
The Microsoft Project Data Interchange (MSPDI) format is an XML file format which Microsoft Project has been able to read and write since Project 2002.
"},{"location":"howto-read-mspdi/#reading-mspdi-files","title":"Reading MSPDI files","text":"
The simplest way to read an MSPDI file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#using-mspdireader","title":"Using MSPDIReader","text":"
You can work directly with the MSPDIReader
class by replacing UniversalProjectReader
with MSPDIReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-mspdi/#encoding","title":"Encoding","text":"
By default MPXJ assumes that MSPDI files are encoded as UTF-8. The UniversalProjectReader
understands Unicode Byte Order Marks (BOM) and will adjust the encoding appropriately if a BOM is present. If you have an MSPDI file with an unusual encoding, you can manually set the encoding used by the reader.
Two methods are provided to do this: setCharset
and setEncoding
. The setCharset
method takes an instance of the Charset
class, while the setEncoding
method takes the name of an encoding. Examples of these methods are shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\n\n// Use a Charset instance\nreader.setCharset(Charset.forName(\"GB2312\"));\nProjectFile project = reader.read(\"my-sample.xml\");\n\n// Use an encoding name\nreader.setEncoding(\"GB2312\");\nproject = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#microsoft-project-compatibility","title":"Microsoft Project Compatibility","text":"
Microsoft Project will read MSPDI files which are not valid XML according to the MSPDI schema. By default MPXJ has been configured to take the same approach. If for some reason you wish to apply strict validation when reading an MSPDI file, you can do this using the setMicrosoftProjectCompatibleInput
method, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\nreader.setMicrosoftProjectCompatibleInput(false);\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-mspdi/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from an MSPDI file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the MSPDIReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nMSPDIReader reader = new MSPDIReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.xml\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-openplan/","title":"How To: Deltek Open Plan BK3 files","text":"
Deltek Open Plan is a planning tool for Windows which can store schedule data in a variety of databases, and export schedules to BK3 files.
"},{"location":"howto-read-openplan/#reading-open-plan-files","title":"Reading Open Plan files","text":"
The simplest way to read an Open Plan file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.bk3\");\n
You can work directly with the OpenPlanReader
by replacing UniversalProjectReader
with OpenPlanReader
, although this offers no particular advantage as there are no additional configuration settings available on the OpenPlanReader
class.
"},{"location":"howto-read-p3/","title":"How To: Read P3 files","text":"
A Primavera P3 installation stores project data as a database consisting of a number of individual files. In a typical P3 installation files for a number of different projects live in a single projects directory. A P3 user can back up an individual project to create a PRX file, which is a compressed archive containing all of the files from a single project.
"},{"location":"howto-read-p3/#reading-prx-files","title":"Reading PRX files","text":"
The simplest way to read a PRX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.prx\");\n
You can work directly with the P3PRXFileReader
by replacing UniversalProjectReader
with P3PRXFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the P3PRXFileReader
class.
"},{"location":"howto-read-p3/#reading-a-p3-directory","title":"Reading a P3 directory","text":"
If you are working with a directory containing P3 project data you have two options. If you know that the directory only contains a single project, you can use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-p3-directory\");\n
If the directory happens to contain multiple projects the UniversalProjectReader
will simply read the first one it finds, in alphabetic order.
If you know that the directory you are working with contains multiple projects, you will need to use the P3DatabaseReader
class.
import java.util.List;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.p3.P3DatabaseReader;\n\n// ...\n\n// Find a list of the project names\nString directory = \"my-p3-directory\";\nList<String> projectNames = P3DatabaseReader.listProjectNames(directory);\n\n// Tell the reader which project to work with\nP3DatabaseReader reader = new P3DatabaseReader();\nreader.setProjectName(projectNames.get(0));\n\n// Read the project\nProjectFile project = reader.read(directory);\n
As the example above shows, the P3DatabaseReader
class provides a method which lists the names of the P3 projects it finds in a directory. You can then select which project you want to load, and call the setProjectName
method of the reader to make this selection. You can then call the read
method passing in the name of the directory, and the reader will extract data for the selected project.
"},{"location":"howto-read-phoenix/","title":"How To: Read Phoenix Project Manager files","text":"
Phoenix Project Manager uses PPX files.
"},{"location":"howto-read-phoenix/#reading-ppx-files","title":"Reading PPX files","text":"
The simplest way to read a PPX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.ppx\");\n
You can work directly with the PhoenixReader
by replacing UniversalProjectReader
with PhoenixReader
, although this offers no particular advantage as there are no additional configuration settings available on the PhoenixReader
class.
"},{"location":"howto-read-planner/","title":"How To: Read Planner files","text":"
Gnome Planner is a popular open source planning tool which writes its own XML files.
"},{"location":"howto-read-planner/#reading-planner-files","title":"Reading Planner files","text":"
The simplest way to read a Planner file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
You can work directly with the PlannerReader
by replacing UniversalProjectReader
with PlannerReader
, although this offers no particular advantage as there are no additional configuration settings available on the PlannerReader
class.
"},{"location":"howto-read-plf/","title":"How To: Read Primavera PLF files","text":"
Primavera P6 can export layout information as PLF files. These files define the visual appearance of the P6 user interface, and can be imported and exported by P6. Although MPXJ doesn't currently offer any facilities to interpret the contents of these files, the data they contain can be read.
"},{"location":"howto-read-plf/#reading-plf-files","title":"Reading PLF files","text":"
A PLF file contains \"structured text\" and can be read using StructuredTextParser
:
import net.sf.mpxj.primavera.StructuredTextParser;\n\n// ...\n\nStructuredTextParser parser = new StructuredTextParser();\nStructuredTextRecord record = parser.parse(new FileInputStream(\"test.plf\"))\n
"},{"location":"howto-read-plf/#attributes","title":"Attributes","text":"
The resulting StructuredTextRecord
contains attributes which can be accesed individually by name, as shown below:
record.getAttribute(\"attribute_name\");\n
The attributes can also be retrieved in the form of a Map
containing all attributes for this record:
Map<String,String> attributes = record.getAttributes();\nattributes.get(\"attribute_name\");\n
Each record has two special attributes: a record number, and optionally a record name. These appear as part of the identifying information for each record, not as part of the general set of attributes for the record. These can be retrieved as shown below:
String recordNumber = record.getRecordNumber();\nString recordName = record.getRecordName();\n
These attributes will also be found in the attributes Map
with the keys _record_number
and _record_name
.
"},{"location":"howto-read-plf/#child-records","title":"Child records","text":"
Along with a set of attributes, each StructuredTextRecord
may have child StructuredTextRecord
instances. These be retrieved as a list, as shown below:
List<StructuredTextRecord> childRecords = record.getChildren();\n
Certain record types are named, and where this is the case a child record can be retrieved individually by name:
StructuredTextRecord child = record.getChild(\"child_name\");\n
"},{"location":"howto-read-pmxml/","title":"How To: Read Primavera PMXML files","text":"
Primavera P6 can export data in an XML format known as PMXML.
"},{"location":"howto-read-pmxml/#reading-pmxml-files","title":"Reading PMXML files","text":"
The simplest way to read a PMXML file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xml\");\n
"},{"location":"howto-read-pmxml/#using-primaverapmfilereader","title":"Using PrimaveraPMFileReader","text":"
You can work directly with the PrimaveraPMFileReader
by replacing UniversalProjectReader
with PrimaveraPMFileReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-pmxml/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently, the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-pmxml/#multiple-projects","title":"Multiple Projects","text":"
A PMXML file can contain multiple projects. By default, MPXJ reads the first non-external project it finds in the file, otherwise it defaults to the first project it finds. You can however use MPXJ to list the projects contained in a PMXML file, as shown below:
import net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nFileInputStream is = new FileInputStream(\"my-sample.xml\");\nMap<Integer, String> projects = reader.listProjects(is);\nSystem.out.println(\"ID\\tName\");\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(entry.getKey()+\"\\t\"+entry.getValue());\n}\n
The call to listProjects
returns a Map
whose key is the project ID, and the values are project short names.
Once you have decided which of these projects you want to work with, you can call setProjectID
to tell the reader which project to open, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setProjectID(123);\nProjectFile file = reader.read(\"my-sample.xml\");\n
Alternatively you can ask MPXJ to read all the projects contained in the file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
The call to the readAll
method returns a list of ProjectFile
instances corresponding to the projects in the PMXML file.
"},{"location":"howto-read-pmxml/#link-cross-project-relations","title":"Link Cross-Project Relations","text":"
A PMXML file can contain multiple projects with relations between activities which span those projects. By default, these cross-project relations are ignored. However, if you set the linkCrossProjectRelations
reader attribute to true
, MPXJ will attempt to link these relations across projects:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setLinkCrossProjectRelations(true);\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-pmxml/#baselines","title":"Baselines","text":"
Users can export PMXML files from P6 which contain the baseline project along with the main project being exported. When the readAll
method is used to read a PMXML file, MPXJ will attempt to populate the baseline fields of the main project if it can locate the baseline project in the PMXML file.
By default the \"Planned Dates\" strategy is used to populate baseline fields, which is the approach P6 uses when the \"Earned Value Calculation\" method is set to \"Budgeted values with planned dates\".
PrimaveraPMFileReader
provides a method allowing the strategy to be changed, thus allowing you to select the \"Current Dates\" strategy, which is the approach used by P6 when the Earned Value Calculation method is set to \"At Completion values with current dates\" or \"Budgeted values with current dates\". The example below illustrates how this method is used:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraBaselineStrategy;\nimport net.sf.mpxj.primavera.PrimaveraPMFileReader;\n\n// ...\n\nPrimaveraPMFileReader reader = new PrimaveraPMFileReader();\nreader.setBaselineStrategy(PrimaveraBaselineStrategy.CURRENT_DATES);\nInputStream is = new FileInputStream(\"my-sample.xml\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-primavera/","title":"How To: Read a Primavera P6 database","text":"
Reading from a Primavera database is a slightly different proposition to reading file-based project data, as a database connection is required.
"},{"location":"howto-read-primavera/#java","title":"Java","text":"
The example below illustrates how to do this for a Primavera database hosted in SQL Server, using the open source JTDS JDBC driver. The only difference when reading from an Oracle database will be the JDBC driver and connection string used.
import java.sql.Connection;\nimport java.sql.DriverManager;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\n//\n// Load the JDBC driver\n//\nString driverClass=\"net.sourceforge.jtds.jdbc.Driver\";\nClass.forName(driverClass);\n\n//\n// Open a database connection. You will need to change\n// these details to match the name of your server, database, user and password.\n//\nString connectionString=\"jdbc:jtds:sqlserver://localhost/PMDB;user=pmdb;password=pmdb\";\nConnection c = DriverManager.getConnection(connectionString);\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setConnection(c);\n\n//\n// Retrieve a list of the projects available in the database\n//\nMap<Integer,String> projects = reader.listProjects();\n\n//\n// At this point you'll select the project\n// you want to work with.\n//\n\n//\n// Now open the selected project using its ID\n//\nint selectedProjectID = 1;\nreader.setProjectID(selectedProjectID);\nProjectFile projectFile = reader.read();\n
You can also connect to a standalone SQLite P6 database. This is easier to achieve as a specific reader class has been created which manages the database connection for you:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseFileReader;\n\n...\n\nPrimaveraDatabaseFileReader reader = new PrimaveraDatabaseFileReader();\n\n//\n// Retrieve a list of the projects available in the database\n//\nMap<Integer,String> projects = reader.listProjects(\"PPMDBSQLite.db\");\n\n//\n// At this point you'll select the project\n// you want to work with.\n//\n\n//\n// Now open the selected project using its ID\n//\nint selectedProjectID = 1;\nreader.setProjectID(selectedProjectID);\nProjectFile projectFile = reader.read(\"PPMDBSQLite.db\");\n
"},{"location":"howto-read-primavera/#net","title":".Net","text":"
The situation is a little more complicated when using the .Net version of MPXJ. In this case you are still actually running Java code, so you need to use a JDBC driver to establish a database connection.
Your first step will be to convert your JDBC driver to a .Net assembly using IKVM. For example the command line below converts a version of Microsoft's SQL Server JDBC driver to a .Net assembly:
c:\\java\\ikvm-8.0.5449.1\\bin\\ikvmc.exe -out:mssql-jdbc-6.4.0.jre8.dll -target:library -keyfile:c:\\java\\mpxj\\src.net\\mpxj.snk -version:6.4.0.0 mssql-jdbc-6.4.0.jre8.jar\n
You can then add a reference to this assembly to your project. Configuring the JDBC driver needs to be done in a slightly different way than you would when using Java. Here we need to create an instance of the JDBC driver class directly, rather than referencing it by name as we would in Java.
//\n// Configure the connection\n//\nvar driver = new SQLServerDriver();\nvar connectionProperties = new Properties();\nvar connection = driver.connect(connectionString, connectionProperties);\n\n//\n// Configure the reader\n//\nvar reader = new PrimaveraDatabaseReader();\nreader.Connection = connection;\n
You can find the complete code for this here.
"},{"location":"howto-read-primavera/#using-primaveradatabasereader","title":"Using PrimaveraDatabaseReader","text":"
This section documents the additional options provided by the PrimaveraDatabaseReader.
"},{"location":"howto-read-primavera/#activity-wbs","title":"Activity WBS","text":"
In the original implementation of the database handling code, MPXJ would assign each task representing a Primavera Activity its own distinct WBS value. This does not match Primavera's behaviour where all of a WBS element's child activities will have the same WBS value as the parent WBS element. MPXJ's default behaviour now matches Primavera, but should you wish to you can revert to the original behaviour by calling the setMatchPrimaveraWBS
as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setMatchPrimaveraWBS(false);\n
"},{"location":"howto-read-primavera/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently, the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraDatabaseReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-primavera/#reading-additional-attributes","title":"Reading Additional Attributes","text":"
A data-driven approach is used to extract the attributes used by MPXJ from the database. You can if you wish change the way attributes are read from the file, or add support for additional attributes. This assumes that you know the column name of the attributes you want to work with in the database. To make changes you will need to retrieve the maps which define which MPXJ attributes are used to store which columns from the database:
PrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\nMap<FieldType, String> resourceFieldMap = reader.getResourceFieldMap();\nMap<FieldType, String> wbsFieldMap = reader.getWbsFieldMap();\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nMap<FieldType, String> assignmentFieldMap = reader.getAssignmentFieldMap();\n
These maps will contain the default mapping between columns and MPXJ attributes. You can modify these existing mappings, or add new ones, for example:
//\n// Change the field used to store rsrc_id\n//\nactivityFieldMap.remove(TaskField.NUMBER1);\nactivityFieldMap.put(TaskField.NUMBER2, \"rsrc_id\");\n\n//\n// Read an Activity column called an_example_field and store it in TEXT10\n//\nactivityFieldMap.put(TaskField.TEXT10, \"an_example_field\");\n
"},{"location":"howto-read-primavera/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from a Primavera database. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the PrimaveraDatabaseReader
to report errors encountered when reading from a Primavera database:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIReader;\n\n// ...\n\nPrimaveraDatabaseReader reader = new PrimaveraDatabaseReader();\n\nreader.setIgnoreErrors(false);\n
Note that if errors are ignored when reading from a Primavera database, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-projectcommander/","title":"How To: Read Project Commander files","text":"
Project Commander is a planning tool for Windows which writes its own PC file format.
"},{"location":"howto-read-projectcommander/#reading-project-commander-files","title":"Reading Project Commander files","text":"
The simplest way to read a Project Commander file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pc\");\n
You can work directly with the ProjectCommanderReader
by replacing UniversalProjectReader
with ProjectCommanderReader
, although this offers no particular advantage as there are no additional configuration settings available on the ProjectCommanderReader
class.
"},{"location":"howto-read-projectlibre/","title":"How To: Read ProjectLibre files","text":"
ProjectLibre writes schedule data to POD files. MPXJ can read POD files written by ProjectLibre version 1.5.5 and later versions.
"},{"location":"howto-read-projectlibre/#reading-pod-files","title":"Reading POD files","text":"
The simplest way to read a POD file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pod\");\n
You can work directly with the ProjectLibreReader
by replacing UniversalProjectReader
with ProjectLibreReader
, although this offers no particular advantage as there are no additional configuration settings available on the ProjectLibreReader
class.
"},{"location":"howto-read-schedule-grid/","title":"How To: Read Schedule Grid files","text":"
Schedule grid files are produced when a schedule is exported from Sage 100 Contractor.
"},{"location":"howto-read-schedule-grid/#reading-schedule-grid-files","title":"Reading Schedule Grid files","text":"
The simplest way to read a schedule grid file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.schedule_grid\");\n
"},{"location":"howto-read-schedule-grid/#using-sagereader","title":"Using SageReader","text":"
You can work directly with the SageReader
class by replacing UniversalProjectReader
with SageReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-schedule-grid/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from a Schedule Grid file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the SageReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sage.SageReader;\n\n// ...\n\nSageReader reader = new SageReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.schedule_grid\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-sdef/","title":"How To: Read SDEF files","text":"
The Standard Data Exchange Format (SDEF) is the US Army Corps of Engineers standard format for exchanging schedule data between systems. The definition of this format can be found here.
"},{"location":"howto-read-sdef/#reading-sdef-files","title":"Reading SDEF files","text":"
The simplest way to read an SDEF file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.sdef\");\n
"},{"location":"howto-read-sdef/#using-sdefreader","title":"Using SDEFReader","text":"
You can work directly with the SDEFReader
class by replacing UniversalProjectReader
with SDEFReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-sdef/#ignore-errors","title":"Ignore Errors","text":"
By default MPXJ will ignore errors when parsing attributes from an SDEF file. This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the SDEFReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFReader;\n\n// ...\n\nSDEFReader reader = new SDEFReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.sdef\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-suretrak/","title":"How To: Read SureTrak files","text":"
A Primavera SureTrak installation stores project data as a database consisting of a number of individual files. In a typical SureTrak installation files for a number of different projects live in a single projects directory. A SureTrak user can back up an individual project to create an STX file, which is a compressed archive containing all of the files from a single project.
"},{"location":"howto-read-suretrak/#reading-stx-files","title":"Reading STX files","text":"
The simplest way to read an STX file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.stx\");\n
You can work directly with the SureTrakSTXFileReader
by replacing UniversalProjectReader
with SureTrakSTXFileReader
, although this offers no particular advantage as there are no additional configuration settings available on the SureTrakSTXFileReader
class.
"},{"location":"howto-read-suretrak/#reading-a-suretrak-directory","title":"Reading a SureTrak directory","text":"
If you are working with a directory containing SureTrak project data you have two options. If you know that the directory only contains a single project, you can use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-suretrak-directory\");\n
If the directory happens to contain multiple projects the UniversalProjectReader
will simply read the first one it finds, in alphabetic order.
If you know that the directory you are working with contains multiple projects, you will need to use the SureTrakDatabaseReader
class.
import java.util.List;\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.suretrak.SureTrakDatabaseReader;\n\n// ...\n\n// Find a list of the project names\nString directory = \"my-suretrak-directory\";\nList<String> projectNames = SureTrakDatabaseReader.listProjectNames(directory);\n\n// Tell the reader which project to work with\nP3DatabaseReader reader = new SureTrakDatabaseReader();\nreader.setProjectName(projectNames.get(0));\n\n// Read the project\nProjectFile project = reader.read(directory);\n
As the example above shows, the SureTrakDatabaseReader
class provides a method which lists the names of the SureTrak projects it finds in a directory. You can then select which project you want to load, and call the setProjectName
method of the reader to make this selection. You can then call the read
method passing in the name of the directory, and the reader will extract data for the selected project.
"},{"location":"howto-read-synchro/","title":"How To: Read Synchro Scheduler files","text":"
Synchro Scheduler writes SP files.
"},{"location":"howto-read-synchro/#reading-sp-files","title":"Reading SP files","text":"
The simplest way to read an SP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.sp\");\n
You can work directly with the SynchroReader
by replacing UniversalProjectReader
with SynchroReader
, although this offers no particular advantage as there are no additional configuration settings available on the SynchroReader
class.
"},{"location":"howto-read-turboproject/","title":"How To: Read TurboProject files","text":"
TurboProject writes schedule data to PEP files.
"},{"location":"howto-read-turboproject/#reading-pep-files","title":"Reading PEP files","text":"
The simplest way to read a PEP file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.pep\");\n
You can work directly with the TurboProjectReader
by replacing UniversalProjectReader
with TurboProjectReader
, although this offers no particular advantage as there are no additional configuration settings available on the TurboProjectReader
class.
"},{"location":"howto-read-xer/","title":"How To: Read XER files","text":"
The XER file format has long been read and written by Primavera P6. Although an XML file format (PMXML) is now also supported, the XER file format is still widely used.
"},{"location":"howto-read-xer/#reading-xer-files","title":"Reading XER files","text":"
The simplest way to read an XER file is to use the UniversalProjectReader
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n// ...\n\nUniversalProjectReader reader = new UniversalProjectReader();\nProjectFile project = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#using-primaveraxerfilereader","title":"Using PrimaveraXERFileReader","text":"
You can work directly with the PrimaveraXERFileReader
class by replacing UniversalProjectReader
with PrimaveraXERFileReader
. This provides access to additional options, as described below.
"},{"location":"howto-read-xer/#ignore-errors","title":"Ignore Errors","text":"
By default P6 ignores records it can't successfully read from an XER file. MPXJ takes the same approach, and in most cases if it doesn't receive the data it expects for a particular record it will ignore the problematic item.
This behavior is controlled using the setIgnoreErrors
method. The example below illustrates how we can force the PrimaveraXERFileReader
to report errors encountered when reading a file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\n\nreader.setIgnoreErrors(false);\nProjectFile project = reader.read(\"my-sample.xer\");\n
Note that if errors are ignored when reading a file, the ignored errors are available by using the ProjectFile.getIgnoredErrors()
method.
"},{"location":"howto-read-xer/#encoding","title":"Encoding","text":"
By default MPXJ assumes that XER files are encoded using Windows-1252. The UniversalProjectReader
understands Unicode Byte Order Marks (BOM) and will adjust the encoding appropriately if a BOM is present. If you have an XER file with an unusual encoding, you can manually set the encoding used by the reader.
Two methods are provided to do this: setCharset
and setEncoding
. The setCharset
method takes an instance of the Charset
class, while the setEncoding
method takes the name of an encoding. Examples of these methods are shown below:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\n\n// Use a Charset instance\nreader.setCharset(Charset.forName(\"GB2312\"));\nProjectFile project = reader.read(\"my-sample.xer\");\n\n// Use an encoding name\nreader.setEncoding(\"GB2312\");\nproject = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#multiple-projects","title":"Multiple Projects","text":"
An XER file can contain multiple projects. By default MPXJ reads the first project it finds in the file which has been marked as the \"exported\" project, otherwise it will simply read the first project it finds. You can however use MPXJ to list the projects contained in an XER file, as shown below:
import net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nFileInputStream is = new FileInputStream(\"my-sample.xer\");\nMap<Integer, String> projects = reader.listProjects(is);\nSystem.out.println(\"ID\\tName\");\nfor (Entry<Integer, String> entry : projects.entrySet())\n{\n System.out.println(entry.getKey()+\"\\t\"+entry.getValue());\n}\n
The call to listProjects
returns a Map
whose key is the project ID, and the values are project short names.
Once you have decided which of these projects you want to work with, you can call setProjectID
to tell the reader which project to open, as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setProjectID(123);\nProjectFile file = reader.read(\"my-sample.xer\");\n
Alternatively you can ask MPXJ to read all of the projects contained in the file:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nInputStream is = new FileInputStream(\"my-sample.xer\");\nList<ProjectFile> files = reader.readAll(is);\n
The call to the readAll
method returns a list of ProjectFile
instances corresponding to the projects in the XER file.
"},{"location":"howto-read-xer/#link-cross-project-relations","title":"Link Cross-Project Relations","text":"
An XER file can contain multiple projects with relations between activities which span those projects. By default these cross-project relations are ignored. However, if you set the linkCrossProjectRelations
reader attribute to true
, MPXJ will attempt to link these relations across projects:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setLinkCrossProjectRelations(true);\nInputStream is = new FileInputStream(\"my-sample.xer\");\nList<ProjectFile> files = reader.readAll(is);\n
"},{"location":"howto-read-xer/#activity-wbs","title":"Activity WBS","text":"
In the original implementation of the XER file handling code, MPXJ would assign each task representing a Primavera Activity its own distinct WBS value. This does not match Primavera's behaviour where all of a WBS element's child activities will have the same WBS value as the parent WBS element. MPXJ's default behaviour now matches Primavera, but should you wish to you can revert to the original behaviour by calling the setMatchPrimaveraWBS
as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setMatchPrimaveraWBS(false);\nProjectFile file = reader.read(\"my-sample.xer\");\n
"},{"location":"howto-read-xer/#wbs-is-full-path","title":"WBS is Full Path","text":"
Currently the WBS attribute of summary tasks (WBS entities in P6) will be a dot separated hierarchy of all of the parent WBS attributes. In this example, root.wbs1.wbs2
is the WBS attribute for wbs2
which has the parents root
and wbs1
. To disable this behaviour, and simply record the code for the current WBS entry (in the example above wbs2
) call the setWbsIsFullPath
method, passing in false
, as illustrated below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileReader;\n\n// ...\n\nPrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nreader.setWbsIsFullPath(false);\n
"},{"location":"howto-read-xer/#reading-additional-attributes","title":"Reading Additional Attributes","text":"
A data-driven approach is used to extract the attributes used by MPXJ from the XER file. You can if you wish change the way attributes are read from the file, or add support for additional attributes. This assumes that you know the column name of the attributes you want to work with in the XER file. To make changes you will need to retrieve the maps which define which MPXJ attributes are used to store which columns from the XER file:
PrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nMap<FieldType, String> resourceFieldMap = reader.getResourceFieldMap();\nMap<FieldType, String> wbsFieldMap = reader.getWbsFieldMap();\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nMap<FieldType, String> assignmentFieldMap = reader.getAssignmentFieldMap();\n
These maps will contain the default mapping between columns and MPXJ attributes. You can modify these existing mappings, or add new ones, for example:
//\n// Change the field used to store rsrc_id\n//\nactivityFieldMap.remove(TaskField.NUMBER1);\nactivityFieldMap.put(TaskField.NUMBER2, \"rsrc_id\");\n\n//\n// Read an Activity column called an_example_field and store it in TEXT10\n//\nactivityFieldMap.put(TaskField.TEXT10, \"an_example_field\");\n
When reading new columns from the XER file, if these columns have a type other than String, it is important to register the type of the column to ensure that it is converted correctly. You will also need to ensure that the MPXJ attribute you are writing this new value to can receive the data type you are assigning to it (for example, you must store a date in a date attribute, you can't store a date in an integer attribute).
For example, if we are reading an integer column called an_example_id
and store it in the NUMBER2
attribute, we will need to take the following steps:
PrimaveraXERFileReader reader = new PrimaveraXERFileReader();\nMap<String, XerFieldType> fieldTypeMap = reader.getFieldTypeMap();\nfieldTypeMap.put(\"an_example_id\", XerFieldType.INTEGER);\nMap<FieldType, String> activityFieldMap = reader.getActivityFieldMap();\nactivityFieldMap.put(TaskField.NUMBER2, \"an_example_id\");\n
"},{"location":"howto-start-java/","title":"Gettsing Started with Java","text":"
MPXJ is built to work with versions of Java from 1.8 onwards. For many people, the easiest way to get started with MPXJ and its dependencies is to use Maven. Just include the following in your POM to register MPXJ as a dependency of your project:
<dependency>\n <groupId>net.sf.mpxj</groupId>\n <artifactId>mpxj</artifactId>\n <version>10.11.0</version>\n</dependency>\n
The traditional method of downloading the MPXJ distribution as a zip file can also be used. Distributions can be found at GitHub and SourceForge.
The zip files contain all of the source, the MPXJ JAR file in the root of the zip file, with the libraries on which MPXJ depends being found in the lib
directory of the zip file. These libraries will need to be available on your classpath in order to use all of the MPXJ functionality. The script
directory in the zip file contains a batch file and a shell script which show how this can be done.
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start-python/","title":"Getting Started with Python","text":"
MPXJ is available as a Python Package, which can be installed using pip
:
pip install mpxj\n
You can find some documentation for the Package here. You'll need Java installed to make use of this package.
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start-ruby/","title":"Getting Started with Ruby","text":"
MPXJ is available as a RubyGem, which can be installed using gem
:
gem install mpxj\n
or included in you Gemfile
and installed using bundler
.
Note that the Ruby version of MPXJ is just a wrapper around the Java library, and provides read-only access to schedule data. You will need Java installed to make use of this Gem. You can find some documentation for the Gem [here] (https://rubygems.org/gems/mpxj)
You'll find a general introduction to MPXJ's functionality here.
"},{"location":"howto-start/","title":"MPXJ Basics","text":"
The MPXJ library allows various formats of Microsoft Project file formats, and file formats from other project planning applications to be read and written using a single consistent API in Java, .Net, Python or any other related languages, and provides read-only access as a Ruby gem.
MPXJ is based around a \"neutral\" data structure which is used to represent project data, coupled with a set of format-specific reader and writer classes which understand how to read from and write to the various supported file formats.
The diagram below illustrates the key entities represented by the MPXJ data structure.
MPXJ currently allows project data to be read from a wide variety of schedule file formats and databases. You can find details of the individual file formats supported elsewhere in the documentation. By far the easiest way to read schedule data is to use the \"universal project reader\" which can determine for itself the type of file you have passed to it.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\n
A similar arrangement exists for the writer classes, although there is not a \"universal project writer\" as such:
net.sf.mpxj.mpx.MPXWriter
: writes Microsoft MPX filesnet.sf.mpxj.mspdi.MSPDIWriter
: writes Microsoft MSPDI (XML) filesnet.sf.mpxj.planner.PlannerWriter
: writes Planner (XML) filesnet.sf.mpxj.sdef.SDEFWriter
: writes SDEF filesnet.sf.mpxj.primavera.PrimaveraPMFileWriter
: writes Primavera PMXML (XML) filesnet.sf.mpxj.json.JsonWriter
: writes JSON files (primarily used to support the Ruby version of MPXJ)All of these classes implement the ProjectWriter interface. If you know which type of file you are working with, you can use these writers directly, for example:
ProjectWriter writer = new MPXWriter();\nwriter.write(project, \"example.mpx\");\n
"},{"location":"howto-start/#tasks-and-resources","title":"Tasks and Resources","text":"
Once you've read your project file, what next? The first things of interest are the tasks and resources which are present in the file.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\nfor (Resource resource : project.getAllResources())\n{\n System.out.println(\"Resource: \" + resource.getName()\n + \" (Unique ID=\" + resource.getUniqueID() + \")\");\n}\n
The code fragment above shows how we can retrieve a collection containing all of the resources present in the file, and iterate through them printing the resource name, ID and unique ID.
Many of the entities represented in MPXJ have some concept of a unique ID. Tasks and resources have two ID fields, the unique ID, which as its name suggests never changes and uniquely identifies a task or a resource, and the ID. The ID of a task or a resource is the sequential number which typically appears next to the task or resource when displayed in Microsoft Project. If the task or resource is moved up or down the list, this number will change depending on the position in the list. The unique ID never changes.
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\nfor (Task task : project.getAllTasks())\n{\n System.out.println(\"Task: \" + task.getName() + \" ID=\" + task.getID()\n + \" Unique ID=\" + task.getUniqueID());\n}\n
The code fragment above retrieves all tasks present in the file and prints details of their names, IDs, and unique IDs.
Methods are provided on the project to locate both tasks and resource using either their ID or their Unique ID, as the examples below illustrate.
Resource r = project.getResourceByUniqueID(Integer.valueOf(99));\nTask t = project.getTaskByUniqueID(Integer.valueOf(99));\n
The methods shown above for retrieving all tasks present in a project file ignores the hierarchical task structure which Microsoft Project allows users to create. To understand the hierarchical task structure, the following methods are used to descend through the hierarchy, starting from the top.
List<Task> tasks = project.getChildTasks();\nTask task = tasks.get(0);\ntasks = task.getChildTasks();\n
These methods are used in the following code fragment to print out an indented list representing the task hierarchy in the file.
public void listHierarchy(ProjectFile file)\n{\n for (Task task : file.getChildTasks())\n {\n System.out.println(\"Task: \" + task.getName());\n listHierarchy(task, \" \");\n }\n\n System.out.println();\n}\n\nprivate void listHierarchy(Task task, String indent)\n{\n for (Task child : task.getChildTasks())\n {\n System.out.println(indent + \"Task: \" + child.getName());\n listHierarchy(child, indent + \" \");\n }\n}\n
As well as the hierarchical relationships between tasks, there is also a temporal relationship between them: this is typically used to indicate when a task can start in relation to the completion of an earlier task. The code fragment below shows the predecessor relationships between tasks.
for (Task task : file.getAllTasks())\n{\n List<Relation> predecessors = task.getPredecessors();\n if (predecessors != null && !predecessors.isEmpty())\n {\n System.out.println(task.getName() + \" predecessors:\");\n for (Relation relation : predecessors)\n {\n System.out.println(\" Task: \" + file.getTaskByUniqueID(relation.getTaskUniqueID()).getName());\n System.out.println(\" Type: \" + relation.getType());\n System.out.println(\" Lag: \" + relation.getDuration());\n }\n }\n}\n
"},{"location":"howto-start/#resource-assignments","title":"Resource Assignments","text":"
Tasks and resources are related by resource assignments. There is a method available on the ProjectFile class which will retrieve all resource assignments in the file. This is used by the code fragment below to provide an overview of all assignments.
for (ResourceAssignment assignment : file.getAllResourceAssignments())\n{\n Task task = assignment.getTask();\n String taskName;\n if (task == null)\n {\n taskName = \"(null task)\";\n }\n else\n {\n taskName = task.getName();\n }\n\n Resource resource = assignment.getResource();\n String resourceName;\n if (resource == null)\n {\n resourceName = \"(null resource)\";\n }\n else\n {\n resourceName = resource.getName();\n }\n\n System.out.println(\"Assignment: Task=\" + taskName + \" Resource=\" + resourceName);\n}\n
Resource assignments can also be retrieved on a task-by-task basis, as the code fragment below illustrates.
for (Task task : file.getAllTasks())\n{\n System.out.println(\"Assignments for task \" + task.getName() + \":\");\n\n for (ResourceAssignment assignment : task.getResourceAssignments())\n {\n Resource resource = assignment.getResource();\n String resourceName;\n\n if (resource == null)\n {\n resourceName = \"(null resource)\";\n }\n else\n {\n resourceName = resource.getName();\n }\n\n System.out.println(\" \" + resourceName);\n }\n}\n
Finally, resource assignments can be viewed on a resource-by-resource basis, as the following code fragment shows.
for (Resource resource : file.getAllResources())\n{\n System.out.println(\"Assignments for resource \" + resource.getName() + \":\");\n\n for (ResourceAssignment assignment : resource.getTaskAssignments())\n {\n Task task = assignment.getTask();\n System.out.println(\" \" + task.getName());\n }\n}\n
"},{"location":"howto-start/#calendars","title":"Calendars","text":"
Calendars are used to define working and non-working time, and are one of the more complex structures defined as part of a project. They are in turn used to define the time period over which a task is scheduled. There are two types of calendar: base calendars and resource calendars. Each base calendar provides a complete definition of the working and non working time for each day of the week. Resource calendars are associated with individual resources. Each resource calendar is derived from a base calendar; resource calendars may be unmodified in which case it will appear to be identical to the underlying base calendar, or the resource calendar may modify the working and non-working days. In this case these changes are \"overlaid\" on top of the working and non-working times defined by the base calendar. The calendars defined in a project can be retrieved using the method call shown below.
List<ProjectCalendar> calendars = file.getCalendars();\n
Normally a task without resource assignments will be scheduled with reference to the \"Standard\" (default) calendar defined as part of the project. This is retrieved using the method calls shown below.
ProjectCalendar defaultCalendar = file.getDefaultCalendar();\n
It is also possible to associate a specific calendar with an individual task. The method call below shows the calendar associated with a task being retrieved.
ProjectCalendar taskCalendar = task.getCalendar();\n
Bearing in mind that one calendar may be derived from another, care must be taken when choosing the methods called on a calendar instance: some methods are used to retrieve attributes defined as part of that specific calendar only, while others are used to descend through the hierarchy of calendars until an \"actual\" value is retrieved. For example the getDays method will retrieve an array of flags indicating the working/non-working/default state of each day of the week as defined by the current calendar. The getDay method however will test the current calendar to see if it is a working or non-working day. If the flag in the current calendar is set to \"default\", the method will use the base calendar from which the current calendar is derived to determine if the day is working or non-working.
As noted above a calendar contains a set of flags which represent each day of the week, these indicate the day of the week is working non-working, or \"default\". Where a day is set as \"default\", the working time for that day is taken from the underlying base calendar, if it is a resource calendar, or uses the default values provided by Microsoft Project if it is a base calendar.
If a particular day is defined as a working day, then the calendar will also contain a set of working hours for that day. The working hours for a day are defined by an instance of the ProjectCalendarHours class. This contains a collection of LocalTimeRange
instances which defined the start and end times of each working period during the day.
Alongside the flags which control whether a day is working or non-working, and the working hours for each day, each calendar defines a set of exceptions which are used to \"override\" the default working or non-working hours for individual days or entire date ranges. Methods are provided to allow a list of all exceptions defined by a calendar can be retrieved, or to retrieve the exception which covers an individual date. Calendar exceptions are represented by instances of the ProjectCalendarException class.
"},{"location":"howto-start/#timephased-data","title":"Timephased Data","text":"
Although resource assignments on their own describe which resources are assigned to which tasks, and how much work they are going to do, this does not necessarily tell us how much work a resource will be doing on any particular date. In order to find this information, you will need to consult the timephased resource assignment data.
Each resource assignment has a pair of methods allowing you to retrieve timephased data, as shown by the example code below.
List<TimephasedResourceAssignment> planned = assignment.getTimephasedPlanned();\nList<TimephasedResourceAssignment> complete = assignment.getTimephasedComplete();\n
Timephased resource assignment data is represented by instances of the TimephasedResourceAssignment class. This class is designed to provide a compact representation of the work carried out over ranges of days, rather than having to represent the work carried out on each individual day using a single class instance per day. Each TimephasedResourceAssignment defines four attributes: a start date, an end date, a total amount of work, and an amount of work per day.
For example, you may retrieve an instance of the TimephasedResourceAssignment class whose start and end date defines a five day period. The total work for the period is 40 hours, and the work per day is defined as 8 hours. This indicates that for the period in question, on each working day within the date range, 8 hours of work will be carried out. It is important to remember that non-working days are ignored, so for example if we have a 7 day period which spans a weekend, the total work could still be 40 hours, and the work per day 8 hours: only the 5 working days are allocated work, the non-working weekend days have zero hours of work performed.
The two lists defined above will contain multiple TimephasedResourceAssignment instances where different numbers of hours are worked on different days. Each contiguous range of dates where the same number of hours are worked in a day will be represented by one TimephasedResourceAssignment instance.
The two lists of timephased data represent completed (actual) work, and planned work respectively. These lists may overlap by a single day if they are being used to show a partially completed day's work. For example, during a normal 8 hour working day, if 4 hours of work has been completed, and 4 hours remains, then the list of completed timephased data will end with 4 hours of work which have been completed, and the planned work list will start with the 4 hours remaining on the same day.
"},{"location":"howto-use-calendars/","title":"How To: Use Calendars","text":"
Calendars are the foundation on which schedules are built. They determine when work can be carried out, and when work is not possible. Given some tasks we need to plan, and knowing how much work each task will require, a calendar can be used to decide when work on each task could start and how much elapsed time will be required to complete the tasks.
"},{"location":"howto-use-calendars/#calendars-in-mpxj","title":"Calendars in MPXJ","text":"
Let's see how calendars work in MPXJ. First let's try creating one. As it happens, the ProjectFile
class provides a convenience method addDefaultBaseCalendar
to create a default calendar. The calendar it creates is modelled on the Standard
calendar you'd see in Microsoft Project if you created a new project. This default calendar defines Monday to Friday as working days, with 8 working hours each day (8am to noon, then 1pm to 5pm).
ProjectFile file = new ProjectFile();\nProjectCalendar calendar = file.addDefaultBaseCalendar();\nSystem.out.println(\"The calendar name is \" + calendar.getName());\n
As you can see from the code above, the calendar also has a name which we can set to distinguish between different calendars.
"},{"location":"howto-use-calendars/#working-days","title":"Working Days","text":"
Let's see what the calendar can tell us. First we'll use the DayOfWeek
enumeration to retrieve the working/non-working state for each day.
for (DayOfWeek day : DayOfWeek.values()) {\n String dayType = calendar.getCalendarDayType(day).toString();\n System.out.println(day + \" is a \" + dayType + \" day\");\n}\n
Running the code shown above will produce output like this:
MONDAY is a WORKING day\nTUESDAY is a WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a NON_WORKING day\nSUNDAY is a NON_WORKING day\n
We can use the setWorkingDay
method to change our pattern of working day. Let's make Saturday a working day for our team, and make Monday a non-working day to compensate.
calendar.setWorkingDay(DayOfWeek.SATURDAY, true);\ncalendar.setWorkingDay(DayOfWeek.MONDAY, false);\n
Now if we use the loop we saw previously to inspect the week days, we'll see this output:
MONDAY is a NON_WORKING day\nTUESDAY is a WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a WORKING day\nSUNDAY is a NON_WORKING day\n
"},{"location":"howto-use-calendars/#working-hours","title":"Working Hours","text":"
So far, all we have done is set a flag which tells us whether a day is working or non-working. How do we know the working times on those days? We can use the getCalendarHours
method to find that information.
The getCalendarHours
method returns a List
of LocalTimeRange
instances. LocalTimeRange
is a simple immutable class which represents a span of time between a start time and an end time as an inclusive range. Let's try printing these LocalTimeRange
instances to our output to see what we get:
List<LocalTimeRange> hours = calendar.getCalendarHours(Day.TUESDAY);\nhours.forEach(System.out::println);\n
Here's the output:
[LocalTimeRange start=08:00 end=12:00]\n[LocalTimeRange start=13:00 end=17:00]\n
Let's add a method to format the hours of a day a little more concisely for display:
private String formatLocalTimeRanges(List<LocalTimeRange> hours) {\n return hours.stream()\n .map(h -> h.getStart() + \"-\" + h.getEnd())\n .collect(Collectors.joining(\", \"));\n}\n
So now our output looks like this:
08:00-12:00, 13:00-17:00\n
Let's use this method to take a look at the whole week again:
for (Day day : Day.values()) {\n String dayType = calendar.getCalendarDayType(day).toString();\n System.out.println(day\n + \" is a \" + dayType + \" day (\"\n + formatLocalTimeRanges(calendar.getCalendarHours(day)) + \")\");\n}\n
Here's the output:
MONDAY is a NON_WORKING day ()\nTUESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nWEDNESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nTHURSDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nFRIDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSATURDAY is a WORKING day ()\nSUNDAY is a NON_WORKING day ()\n
The one thing we're missing now is that although we have set Saturday to be a working day, it doesn't have any working hours. MPXJ has some constants which can be used to help us add some working hours:
hours = calendar.getCalendarHours(Day.SATURDAY);\nhours.add(ProjectCalendarDays.DEFAULT_WORKING_MORNING);\nhours.add(ProjectCalendarDays.DEFAULT_WORKING_AFTERNOON);\n
Now when we examine our week this is what we see:
MONDAY is a NON_WORKING day ()\nTUESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nWEDNESDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nTHURSDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nFRIDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSATURDAY is a WORKING day (08:00-12:00, 13:00-17:00)\nSUNDAY is a NON_WORKING day ()\n
The version of MPXJ at the time of writing (12.0.0) has a limitation that if setCalendarDayType
is used to make a day into a working day, we don't automatically add working hours for it. This behaviour is likely to change with the next major version of MPXJ.
What if we want to supply some working hours different from the defaults we've used so far? To set our own working hours we just need to create as many LocalTimeRange
instances as we need using a pair of LocalTime
instances for each one to represent the start and end times.
LocalTime startTime = LocalTime.of(9, 0);\nLocalTime finishTime = LocalTime.of(14, 30);\nhours = calendar.getCalendarHours(DayOfWeek.SATURDAY);\nhours.clear();\nhours.add(new LocalTimeRange(startTime, finishTime));\n
Now when we look at the working hours for Saturday, this is what we see:
SATURDAY is a WORKING day (09:00-14:30)\n
Now we've seen how we can create our own ranges of working time for a day, let's tackle a slightly more challenging case: dealing with midnight. Our first step is to take a look at the actual amount of working time we've set up on Saturday. To do this we call the getWork
method, as shown below.
Duration duration = calendar.getWork(Day.SATURDAY, TimeUnit.HOURS);\nSystem.out.println(duration);\n
This getWork
method determines the total amount of work on the given day, and returns this in the format we specify. In this case we've asked for hours, and we'll be receiving the result as a Duration
object. Duration
simply combines the duration amount with an instance of the TimeUnit
enumeration so we always know the units of the duration amount.
Running the code above give us this output:
5.5h\n
As you can see, the toString
method of Duration
give us a nicely formatted result, complete with an abbreviation for the units.
Let's try to change Saturday to be 24 hour working. First we'll configure a midnight to midnight date range:
startTime = LocalTime.MIDNIGHT;\nfinishTime = LocalTime.MIDNIGHT;\nhours.clear();\nhours.add(new LocalTimeRange(startTime, finishTime));\nSystem.out.println(formatLocalTimeRanges(calendar.getCalendarHours(DayOfWeek.SATURDAY)));\n
This looks reasonable:
00:00-00:00\n
Now let's see how much work this represents:
duration = calendar.getWork(DayOfWeek.SATURDAY, TimeUnit.HOURS);\nSystem.out.println(duration);\n
24.0h\n
So we have our 24 hours of work on Saturday!
"},{"location":"howto-use-calendars/#exceptions","title":"Exceptions","text":"
After working a few of these 24 hour days on Saturdays, we might be in need of a vacation! How can we add this to our calendar?
So far we've been working with the DayOfWeek
class to make changes to days of the week, rather than any specific date. Now we'll need to work with a specific date, and add an \"exception\" for this date. The terminology here can be slightly confusing when coming from a programming background, but the term exception is often used by scheduling applications in the context of making ad-hoc adjustments to a calendar.
LocalDate exceptionDate = LocalDate.of(2022, 5, 10);\n\nboolean workingDate = calendar.isWorkingDate(exceptionDate);\nSystem.out.println(exceptionDate + \" is a \"\n + (workingDate ? \"working\" : \"non-working\") + \" day\");\n
In the code above we're creating a LocalDate
instance to represent the date we want to add an exception for. The code uses the isWorkingDate
method to determine whether or not the given date is a working day. Before we add the exception, here's the output we get:
2022-05-10 is a working day\n
Now we can create our exception.
ProjectCalendarException exception = calendar.addCalendarException(exceptionDate);\nexception.setName(\"A day off\");\n
The code above illustrates adding an exception for a single day. The code above also shows that optionally an exception can be named, this can make it easier to understand the purpose of each exception. Now if we re-run our code which displays whether our chosen date is a working day, this is what we see:
2022-05-10 is a non-working day\n
We have successfully added an exception to turn this date into a day off!
Perhaps we were being a little too generous in giving ourselves the entire day off, perhaps in this case we should make this a half day instead. To do that, we just need to add a time range to the exception:
startTime = LocalTime.of(8, 0);\nfinishTime = LocalTime.of(12, 0);\nexception.add(new LocalTimeRange(startTime, finishTime));\n
Now if we look at our chosen date, this is what we see:
2022-05-10 is a working day\n
Let's take a closer look at what's happening on that day:
System.out.println(\"Working time on Tuesdays is normally \"\n + calendar.getWork(DayOfWeek.TUESDAY, TimeUnit.HOURS) + \" but on \"\n + exceptionDate + \" it is \"\n + calendar.getWork(exceptionDate, TimeUnit.HOURS));\n
The code above shows how we use the getWork
method which takes a DayOfWeek
as an argument to look at what the default working hours are on a Tuesday, then we use the getWork
method which takes a LocalDate
instance as an argument to see what's happening on the specific Tuesday of our exception. Here's the output we get:
Working time on Tuesdays is normally 8.0h but on 2022-05-10 it is 4.0h\n
We can see the effect of adding a LocalTimeRange
to our exception: we've gone from an exception which changes a working day into a non-working day to an exception which just changes the number of working hours in the day. This same approach can be used to change a date which falls on a day that's typically non-working (for example a Sunday) into a working day, just by adding an exception with some working hours.
We can also use a single exception to affect a number of days. First let's write a little code to see the number of working hours over a range of days:
private void dateDump(ProjectCalendar calendar, LocalDate startDate, LocalDate endDate)\n{\n for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1)) {\n System.out.println(date + \"\\t\" + calendar.getWork(date, TimeUnit.HOURS));\n }\n}\n
Running this code with our calendar as its stands produces this output for the example week we're using:
2022-05-23 0.0h\n2022-05-24 8.0h\n2022-05-25 8.0h\n2022-05-26 8.0h\n2022-05-27 8.0h\n
Let's add an exception which covers Tuesday to Thursday that week (24th to 26th), and changes the working hours, so there are now only four hours of work per day (9am to 12pm):
LocalDate exceptionStartDate = LocalDate.of(2022, 5, 24);\nLocalDate exceptionEndDate = LocalDate.of(2022, 5, 26);\nexception = calendar.addCalendarException(exceptionStartDate, exceptionEndDate);\nstartTime = LocalTime.of(9, 0);\nfinishTime = LocalTime.of(13, 0);\nexception.add(new LocalTimeRange(startTime, finishTime));\n
Here we can see that we're using a different version of the addCalendarException
method which takes a start and an end date, rather that just a single date. Running our code again to print out the working hours for each day now gives us this output:
2022-05-23 0.0h\n2022-05-24 4.0h\n2022-05-25 4.0h\n2022-05-26 4.0h\n2022-05-27 8.0h\n
As we can see, we've changed multiple days with this single exception.
"},{"location":"howto-use-calendars/#working-weeks","title":"Working Weeks","text":"
So far we've looked at using ProjectCalendarException
, which can make one change (add working hours, change working hours, or make days non-working) and apply that change to one day or a contiguous range of days. What if we want to make more complex changes to the working pattern of a calendar?
Let's imagine that our project has a three week \"crunch\" period at the beginning of October where we will need to work 16 hour days, Monday through Friday, and 8 hour days at weekends. (I hope this is a fictional example and you'd don't have to work at such a high intensity in real life!). We could construct this work pattern using exceptions: we'd need six in total, one for each of the three sets of weekend days, and one for each of the three sets of week days.
An alternative way to do this is to set up a new working week, using the ProjectCalendarWeek
class. \"Working Week\" is perhaps a slightly misleading name, as a ProjectCalendarWeek
can be set up for an arbitrary range of dates, from a few days to many weeks. What it represents is the pattern of working an non-working time over the seven days of a week, and this pattern is applied from the start to the end of the date range we configure.
The ProjectCalendar
we've been working with so far is actually already a form of working week (they share a common parent class). The main differences between the two are that a ProjectCalendarWeek
allows us to specify the range of dates over which it is effective, and a ProjectCalendarWeek
does not have exceptions: exceptions are only added to a ProjectCalendar
.
For a fresh start, we'll create a new ProjectCalendar
instance. With this we'll add a new working week definition and give it a name, to make it easily identifiable. Now we'll set the dates for which this work pattern is valid (in this case the first three weeks of October). Finally we mark every day as a working day. Here's how our example looks in code:
LocalDate weekStart = LocalDate.of(2022, 10, 1);\nLocalDate weekEnd = LocalDate.of(2022, 10, 21);\ncalendar = file.addDefaultBaseCalendar();\nProjectCalendarWeek week = calendar.addWorkWeek();\nweek.setName(\"Crunch Time!\");\nweek.setDateRange(new LocalDateRange(weekStart, weekEnd));\nArrays.stream(DayOfWeek.values()).forEach(d -> week.setWorkingDay(d, true));\n
Next we can set up our weekend 9am to 5pm working pattern:
startTime = LocalTime.of(9, 0);\nfinishTime = LocalTime.of(17, 0);\nLocalTimeRange weekendHours = new LocalTimeRange(startTime, finishTime);\nArrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)\n .stream().forEach(d -> week.addCalendarHours(d).add(weekendHours));\n
Finally we can set up our weekday 5am to 9pm pattern:
startTime = LocalTime.of(5, 0);\nfinishTime = LocalTime.of(21, 0);\nLocalTimeRange weekdayHours = new LocalTimeRange(startTime, finishTime);\nArrays.asList(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY,\n DayOfWeek.THURSDAY, DayOfWeek.FRIDAY)\n .stream().forEach(d -> week.addCalendarHours(d).add(weekdayHours));\n
As ProjectCalendar
and ProjectCalendarWeek
are both derived from the same parent class, we can use the same code we did previously to examine how our new ProjectCalendarWeek
instance looks:
MONDAY is a WORKING day (05:00-21:00)\nTUESDAY is a WORKING day (05:00-21:00)\nWEDNESDAY is a WORKING day (05:00-21:00)\nTHURSDAY is a WORKING day (05:00-21:00)\nFRIDAY is a WORKING day (05:00-21:00)\nSATURDAY is a WORKING day (09:00-17:00)\nSUNDAY is a WORKING day (09:00-17:00)\n
To see the effect that our new working week has had on the calendar, let's first take a look at the week running up to the start of our crunch period. Using the same code we worked with previously to present working hours for a range of dates we see this output:
2022-09-24 0.0h\n2022-09-25 0.0h\n2022-09-26 8.0h\n2022-09-27 8.0h\n2022-09-28 8.0h\n2022-09-29 8.0h\n2022-09-30 8.0h\n
So starting from Saturday 24th we can see that we have that standard working pattern: weekends are non-working (zero working hours), and week days have 8 hours of working time.
Now let's look at the first week of our crunch period:
2022-10-01 8.0h\n2022-10-02 8.0h\n2022-10-03 16.0h\n2022-10-04 16.0h\n2022-10-05 16.0h\n2022-10-06 16.0h\n2022-10-07 16.0h\n
We can see that the crunch is in full effect, we're working 8 hour days at the weekend, and 16 hour days for the rest of the week - not something I'd like to try for any length of time!
To summarise: the ProjectCalendar
instance itself defines the default working and non-working pattern for the seven week days. Additional working weeks can be added to the calendar which override this pattern for specific date ranges.
"},{"location":"howto-use-calendars/#recurring-exceptions","title":"Recurring Exceptions","text":"
So far we've seen how exceptions can be used to override the default working pattern established by a calendar for either a single day, or for a contiguous range of days. We've also seen how an entirely new seven-day working pattern can be applied across a range of dates by using working weeks. But what if we want to represent a regularly occurring exception which will change our default working pattern such as, for example, Christmas Day or Thanksgiving? To deal with this we can use recurring exceptions.
A recurring exception can be created simply by passing an instance of RecurringData
to the addCalendarException
method.
RecurringData recurringData = new RecurringData();\nexception = calendar.addCalendarException(recurringData);\n
Let's create a simple recurence for 1st January for five years:
recurringData.setRecurrenceType(RecurrenceType.YEARLY);\nrecurringData.setOccurrences(5);\nrecurringData.setDayNumber(Integer.valueOf(1));\nrecurringData.setMonthNumber(Integer.valueOf(1));\nrecurringData.setStartDate(LocalDate.of(2023, 1, 1));\nSystem.out.println(recurringData);\n
The toString
method on the RecurringData
class tries to describe the recurrence as best it can, here's the output we'll see from the code above:
[RecurringData Yearly on the 1 January From 2023-01-01 For 5 occurrences]\n
The example above shows a very simple configuration. Full details of how to use RecurringData
are provided elsewhere as they are beyond the scope of this section.
Before we move on from recurring exceptions, one useful feature of the ProjectCalendarException
class is the getExpandedExceptions
method. This will convert a recurring exception into a list of individual exceptions representing each date or range of dates the recurring exception will affect the calendar. You may find this useful if you need to display or pass this data on for consumption elsewhere.
"},{"location":"howto-use-calendars/#calendar-hierarchies","title":"Calendar Hierarchies","text":"
Now we've seen how to set up an individual calendar, perhaps we could go ahead and create calendars for all of the people who will be working on our project? What we'd quickly find is that a considerable amount of the information in each calendar will be the same: the same working week pattern, the same public holidays and so on. We could set all of this up programmatically of course, but wouldn't it be great if we could change this kind of detail in just one place, and have all of our other calendars inherit it?
"},{"location":"howto-use-calendars/#creating-a-calendar-hierarchy","title":"Creating a Calendar Hierarchy","text":"
As it happens, we can do this as our calendars can be organised into a hierarchy, with each \"child\" calendar inheriting its configuration from a \"parent\" calendar and overriding that configuration as required rather like a class hierarchy in a programing language). This will allow us to have one shared \"base\" calendar for everyone, with derived calendars used for individuals on our team where we need to add variation, for example personal vacation time and so on.
ProjectFile file = new ProjectFile();\nProjectCalendar parentCalendar = file.addDefaultBaseCalendar();\nLocalDate christmasDay = LocalDate.of(2023, 12, 25);\nparentCalendar.addCalendarException(christmasDay);\n
In the example above we've used the familiar addDefaultBaseCalendar
method to create a simple calendar, and called addCalendarException
to add an exception for Christmas Day 2023.
ProjectCalendar childCalendar = file.addDefaultDerivedCalendar();\nchildCalendar.setParent(parentCalendar);\nSystem.out.println(christmasDay + \" is a working day: \"\n + childCalendar.isWorkingDate(christmasDay));\n
Now we've created childCalendar
, using a method we've not seen before, addDefaultBaseCalendar
(we'll talk about this method in more detail in a minute), and we've used the new calendar's setParent
method to attach parentCalendar
as its parent. We can see the effect of this when we check to see if Christmas Day 2023 is a working day. This is a Monday so by default it will be a working day, but as childCalendar
is inheriting from parentCalendar
it picks up the exception defined in parentCalendar
and makes Christmas Day a non-working day.
Here's the output when our code is executed:
2023-12-25 is a working day: false\n
We can also do the same thing with day types:
parentCalendar.setCalendarDayType(DayOfWeek.TUESDAY, DayType.NON_WORKING);\nSystem.out.println(\"Is \" + DayOfWeek.TUESDAY + \" a working day: \" \n + childCalendar.isWorkingDay(DayOfWeek.TUESDAY));\n
In the example above we've set Tuesday to be a non-working day in the parent calendar, and we can see that this is inherited by the child calendar. Here's the output we see when we execute our code:
Is TUESDAY a working day: false\n
So what's special about the \"derived calendar\" we've just created (childCalendar
), why is it different to the normal calendar, and what's the difference between the addDefaultBaseCalendar
and addDefaultDerivedCalendar
methods?
The answer to this question lies in the DayType
enumeration. Let's take a look at the day types for parentCalendar
.
SUNDAY is a NON_WORKING day\nMONDAY is a WORKING day\nTUESDAY is a NON_WORKING day\nWEDNESDAY is a WORKING day\nTHURSDAY is a WORKING day\nFRIDAY is a WORKING day\nSATURDAY is a NON_WORKING day\n
So far so good, we have a mixture of working an non-working days, and we can see that as part of our last example we set Tuesday to be a non-working day. Now let's take a look at childCalendar
:
SUNDAY is a DEFAULT day\nMONDAY is a DEFAULT day\nTUESDAY is a DEFAULT day\nWEDNESDAY is a DEFAULT day\nTHURSDAY is a DEFAULT day\nFRIDAY is a DEFAULT day\nSATURDAY is a DEFAULT day\n
Ah-ha! Here we can see that the DayType
enumeration actually has a third value alongside WORKING
and NON_WORKING
: DEFAULT
. The DEFAULT
value simply means that we should inherit the parent calendar's settings for this particular day: so whether the day is working, non-working, what the working hours are, and so on.
We can override the day type we're inheriting from the base calendar:
childCalendar.setCalendarDayType(DayOfWeek.TUESDAY, DayType.WORKING);\nLocalTime startTime = LocalTime.of(9, 0);\nLocalTime finishTime = LocalTime.of(12, 30);\nchildCalendar.addCalendarHours(DayOfWeek.TUESDAY).add(new LocalTimeRange(startTime, finishTime));\n
In the code above we're explicitly setting Tuesday to be a working day, rather than inheriting the settings for Tuesday from the parent calendar, then we're adding the working hours we want for Tuesday.
Earlier we said we come back and look at the addDefaultDerivedCalendar
method in a little more detail. The main difference between addDefaultDerivedCalendar
and addDefaultBaseCalendar
is that the calendar created by addDefaultDerivedCalendar
has no working hours defined, and all day types are set to DEFAULT
so everything is inherited from the parent calendar.
"},{"location":"howto-use-calendars/#working-with-a-calendar-hierarchy","title":"Working with a Calendar Hierarchy","text":"
In general when working with a calendar hierarchy, if we use a calendar to determine working/non-working time, working hours, and so on for a given date, anything configured in a child calendar will always override what we find in the parent calendar. So for example if we have exceptions or working weeks configured in a child calendar, these will override anything found in a parent calendar.
If we're asking the calendar a question about a particular day (rather than a date), for example Monday, Tuesday and so on, we'll use information from the child calendar if the day type is WORKING
or NON_WORKING
, otherwise we'll work our way up the calendar hierarchy until we find the first ancestor calendar which does not specify the day type as DEFAULT
, and we'll use the configuration for the day in question from that calendar.
This brings us on to an interesting question: how do we know if we ask the calendar for a piece of information, whether that's come from the calendar whose method we've just called, or if the response we've received has come from another calendar somewhere further up the calendar hierarchy?
As it happens there are only a small number of attributes for which this is relevant. These are summarised by the table below.
Attribute Set Get Get with Hierarchy Day Type setCalendarDayType
getCalendarDayType
getDayType
Hours addCalendarHours
getCalendarHours
getHours
Minutes Per Day setCalendarMinutesPerDay
getCalendarMinutesPerDay
getMinutesPerDay
Minutes Per Week setCalendarMinutesPerWeek
getCalendarMinutesPerWeek
getMinutesPerWeek
Minutes Per Month setCalendarMinutesPerMonth
getCalendarMinutesPerMonth
getMinutesPerWeek
Minutes Per Year setCalendarMinutesPerYear
getCalendarMinutesPerYear
getMinutesPerYear
The first column give us the name of the attribute, and the second column give the name of the method we'd call to set that attribute for the current calendar. The third column gives us the name of the method we'd use to retrieve the attribute from the current calendar only (i.e this will ignore any parent calendars). Finally the last column gives us the name of the method we'd call to retrieve the attribute from the current calendar, or inherit that attribute from a parent calendar if it is not present in the current calendar.
We haven't looked at the Minutes Per X attributes so far. The values they contain are used when calculating working time. One interesting point to note is that if no calendars in a hierarchy define these values the default values will be retrieved from from the ProjectFile
configuration, which is represented by the ProjectConfig
class.
"},{"location":"howto-use-calendars/#how-deep-is-your-hierarchy","title":"How deep is your Hierarchy?","text":"
MPXJ will allow you to create an arbitrarily deep hierarchy of calendars if you wish by establishing parent-child relationships between the calendars you create. Most schedule application file formats will only support a limited hierarchy of calendars, which you will see when you read files of this type when using MPXJ. The notes below briefly outlines how calendar hierarchies operate in some of the applications MPXJ can work with.
If you are using MPXJ to create or modify schedule data, when you write the results to a file MPXJ will attempt to ensure that the calendars it writes to the file format you have chosen reflect what the target application is expecting. This means that MPXJ may end up \"flattening\" or otherwise simplifying a set of calendars and their hierarchy to ensure that they are read correctly by the target application and are \"functionally equivalent\" in use.
"},{"location":"howto-use-calendars/#microsoft-project","title":"Microsoft Project","text":"
Microsoft Project uses two tiers of calendars. The first tier of calendars are referred to as \"base calendars\", one of which is marked as the default calendar for the project. Work is scheduled based on the default calendar, unless a task explicitly selects a different base calendar to use when being scheduled, or resources with their own calendars have been assigned to the task. Each resource will have its own calendar, which is always derived from a base calendar.
Note that, as you might expect, material resources don't have a calendar!
"},{"location":"howto-use-calendars/#primavera-p6","title":"Primavera P6","text":"
The situation with P6 is a little more complicated, although it's still a two tier arrangement. P6 has the concept of Global calendars (broadly similar to base calendars in Microsoft Project). These can be assigned to activities in any project. Global calendars are never derived from other calendars.
You can also have Project calendars which, as their name suggests, can only be assigned to activities in the project to which they belong. Project calendars can be derived from a Global Calendar, or they can have no parent calendar.
Finally you can have two types of resource calendar: Shared, or Personal. These can either be derived from a Global calendar, or can have no parent. A Shared resource calendar can be assigned to multiple resources, but a Personal resource calendar can only be assigned to a single resource.
When reading a P6 schedule, the ProjectCalendar
method getType
can be used to retrieve the calendar type (Global, Shared, or Personal), while the getPersonal
method returns a Boolean flag indicating if the calendar is a Personal resource calendar.
"},{"location":"howto-use-calendars/#others","title":"Others","text":"
ConceptDraw, Planner, SureTrak and TurboProject all support some form of calendar hierarchy, although Planner is the only one which definitely supports an arbitrarily deep nested calendar structure.
"},{"location":"howto-use-calendars/#calendar-container","title":"Calendar Container","text":"
So far we've looked at creating and configuring calendars, and lining them together in a hierarchy. If we've just read a schedule in from a file, how can we examine the calendars it contains? Let's set up some calendars and take a look:
ProjectFile file = new ProjectFile();\nProjectCalendar calendar1 = file.addCalendar();\ncalendar1.setName(\"Calendar 1\");\n\nProjectCalendar calendar2 = file.addCalendar();\ncalendar2.setName(\"Calendar 2\");\n\nProjectCalendar calendar3 = file.addCalendar();\ncalendar2.setName(\"Calendar 3\");\n
Our sample code above creates three calendars, each with a distinct name. To see what calendars our file contains we can use the ProjectFile
method getCalendars
:
file.getCalendars().forEach(c -> System.out.println(c.getName()));\n
Which gives us the following output, as we'd expect:
Calendar 1\nCalendar 2\nCalendar 3\n
The getCalendars
method returns an object which implements the List<ProjectCalendar>
interface, but it also does more for us than just that. The actual object being returned is a ProjectCalendarContainer
, which is in charge of managing the calendars in the file and making it easy to access them.
The typical way this is done is through the use of the calendar's Unique ID attribute. Each calendar has an Integer
Unique ID, typically this is read as part of the calendar information from a schedule file, or if you are creating a schedule yourself, the default is for the Unique ID to be automatically populated. Let's see:
file.getCalendars().forEach(c -> System.out.println(c.getName() \n + \" (Unique ID: \" + c.getUniqueID() + \")\"));\n
Here's what we get:
Calendar 1 (Unique ID: 1)\nCalendar 2 (Unique ID: 2)\nCalendar 3 (Unique ID: 3)\n
Let's use a Unique ID to retrieve a calendar:
ProjectCalendar calendar = file.getCalendars().getByUniqueID(2);\nSystem.out.println(calendar.getName());\n
Here's the result of running this code:
Calendar 2\n
The ProjectCalendarContainer
class also allows us to retrieve calendars by name, although that's not recommended as MPXJ doesn't enforce presence or uniqueness constraints on calendar names.
Most of the time accessing a calendar from some other part of MPXJ is handled for you, for example to retrieve a resource's calendar you just need to call the Resource
method getCalendar
rather than having to use ProjectCalendarContainer
to retrieve it by Unique ID.
"},{"location":"howto-use-calendars/#calendar-relationships","title":"Calendar Relationships","text":"
The ProjectCalendar
class provides a variety of methods to allow us to explore how it relates to other calendars and the rest of the schedule.
As we've been discussing the hierarchy of calendars, the first method we can try is isDerived
, which will return true
if this calendar has been derived from a parent calendar. Alongside this we can also use the getParent
method to retrieve this calendar's parent. We can traverse a hierarchy of calendars using this method until getParent
returns null
at which point we know we have reached a \"base\" calendar and can go no further.
Calendars can also be assigned to both Tasks and Resources. The getTasks
and getResources
methods will each retrieve a list of the tasks and resources which explicitly use this calendar.
Finally, earlier in this section we mentioned the idea of the default calendar for a project. We can set or retrieve the default calendar using the ProjectFile
methods setDefaultCalendar
and getDefaultCalendar
, as illustrated below.
ProjectFile file = new ProjectFile();\nProjectCalendar calendar = file.addDefaultBaseCalendar();\nfile.setDefaultCalendar(calendar);\nSystem.out.println(\"The default calendar name is \"\n + file.getDefaultCalendar().getName());\n
As the name suggests, the default calendar will be used for all date, time, duration and work calculations if no other calendar has been assigned explicitly.
"},{"location":"howto-use-external-projects/","title":"How To: Use External Projects","text":"
From a schedule in Microsoft Project you can work with data from other project files in three ways: Subprojects, External Predecessors, and Resource Pools.
"},{"location":"howto-use-external-projects/#subprojects","title":"Subprojects","text":"
Microsoft Project allows you to manage larger projects by breaking them down into Subprojects. From one MPP file, a link can be added to another MPP file forming a parent-child relationship. The child MPP file will appear as a summary task in the location you've selected within the parent file. When this summary task is expanded the tasks from the child MPP file will appear seamlessly as tasks in the parent file.
"},{"location":"howto-use-external-projects/#identifying-subproject-tasks","title":"Identifying Subproject Tasks","text":"
If you use MPXJ to read an MPP file that contains a Subproject, initially you won't see anything different to a file which just contains ordinary tasks: the Subproject will just appear as a normal summary task whose attributes will roll up the details from the Subproject. If you want you can just work with the task as-is, you only need to so something different if you want to work with the contents of the Subproject.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.Task;\nimport net.sf.mpxj.reader.UniversalProjectReader;\n\n...\n\nProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfor (Task task : file.getTasks())\n{\n if (task.getExternalProject())\n {\n System.out.println(task.getName() + \" is a subproject\");\n System.out.println(\"Path to the file is: \" +\n task.getSubprojectFile());\n System.out.println(\"GUID of this project is: \" +\n task.getSubprojectGUID());\n System.out.println(\"Offset used when displaying Unique ID values is: \" +\n task.getSubprojectTasksUniqueIDOffset());\n }\n}\n
The example above illustrates how we can identify a Subproject by using a task's External Project attribute. Once we have identified that we have a Subproject we can determine where the file is located, using the Subproject File attribute, and the GUID of this project, using the Subproject GUID attribute.
The last attribute we're looking at in this example is the Subproject Tasks Unique ID Offset. When Microsoft Project provides a combined view of two or more MPP files using Subprojects, one issue is that the Unique ID values in each project will no longer be unique. To get around this problem Microsoft Project adds an offset to the Unique ID values of the tasks it displays from each Subproject to ensure that each one has a distinct value. This offset is the value we're retrieving using the getSubprojectTasksUniqueIDOffset
method.
"},{"location":"howto-use-external-projects/#reading-subproject-data","title":"Reading Subproject Data","text":"
If you wish, you can use UniversalProjectReader
directly to load the external project, as the example below illustrates:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nString filePath = externalProjectTask.getSubprojectFile();\nProjectFile externalProjectFile = new UniversalProjectReader().read(filePath);\n
The code above assumes that the file is located on a readable filesystem at the exact path specified by the Subproject File attribute.
Note that these examples assume that the file is on a filesystem which is directly readable. For MPP files exported from Project Server, it is likely that the path to an external project will be in the form <>\\FileName
which represents a project hosted by Project Server. MPXJ cannot open this type of external project.
An alternative to writing your own code to do this would be to use the method provided by MPXJ, as illustrated below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nProjectFile externalProjectFile = externalProjectTask.getSubprojectObject();\n
The advantage of this approach, apart from using less code, is that MPXJ will attempt to find the file in locations other than the full path provided in Subproject File. By default the other place MPXJ will look is in the working directory of the current process, however this behaviour can be configured as the example below illustrates:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfile.getProjectConfig().setSubprojectWorkingDirectory(new File(\"/path/to/dir\"));\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nProjectFile externalProjectFile = externalProjectTask.getSubprojectObject();\n
In the code above we're calling the setSubprojectWorkingDirectory
method to give MPXJ details of a directory to look in when attempting to read an external project.
Note that if MPXJ can't load the external project for any reason, the getSubprojectObject
method will return null
.
"},{"location":"howto-use-external-projects/#expanding-subproject-data","title":"Expanding Subproject Data","text":"
In Microsoft Project, when a Subproject task is expanded it behaves just like any other summary task by revealing the child tasks it contains. We can reproduce this behavior using the code shown in the sample below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nTask externalProjectTask = file.getTaskByID(Integer.valueOf(1));\nSystem.out.println(\"Has child tasks? \" + externalProjectTask.hasChildTasks());\nexternalProjectTask.expandSubproject();\nSystem.out.println(\"Has child tasks? \" + externalProjectTask.hasChildTasks());\n
The expandSubproject
method attempts to open the external project, and if successful attaches the tasks from the external project as children of the external project task. You are then able to access the tasks from the parent project along with the tasks from the external project as part of the same MPXJ ProjectFile instance.
Note that when using the expandSubproject
method, the setSubprojectWorkingDirectory
method on ProjectConfig
can be used to tell MPXJ where to find the external projects in the same way we did when using the getSubprojectObject
method.
You can also do this globally and expand all Subproject tasks in a project by using the expandSubprojects
method on the project file itself:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfile.expandSubprojects(false);\n
Remember that all the \"expand subproject\" functionality described in the notes above is doing is attaching the tasks from one ProjectFile
instance as child tasks of a task in another ProjectFile
instance. This will allow you to recursively descend through the tasks in a project and any subprojects. However, these tasks still belong to separate ProjectFile
instances, so calling the getTasks()
method on the top level ProjectFile
instance will only return the tasks from that project, and will not include tasks from any subprojects.
"},{"location":"howto-use-external-projects/#external-predecessors","title":"External Predecessors","text":"
The second way an external project can be referenced in a Microsoft Project schedule is through the use of an external predecessor task. Project allows you to enter the task ID for a predecessor in the form myproject.mpp\\123
which selects the task with ID 123
in myproject.mpp
as the predecessor of the task in the schedule you are working on.
When you use an external predecessor task like this, Project includes a \"placeholder\" task in your current schedule which represents the task in the external project and has a copy of all of the relevant attributes of the task from the external project. In many cases this placeholder task is all you need to work with the schedule.
When you are working with MPXJ, how can you identify that you are looking at a placeholder task representing an external predecessor? The sample code below illustrates this:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nfor (Task task : file.getTasks())\n{\n if (task.getExternalTask())\n {\n System.out.println(task.getName() + \" is an external predecessor\");\n System.out.println(\"The path to the file containing this task is: \"\n + task.getSubprojectFile());\n System.out.println(\"The ID of the task in this file is: \"\n + task.getSubprojectTaskID());\n System.out.println(\"The Unique ID of the task in this file is: \"\n + task.getSubprojectTaskUniqueID());\n }\n}\n
As the code above illustrates, if the getExternalTask
method return true, the task is an external predecessor. As illustrated by the code there are three relevant attributes: Subproject File (the location of the external project this predecessor belongs to), and the Subproject Task ID and Subproject Task Unique ID which are the ID and Unique ID of the task in the schedule it comes from.
As with a task representing an external project, you can retrieve the project for an external predecessor task using the getSubprojectObject
method. Note however that the expandSubproject
method will have no effect as the external predecessor task does not represent an entire project!
"},{"location":"howto-use-external-projects/#predecessors-and-successors-from-subprojects","title":"Predecessors and Successors from Subprojects","text":"
As we saw in a previous section, when working with Microsoft Project you can configure a project with a number of subprojects. When this is the case you can also create predecessor or successor relationships between tasks in any of these projects. When you open your MPP file in Microsoft Project, and all of the subprojects can also be opened, then Microsoft Project will present you with a unified view of the tasks and their relationships, even though the relationships cross different files. However, if you open your project but do not have the subproject files available, you will see placeholder external tasks representing the predecessor or successor tasks from the missing subproject files.
When reading the file using MPXJ, you will encounter the same situation: opening your MPP file without any of the subprojects being available you will see placeholder external tasks for predecessor and successor tasks from the subproject files. As we have already seen, the expandSubprojects
method can be used to expand all subprojects, if the files they represent are available, allowing you to traverse the hierarchy of tasks. The expandSubprojects
method also offers some additional functionality: when you pass true
to this method, MPXJ will attempt to replace any predecessor or successor relationships which include placeholder external tasks with relationships which refer to the original task from a subproject, and those placeholder external tasks will be removed from the project entirely. This functionality is intended to replicate what you would see if you opened your file in Microsoft Project and all subprojects were successfully loaded.
As noted previously, the expandSubprojects
method is only stitching together a set of individual ProjectFile
instances so the tasks they contain can be traversed seamlessly, and in this case the predecessor and successor relationships between those tasks no longer use placeholder external tasks. This is still not a single unified ProjectFile
instance so care should be taken when working with this data to bear in mind that it comes from a number of separate files.
"},{"location":"howto-use-external-projects/#resource-pools","title":"Resource Pools","text":"
The final way an external project can be used from a Microsoft Project schedule is as a resource pool. A resource pool schedule allows you to capture details of all of your organisation's resources in one place, then refer to them from multiple schedules. Setting up a resource pool like this should ensure that your resource utilisation across different projects is accurately captured as the utilisation detail in the resource pool is updated by the projects using those resources.
The full path for a project's resource pool can be retrieved using the getResourcePoolFile
method as illustrated below:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nString path = file.getProjectProperties().getResourcePoolFile();\n
In a similar manner to the other external project examples given in previous sections, MPXJ can also open and read the resource pool file for you:
ProjectFile file = new UniversalProjectReader().read(\"sample.mpp\");\nProjectFile resourcePool = file.getProjectProperties().getResourcePoolObject();\n
"},{"location":"howto-use-external-projects/#mspdi-files","title":"MSPDI Files","text":"
Much of the detail noted above is also applicable to MSPDI files, but with the following exceptions:
getSubprojectObject
method on the task, or you can call the expandSubproject
or expandSubprojects
methods documented in the previous sections to show the tasks contained in the Subproject as part of the main project.Note that although Microsoft Project will write external predecessor information to an MSPDI file, it will fail to load these correctly when the MSPDI file is reopened.
"},{"location":"howto-use-fields/","title":"How To: Use Fields","text":"
Once you've read a schedule using MPXJ, and you have a ProjectFile
instance with tasks, resources and resource assignments, how do you access the data represented as fields in each of these entities? If you're creating or updating a schedule, how can you assign values to fields? This section explains the different approaches you can take in each of these cases.
"},{"location":"howto-use-fields/#setter-and-getter-methods","title":"Setter and Getter Methods","text":"
Let's start by creating a task we can use to demonstrate some of these approaches:
ProjectFile file = new ProjectFile();\nTask task = file.addTask();\n
When you already know exactly which field you need to access, you can work with the data these fields contain in a type-safe way by using the setter and getter methods provided by each class, for example:
task.setName(\"Task 1\");\n\nString name = task.getName();\nSystem.out.println(\"Task name: \" + name);\n
Here's the output from the sample code:
Task name: Task 1\n
Here we can see that we are able to set the name of the task using a String
, and when we call the getter method we'll be returned the name as a String
. How about working with a field that has a type other than a String?
LocalDateTime startDate = LocalDateTime.of(2022, 5, 10, 8, 0);\ntask.setStart(startDate);\n\nSystem.out.println(\"Start date: \" + task.getStart());\n
Here's the output from the sample code:
Start date: 2022-05-10T08:00\n
We're setting and retrieving the task's start date using a LocalDateTime
instance. For almost all of the fields supported by tasks, resources, and resource assignments you'll find a pair of getter and setter methods allowing you to access and modify the field with a convenient type safe interface.
"},{"location":"howto-use-fields/#field-enumerations","title":"Field Enumerations","text":"
What if we don't know ahead of time which fields we need to access? For example, what if our application allows users to choose which fields to display for each task? In this case we can use a data-driven approach to read and write fields, as shown in the example below.
task = file.addTask();\ntask.set(TaskField.NAME, \"Task 2\");\n\nname = (String)task.get(TaskField.NAME);\nSystem.out.println(\"Task name: \" + name);\n\nstartDate = LocalDateTime.of(2022, 5, 11, 8, 0);\ntask.set(TaskField.START, startDate);\n\nSystem.out.println(\"Start date: \" + task.getStart());\n
Here's the output from this sample code:
Task name: Task 2\nStart date: 2022-05-11T08:00\n
What are the TaskField
values in the example above? TaskField
is an enumeration representing all of the fields of a Task
instance. This type of enumeration is not unique to tasks, there are four main enumerations available:
ProjectField
: fields available from ProjectProperties
ResourceField
: fields available from a Resource
TaskField
: fields available from a Task
AssignmentField
: fields available from a ResourceAssignment
The ProjectProperties
, Resource
, Task
and ResourceAssignment
classes noted above actually all implement the FieldContainer
interface. This is the interface that gives us the get
and set
methods we've seen in the examples above. FieldContainer
also provides us with one more interesting method: getCachedValue
. What is this, and why is it different to the get
method? Let's take a step back and look at calculated values to understand where getCachedValue
fits in.
"},{"location":"howto-use-fields/#calculated-fields","title":"Calculated Fields","text":"
Some of the fields available from each of these classes can actually contain a calculated value. For example: the Task
field \"Start Variance\" represents the difference between the Baseline Start date and the Start date of a task. Some schedules may provide this value for us when we read the data they contain, others may not. If we don't have this value when we read our schedule data, but we do have a Baseline Start and Start date available to us, then we can perform the calculation ourselves to produce the Start Variance value. The example below illustrates this:
// Set up the sample project\nProjectFile file = new ProjectFile();\n\n// We need at least a default calendar to calculate variance\nfile.setDefaultCalendar(file.addDefaultBaseCalendar());\n\n// Create tasks\nTask task1 = file.addTask();\nTask task2 = file.addTask();\n\n// Set up example dates\nLocalDateTime baselineStart = LocalDateTime.of(2022, 5, 1, 8, 0);\nLocalDateTime startDate = LocalDateTime.of(2022,5, 10, 8, 0);\n\n// Update task1 using methods\ntask1.setStart(startDate);\ntask1.setBaselineStart(baselineStart);\n\n// Update task2 using TaskField enumeration\ntask2.set(TaskField.START, startDate);\ntask2.set(TaskField.BASELINE_START, baselineStart);\n\n// Show the variance being retrieved by method and TaskField enumeration\nSystem.out.println(\"Task 1\");\nSystem.out.println(\"Start Variance from method: \"\n + task1.getStartVariance());\nSystem.out.println(\"Start Variance from get: \"\n + task1.get(TaskField.START_VARIANCE));\nSystem.out.println();\n\nSystem.out.println(\"Task 2\");\nSystem.out.println(\"Start Variance from method: \"\n + task2.getStartVariance());\nSystem.out.println(\"Start Variance from get: \"\n + task2.get(TaskField.START_VARIANCE));\n
Here's the output from running this code:
Task 1\nStart Variance from method: 6.0d\nStart Variance from get: 6.0d\n\nTask 2\nStart Variance from method: 6.0d\nStart Variance from get: 6.0d\n
Regardless of how we set up the data, both the getStartVariance
method and the call to get(TaskField.START_VARIANCE)
trigger the calculation and produce the expected Start Variance value.
Rather than immediately discarding the Start Variance value we've just calculated, this value is cached as part of the data held by the task, and will be returned next time we use the getStartVariance
method or we call get(TaskField.START_VARIANCE)
.
"},{"location":"howto-use-fields/#cached-values","title":"Cached Values","text":"
The getCachedValue
method allows us to retrieve a field without attempting to calculate a value. It's not a method you'd normally expect to use, but it's worth mentioning for completeness. Let's take a look at this using a new example:
// Set up the sample project with a default calendar\nProjectFile file = new ProjectFile();\nfile.setDefaultCalendar(file.addDefaultBaseCalendar());\n\n// Set up example dates\nLocalDateTime baselineStart = LocalDateTime.of(2022, 5, 1, 8, 0);\nLocalDateTime startDate = LocalDateTime.of(2022,5, 10, 8, 0);\n\n// Create a task\nTask task = file.addTask();\ntask.setStart(startDate);\ntask.setBaselineStart(baselineStart);\n\nSystem.out.println(\"Start Variance using getCachedValue(): \" \n + task.getCachedValue(TaskField.START_VARIANCE));\nSystem.out.println(\"Start Variance using get(): \" \n + task.get(TaskField.START_VARIANCE));\nSystem.out.println(\"Start Variance using getCachedValue(): \" \n + task.getCachedValue(TaskField.START_VARIANCE));\n
The output from this code is:
Start Variance using getCachedValue(): null\nStart Variance using get(): 6.0d\nStart Variance using getCachedValue(): 6.0d\n
What we can see happening here is that using the getCachedValue
method initially returns null
as the Start Variance is not present, and MPXJ doesn't attempt to calculate it. When we use the get
method, MPXJ sees that it doesn't have a value for this field and knows how to calculate it, and returns the expected result. Finally if we use the getCachedValue
method again, as we've now calculated this value and cached it, the method returns the Start Variance.
In summary, getCachedValue
will never attempt to calculate values for fields which are not already present. This can be useful if you want to read a schedule using MPXJ, but retrieve only the fields which were in the original schedule, not calculated or inferred by MPXJ.
"},{"location":"howto-use-fields/#fieldtype","title":"FieldType","text":"
Earlier in this section we noted that there were four main enumerations representing the fields which particular classes can contain.
ProjectField
ResourceField
TaskField
AssignmentField
What I didn't mention then is that each of these enumerations implements the FieldType
interface which defines a common set of methods for each of these enumerations. The most interesting of these methods are:
name()
getName()
getFieldTypeClass()
getDataType()
The name()
method retrieves the name of the enumeration value exactly as it appears in the code. The getName()
method returns a localized version of the name, suitable for display to end users (currently English is the default and only supported locale).
The getFieldTypeClass()
method returns a value from the FieldTypeClass
enumeration which will help you to determine which kind of object this FieldType
belongs to (for example task, resource, and so on). Finally the getDataType()
method will return a value from the DataType
enumeration which indicates the data type you will receive from the get
method when accessing this field, and the type to pass to the set
method when updating the field.
Here's some example code to make this a little clearer:
FieldType type = TaskField.START_VARIANCE;\n\nSystem.out.println(\"name(): \" + type.name());\nSystem.out.println(\"getName(): \" + type.getName());\nSystem.out.println(\"getFieldTypeClass(): \" + type.getFieldTypeClass());\nSystem.out.println(\"getDataType():\" + type.getDataType());\n
In this case we're using the Task Start Variance field as an example. Here's the output:
name(): START_VARIANCE\ngetName(): Start Variance\ngetFieldTypeClass(): TASK\ngetDataType(): DURATION\n
Returning to our earlier example of how we might allow a user to select fields we will display, we can use the data type of the selected field to determine how we format the value for display.
private String getValueAsText(FieldContainer container, FieldType type)\n{\n Object value = container.get(type);\n if (value == null)\n {\n return \"\";\n }\n\n String result;\n switch (type.getDataType())\n {\n case CURRENCY:\n {\n result = new DecimalFormat(\"\u00a30.00\").format(value);\n break;\n }\n\n case DATE:\n {\n result = DateTimeFormatter.ofPattern(\"dd/MM/yyyy\").format((LocalDateTime)value);\n break;\n }\n\n case BOOLEAN:\n {\n result = ((Boolean)value).booleanValue() ? \"Yes\" : \"No\";\n break;\n }\n\n default:\n {\n result = value.toString();\n break;\n }\n }\n\n return result;\n}\n
The sample code above implements a generic method which can work with any class implementing the FieldContainer
interface (for example, Task
, Resource
and so on). Given the particular field the user has asked us to display (passed in via the type
argument), we retrieve the value from the container as an Object
, then use the data type to decide how best to format the value for display. (This is obviously a contrived example - I wouldn't recommend creating new instances of DecimalFormat
and DateTimeFormatter
each time you need to format a value!)
"},{"location":"howto-use-fields/#custom-fields","title":"Custom Fields","text":"
So far we've seen how simple fields like Name and Start can be accessed and modified using both field-specific and generic methods. Name and Start are examples of standard fields which might be provided and managed by schedule applications, and have a well understood meaning. What if we have some additional data we want to capture in our schedule, but that data doesn't fit into any of these standard fields?
Microsoft Project's solution to this problem is Custom Fields. By default Microsoft Project provides a number of general purpose fields with names like \"Text 1\", \"Text 2\", \"Date 1\", \"Date 2\" and so on, which can be used to relevant vales as part of the schedule. If we look for methods like setText1
or setDate1
we won't find them, so how can we work with these fields?
The answer is quite straightforward, for each of these custom fields you'll find getter and setter methods which take an integer value, for example:
task.setText(1, \"This is Text 1\");\nString text1 = task.getText(1);\nSystem.out.println(\"Text 1 is: \" + text1);\n
If you're working with the generic get
and set
methods, the situation is more straightforward as each individual field has its own enumeration, as shown below:
task.set(TaskField.TEXT1, \"This is also Text 1\");\ntext1 = (String)task.get(TaskField.TEXT1);\nSystem.out.println(\"Text 1 is: \" + text1);\n
For Task
, Resource
and ResourceAssignment
the following custom fields are available for use:
Task
and Resource
only)Microsoft Project allows users to configure custom fields. This facility can be used to do something as simple as provide an alias for the field, allowing it to be displayed with a meaningful name rather than something like \"Text 1\" or \"Date 1\". Alternatively there are more complex configurations available, for example constraining the values that can be entered for a field by using a lookup table, or providing a mask to enforce a particular format.
Information about custom field configurations can be obtained from the CustomFieldsContainer
. The sample code below provides a simple illustration of how we can query this data.
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nCustomFieldContainer container = file.getCustomFields();\nfor (CustomField field : container)\n{\n FieldType type = field.getFieldType();\n String typeClass = type.getFieldTypeClass().toString();\n String typeName = type.name();\n String alias = field.getAlias();\n System.out.println(typeClass + \".\" + typeName + \"\\t\" + alias);\n}\n
Depending on how the custom fields in your schedule are configured, you'll see output like this:
TASK.TEXT1 Change Request Reason\nTASK.NUMBER1 Number of Widgets Required\nRESOURCE.DATE1 Significant Date\n
In the source above, the first thing we're retrieving from each CustomField
instance is the FieldType
, which identifies the field we're configuring. The values we retrieve here will be from one of the enumerations we've touched on previously in this section, for example TaskField
, ResourceField
and so on.
The next thing we're doing in our sample code is to create a representation of the parent type to which this field belongs, followed by the name of the field itself (this is what's providing us with the value TASK.TEXT1
for example). Finally we're displaying the alias which has been set by the user for this field.
It's important to note that for schedules from Microsoft Project, there won't necessarily be a CustomField
entry for all of the custom fields in use in a schedule. For example, if a user has added values to the \"Text 1\" field for each of the tasks in their schedule, but have not configured Text 1 in some way (for example by setting an alias or adding a lookup table) there won't be an entry for \"Text 1\" in the CustomFieldContainer
.
As well as iterating through the collection of CustomField
instances for the current schedule, you can directly request the CustomField
instance for a specific field, as shown below:
CustomField fieldConfiguration = container.get(TaskField.TEXT1);\n
One common use-case for the configuration data help in CustomFieldContainer
is to locate particular information you are expecting to find in the schedule. For example, let's say that you know that the schedule you're reading should have a field on each task which users have named \"Number of Widgets Required\", and you want to read that data. You can determine which field you need by using a method call similar to the one shown below:
FieldType fieldType = container.getFieldTypeByAlias(\n FieldTypeClass.TASK,\n \"Number of Widgets Required\");\n
Note that the first argument we need to pass identifies which parent entity we're expecting to find the field in. The CustomFieldContainer
will have entries from all field containers (tasks, resources, resource assignments and so on) so this is used to locate the correct one - particularly useful if, for example, a task and a resource might both have a field with the same alias! Remember: this method will return null
if we don't have a field with the alias you've provided.
Once we have the FieldType
of the field we're looking for, we can use this to retrieve the value using the get
method as we've seen earlier in this section:
Task task = file.getTaskByID(Integer.valueOf(1));\nObject value = task.get(fieldType);\n
Finally, there are a couple of convenience methods to make retrieving a field by its alias easier. The first is that each \"container\" class for the various entities also provides a getFieldTypeByAlias
method. If you know ahead of time you're looking for a field in a particular entity, this will simplify your code somewhat. The example below illustrates this: as we're looking for a task field we can go straight to the TaskContainer
and ask for the field with the alias we're looking for:
fieldType = file.getTasks().getFieldTypeByAlias(\"Number of Widgets Required\");\n
Lastly, you can actually retrieve the value of a field directly from the parent entity using its alias, as shown below:
value = task.getFieldByAlias(\"Number of Widgets Required\");\n
This is not recommended where you are iterating across multiple tasks to retrieve values: it's more efficient to look up the FieldType
once before you start, then use that to retrieve the value you are interested in from each task.
"},{"location":"howto-use-fields/#populated-fields","title":"Populated Fields","text":"
So far we've touched on how to can read and write fields in examples where we are targeting specific fields. If we're reading a schedule whose contents are unknown to us, how can we tell which fields are actually populated? A typical use-case for this might be where we need to read a schedule, then present the user with the ability to select the columns they'd like to see in a tabular display of the schedule contents. If you look at the various enumerations we have mentioned previously in this section (TaskField
, ResourceField
and so on) you can see that there are a large number of possible fields a user could choose from, so ideally we only want to show a user fields which actually contain non-default values.
To solve this problem we need to use the appropriate getPopulatedFields
method for each of the entities we're interested in.
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nSet<ProjectField> projectFields = file.getProjectProperties().getPopulatedFields();\nSet<TaskField> taskFields = file.getTasks().getPopulatedFields();\nSet<ResourceField> resourceFields = file.getResources().getPopulatedFields();\nSet<AssignmentField> assignmentFields = file.getResourceAssignments().getPopulatedFields();\n
In the example above we're opening a sample file, then for each of the main classes which implement the FieldContainer
interface, we'll query the container which holds those classes and call its getPopulatedFields
method. In each case this will return a Set
containing the enumeration values representing fields which have non-default values.
If you need to you can retrieve all of this information in one go:
ProjectFile file = new UniversalProjectReader().read(\"example.mpp\");\n\nSet<ProjectField> allFields = file.getPopulatedFields();\n
The set returned by the project's getPopulatedFields
will contain all the populated fields from all entities which implement the FieldContainer
interface. You'll need to remember to look at the FieldTypeClass
value of each field in the resulting set to determine which entity the field belongs to. The following section provides more detail on this.
"},{"location":"howto-use-fields/#user-defined-fields","title":"User Defined Fields","text":"
In an earlier section we touched briefly on how Microsoft Project uses a fixed set of \"custom fields\" to allow you to store arbitrary data as part of the schedule. A more common approach in other applications is to allow you to create your own fields to represent the data you need to store - that way you can have exactly the fields you need, without needing to worry if you can fit your data into the fixed set of custom fields. In fact Microsoft Project also supports this concept, in the form of Enterprise Custom Fields, although these are only available if you are working with a schedule hosted in Project Server (Project 365).
As you can imagine MPXJ can't provide dedicated getter and setter methods for these fields as it doesn't know ahead of time what they are - they're user defined! Instead we rely on the get
and set
methods to work with these fields.
When a schedule is read by MPXJ, each user defined field is represented internally by an instance of the UserDefinedField
class. This class implements the FieldType
interface, and so can be used with the get
and set
methods to read and write these values.
You can see which user defined fields exist in a project using code similar to the example below:
for (UserDefinedField field : project.getUserDefinedFields())\n{\n System.out.println(\"name(): \" + field.name());\n System.out.println(\"getName(): \" + field.getName());\n System.out.println(\"getFieldTypeClass(): \" + field.getFieldTypeClass());\n System.out.println(\"getDataType():\" + field.getDataType()); \n}\n
As well as using the getUserDefinedFields
method on the project to see which fields are defined, the getPopulatedFields
methods discussed in an earlier section will also return UserDefinedField
instances if these fields have values in the schedule. Information about UserDefinedField
instances is also available in the CustomFieldContainer
. This means that when you read a schedule and you are expecting certain user defined fields to be present, you can use the getFieldTypeByAlias
or getFieldByAlias
methods to find the fields you are interested in by name, as described in an earlier section.
If you import schedules data from an application which supports user defined fields and export to a Microsoft Project file format (MPX or MSPDI), MPXJ will automatically map any user defined fields to unused custom fields. Note that as there are only a finite number of custom field available, it is possible that not all user defined fields will be available when the resulting file is opened in Microsoft Project.
"},{"location":"howto-use-universal/","title":"How To: Use the Universal Project Reader","text":"
As you may have seen elsewhere in this documentation, the preferred way to read from most sources of schedule data is to use the UniversalProjectReader
:
ProjectReader reader = new UniversalProjectReader ();\nProjectFile project = reader.read(\"example.mpp\");\n
This is very convenient as you don't need to know ahead of time what type of schedule file you are working with, UniversalProjectReader
will figure this out for you. The drawback to this approach is that for a number of schedule types, the reader class for that type may provide additional configuration options to guide the way schedule data is read. In the example above, you can see that there is no opportunity to provide any extra configuration to the reader class selected by UniversalProjectReader
.
To get around this issue, UniversalProjectReader
provides access to \"project reader proxy\" classes. These proxy classes implement the UniversalProjectReader.ProjectReaderProxy
interface and provide access to the reader class which UniversalProjectReader
has selected to read the project data at the point just before schedule data has been read.
You can use these proxy classes to, for example, choose whether or not to continue reading the type of schedule contained in the supplied file or stream, or you can change the reader's settings before continuing to read the schedule. The example code below illustrates both these situations.
UniversalProjectReader upr = new UniversalProjectReader();\n\n// Retrieve the proxy\ntry (UniversalProjectReader.ProjectReaderProxy proxy = upr.getProjectReaderProxy(file))\n{\n // Retrieve the reader class\n ProjectReader reader = proxy.getProjectReader();\n\n // Determine if we want to continue processing this file type.\n // In this example we are ignoring SDEF files.\n if (reader instanceof SDEFReader)\n { \n return;\n }\n\n // Provide configuration for specific reader types.\n // In this example we are changing the behavior of the Phoenix reader.\n if (reader instanceof PhoenixReader)\n {\n ((PhoenixReader)reader).setUseActivityCodesForTaskHierarchy(false);\n }\n\n // Finally, we read the schedule\n ProjectFile project = proxy.read();\n\n // Now we can work with the schedule data...\n}\n
The first thing to notice is that the proxy class is being used within a \"try with resources\" statement. This is important as the UniversalProjectReader
may have a number of resources open (streams, temporary files, and so on) which need to be released once you have finished with the proxy class. UniversalProjectReader.ProjectReaderProxy
implements the AutoCloseable
interface, so you can either arrange to explicitly call the close
method yourself at an appropriate point, or you can use try with resources to ensure this happens automatically.
The initial line of the try
statement calls getProjectReaderProxy
to retrieve the proxy. This method can be called with either a file name, a File
instance, or an InputStream
. Within the try
block, the first thing we do is retrieve the reader class instance which the UniversalProjectReader
has selected to read our schedule data.
The next two stanzas of code use instanceof
to determine the type of the reader selected: in the first stanza we're choosing not to continue if we've been provided with an SDEF file. In the second stanza, if we are dealing with a Phoenix schedule, we're choosing to change the default behavior of the reader.
Finally at the end of the try
block we're calling the read
method of the proxy to read the schedule. The proxy also provides a readAll
method: if the source data contains multiple schedules you can use this method to read them all.
Note that we're using the read
or readAll
methods provided by the proxy class, we're not attempting to use the methods provided on the reader class itself. This is important as the UniversalProjectReader
may have located the schedule within a larger set of data, for example within a Zip file or sub-directory. The proxy class already has this context, whereas you won't necessarily have this information if you tried to use the reader class methods directly.
"},{"location":"howto-write-mpx/","title":"How To: Write MPX files","text":"
Versions of Microsoft Project up to Project 98 could read and write MPX files as a data interchange format. Versions of Project after Project 98 until Project 2010 can only read MPX files. Versions of Microsoft Project after 2010 cannot read MPX files. Other third party project planning applications continue to use MPX as a data interchange format.
The sample code below illustrates how to write data to an MPX file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mpx.MPXWriter;\n\n// ...\n\nMPXWriter writer = new MPXWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/","title":"How To: Write MSPDI files","text":"
Since Microsoft Project 2002, Microsoft Project has been able to read and write an XML-based data interchange format called MSPDI.
"},{"location":"howto-write-mspdi/#writing-mspdi-files","title":"Writing MSPDI files","text":"
The sample code below illustrates how to write data to an MSPDI file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#using-mspdiwriter","title":"Using MSPDIWriter","text":""},{"location":"howto-write-mspdi/#microsoft-project-compatible-output","title":"Microsoft Project Compatible Output","text":"
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
:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setMicrosoftProjectCompatibleOutput(false);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#save-version","title":"Save Version","text":"
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\nProject2003\nProject2007\nProject2010\nProject2013\nProject2016\n
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;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\nimport net.sf.mpxj.mspdi.SaveVersion;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setSaveVersion(SaveVersion.Project2002);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-mspdi/#timephased-data","title":"Timephased Data","text":"
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:
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setWriteTimephasedData(true);\nwriter.write(projectFile, outputFileName);\n
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;\nimport net.sf.mpxj.mspdi.MSPDIWriter;\n\n// ...\n\nMSPDIWriter writer = new MSPDIWriter();\nwriter.setWriteTimephasedData(true);\nwriter.setSplitTimephasedAsDays(false);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-planner/","title":"How To: Write Planner files","text":"
Gnome Planner is a simple cross platform planning tool. MPXJ can be used to write a schedule as a Planner file, which the Gnome Planner application can open.
The sample code below illustrates how to write data to a Planner file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.planner.PlannerWriter;\n\n// ...\n\nPlannerWriter writer = new PlannerWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-pmxml/","title":"How To: Write PMXML files","text":"
The XML file format supported by Primavera P6 for import and export is known as PMXML.
The sample code below illustrates how to write data to a PMXML file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileWriter;\n\n// ...\n\nPrimaveraPMFileWriter writer = new PrimaveraPMFileWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-pmxml/#using-primaverapmfilewriter","title":"Using PrimaveraPMFileWriter","text":""},{"location":"howto-write-pmxml/#baselines","title":"Baselines","text":"
By default baselines are not written to PMXML files. If the ProjectFile
instance you are writing contains a baseline, this can be included in the PMXML file by calling the setWriteBaselines
method as shown below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraPMFileWriter;\n\n// ...\n\nPrimaveraPMFileWriter writer = new PrimaveraPMFileWriter();\nwriter.setWriteBaselines(true);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-sdef/","title":"How To: Write SDEF files","text":"
SDEF is the Standard Data Exchange Format, as defined by the USACE (United States Army Corps of Engineers). SDEF is a fixed column format text file, used to import a project schedule up into the QCS (Quality Control System) software from USACE. The specification for the file format can be found here.
The sample code below illustrates how to write data to an SDEF file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFWriter;\n\n// ...\n\nSDEFWriter writer = new SDEFWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-sdef/#using-sdefwriter","title":"Using SDEFWriter","text":""},{"location":"howto-write-sdef/#charset","title":"Charset","text":"
By default SDEF files are written using the US_ASCII
charset. The setCharset
method on the SDEFWriter
class can be used to change this if required:
import java.nio.charset.StandardCharsets;\n\nimport net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.sdef.SDEFWriter;\n\n// ...\n\nSDEFWriter writer = new SDEFWriter();\nwriter.setCharset(StandardCharsets.UTF_8);\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-xer/","title":"How To: Write XER files","text":"
XER files have been imported and exported by Primavera software since the earliest days of P6 and this format is still often the preferred way to move schedule data between instances of P6 even today.
The sample code below illustrates how to write data to an XER file.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileWriter;\n\n// ...\n\nPrimaveraXERFileWriter writer = new PrimaveraXERFileWriter();\nwriter.write(projectFile, outputFileName);\n
"},{"location":"howto-write-xer/#using-primaveraxerfilewriter","title":"Using PrimaveraXERFileWriter","text":""},{"location":"howto-write-xer/#encoding","title":"Encoding","text":"
By default XER files written by MPXJ are encoded using the Windows-1252 character set. If you need to use a different encoding, the setCharset
or setEncoding
methods can be used to achieve this, as illustrated by the code below.
import net.sf.mpxj.ProjectFile;\nimport net.sf.mpxj.primavera.PrimaveraXERFileWriter;\n\n// ...\n\nPrimaveraXERFileWriter writer = new PrimaveraXERFileWriter();\n\n// Use a Charset instance\nwriter.setCharset(Charset.forName(\"GB2312\"));\nwriter.write(projectFile, outputFileName);\n\n// Use an encoding name\nwriter.setEncoding(\"GB2312\");\nwriter.write(projectFile, outputFileName);\n
"},{"location":"maven-reports/","title":"Maven Reports","text":"
Reports generated from the Maven project, including Javadocs, can be found here.
"},{"location":"mpp-field-guide/","title":"MPP Field Guide","text":""},{"location":"mpp-field-guide/#mpp-field-guide","title":"MPP Field Guide","text":"
The tables below provide an indication of which fields are populated when different MPP file versions are read using MPXJ The tables are not hand-crafted: they have been generated from test data and are therefore may be missing some details.
"},{"location":"mpp-field-guide/#project","title":"Project","text":""},{"location":"mpp-field-guide/#core-fields","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 AM Text \u2713 \u2713 \u2713 \u2713 Activity ID Increment \u2713 \u2713 \u2713 \u2713 Activity ID Increment Based On Selected Activity \u2713 \u2713 \u2713 \u2713 Activity ID Prefix \u2713 \u2713 \u2713 \u2713 Activity ID Suffix \u2713 \u2713 \u2713 \u2713 Application Version \u2713 \u2713 \u2713 \u2713 Author \u2713 \u2713 \u2713 \u2713 Auto Add New Resources and Tasks \u2713 \u2713 \u2713 \u2713 Auto Filter \u2713 \u2713 Auto Link \u2713 \u2713 \u2713 \u2713 Bar Text Date Format \u2713 \u2713 \u2713 \u2713 Calculate Float on Finish Date of Each Project \u2713 \u2713 \u2713 \u2713 Calculate Multiple Paths Using Total Float \u2713 \u2713 \u2713 \u2713 Category \u2713 \u2713 \u2713 \u2713 Comments \u2713 \u2713 \u2713 \u2713 Company \u2713 \u2713 \u2713 \u2713 Compute Start to Start Lag From Early Start \u2713 \u2713 \u2713 \u2713 Consider Assignments In Other Project With Priority Equal or Higher Than \u2713 \u2713 \u2713 \u2713 Content Status \u2713 \u2713 \u2713 Content Type \u2713 \u2713 \u2713 Creation Date \u2713 \u2713 \u2713 \u2713 Critical Activity Type \u2713 \u2713 \u2713 \u2713 Critical Slack Limit \u2713 \u2713 Currency Code \u2713 \u2713 \u2713 Currency Digits \u2713 \u2713 \u2713 \u2713 Currency Symbol \u2713 \u2713 \u2713 \u2713 Currency Symbol Position \u2713 \u2713 \u2713 \u2713 Current Date \u2713 \u2713 \u2713 \u2713 Custom Properties \u2713 \u2713 \u2713 \u2713 Date Format \u2713 \u2713 \u2713 \u2713 Date Order \u2713 \u2713 \u2713 \u2713 Date Separator \u2713 \u2713 \u2713 \u2713 Days per Month \u2713 \u2713 \u2713 \u2713 Decimal Separator \u2713 \u2713 \u2713 \u2713 Default Calendar Unique ID \u2713 \u2713 \u2713 \u2713 Default End Time \u2713 \u2713 \u2713 \u2713 Default Overtime Rate \u2713 \u2713 \u2713 Default Standard Rate \u2713 \u2713 \u2713 Default Start Time \u2713 \u2713 \u2713 \u2713 Default Work Units \u2713 \u2713 \u2713 \u2713 Document Version \u2713 \u2713 \u2713 Editable Actual Costs \u2713 \u2713 Editing Time \u2713 \u2713 \u2713 \u2713 File Application \u2713 \u2713 \u2713 \u2713 File Type \u2713 \u2713 \u2713 \u2713 Finish Date \u2713 \u2713 \u2713 \u2713 Fiscal Year Start \u2713 \u2713 \u2713 \u2713 Fiscal Year Start Month \u2713 \u2713 \u2713 \u2713 Full Application Name \u2713 \u2713 \u2713 \u2713 GUID \u2713 \u2713 \u2713 \u2713 Honor Constraints \u2713 \u2713 \u2713 \u2713 Hyperlink Base \u2713 \u2713 \u2713 \u2713 Keywords \u2713 \u2713 \u2713 \u2713 Language \u2713 \u2713 \u2713 Last Author \u2713 \u2713 \u2713 \u2713 Last Printed \u2713 \u2713 \u2713 \u2713 Last Saved \u2713 \u2713 \u2713 \u2713 Level All Resources \u2713 \u2713 \u2713 \u2713 Leveling Priorities \u2713 \u2713 \u2713 \u2713 Limit Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 MPP File Type \u2713 \u2713 \u2713 \u2713 MPX Code Page \u2713 \u2713 \u2713 \u2713 MPX Delimiter \u2713 \u2713 \u2713 \u2713 MPX File Version \u2713 \u2713 \u2713 \u2713 MPX Program Name \u2713 \u2713 \u2713 \u2713 Manager \u2713 \u2713 \u2713 \u2713 Maximum Percentage to Overallocate Resources \u2713 \u2713 \u2713 \u2713 Microsoft Project Server URL \u2713 \u2713 \u2713 \u2713 Minutes per Day \u2713 \u2713 \u2713 \u2713 Minutes per Month \u2713 \u2713 \u2713 \u2713 Minutes per Week \u2713 \u2713 \u2713 \u2713 Minutes per Year \u2713 \u2713 \u2713 \u2713 Multiple Critical Paths \u2713 \u2713 \u2713 New Task Start Is Project Start \u2713 \u2713 \u2713 \u2713 New Tasks Are Manual \u2713 \u2713 \u2713 New Tasks Estimated \u2713 \u2713 \u2713 \u2713 Number of Float Paths to Calculate \u2713 \u2713 \u2713 \u2713 PM Text \u2713 \u2713 \u2713 \u2713 Presentation Format \u2713 \u2713 \u2713 Preserve Minimum Float When Leveling \u2713 \u2713 \u2713 \u2713 Preserve Scheduled Early and Late Dates \u2713 \u2713 \u2713 \u2713 Project File Path \u2713 \u2713 \u2713 Project Title \u2713 \u2713 \u2713 \u2713 Relationship Lag Calendar \u2713 \u2713 \u2713 \u2713 Resource Pool File \u2713 \u2713 \u2713 Revision \u2713 \u2713 \u2713 \u2713 Schedule From \u2713 \u2713 \u2713 \u2713 Short Application Name \u2713 \u2713 \u2713 \u2713 Show Project Summary Task \u2713 \u2713 \u2713 \u2713 Split In Progress Tasks \u2713 \u2713 \u2713 \u2713 Start Date \u2713 \u2713 \u2713 \u2713 Status Date \u2713 \u2713 \u2713 Subject \u2713 \u2713 \u2713 \u2713 Template \u2713 \u2713 \u2713 \u2713 Thousands Separator \u2713 \u2713 \u2713 \u2713 Time Format \u2713 \u2713 \u2713 \u2713 Time Separator \u2713 \u2713 \u2713 \u2713 Total Slack Calculation Type \u2713 \u2713 \u2713 \u2713 Updating Task Status Updates Resource Status \u2713 \u2713 \u2713 \u2713 Use Expected Finish Dates \u2713 \u2713 \u2713 \u2713 WBS Code Separator \u2713 \u2713 \u2713 \u2713 Week Start Day \u2713 \u2713 \u2713 \u2713 When Scheduling Progressed Activities Use \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Date \u2713 \u2713 \u2713 Baseline2 Date \u2713 \u2713 Baseline3 Date \u2713 \u2713 Baseline4 Date \u2713 \u2713 Baseline5 Date \u2713 \u2713 Baseline6 Date \u2713 \u2713 Baseline7 Date \u2713 \u2713 Baseline8 Date \u2713 \u2713 Baseline9 Date \u2713 \u2713 Baseline10 Date \u2713 \u2713 Baseline Calendar Name \u2713 \u2713 \u2713 \u2713 Baseline Date \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#task","title":"Task","text":""},{"location":"mpp-field-guide/#core-fields_1","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 % Complete \u2713 \u2713 \u2713 \u2713 % Work Complete \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 Activity Codes \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 \u2713 Actual Duration \u2713 \u2713 \u2713 \u2713 Actual Duration Units \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Board Status ID \u2713 Budget Cost \u2713 \u2713 \u2713 Budget Work \u2713 \u2713 \u2713 Calendar Unique ID \u2713 \u2713 \u2713 Complete Through \u2713 \u2713 \u2713 \u2713 Constraint Date \u2713 \u2713 \u2713 \u2713 Constraint Type \u2713 \u2713 \u2713 \u2713 Contact \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 \u2713 Critical \u2713 \u2713 \u2713 \u2713 Deadline \u2713 \u2713 \u2713 Duration \u2713 \u2713 \u2713 \u2713 Duration Units \u2713 \u2713 \u2713 Duration Variance \u2713 \u2713 \u2713 \u2713 Early Finish \u2713 \u2713 \u2713 \u2713 Early Start \u2713 \u2713 \u2713 \u2713 Earned Value Method \u2713 \u2713 Effort Driven \u2713 \u2713 \u2713 \u2713 Estimated \u2713 \u2713 \u2713 Expanded \u2713 \u2713 \u2713 \u2713 Expense Items \u2713 \u2713 \u2713 \u2713 External Project \u2713 \u2713 \u2713 External Task \u2713 \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 Finish Slack \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 \u2713 Fixed Cost \u2713 \u2713 \u2713 \u2713 Fixed Cost Accrual \u2713 \u2713 \u2713 \u2713 Free Slack \u2713 \u2713 \u2713 GUID \u2713 \u2713 Hide Bar \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink SubAddress \u2713 \u2713 \u2713 \u2713 ID \u2713 \u2713 \u2713 \u2713 Ignore Resource Calendar \u2713 \u2713 \u2713 Late Finish \u2713 \u2713 \u2713 \u2713 Late Start \u2713 \u2713 \u2713 \u2713 Level Assignments \u2713 \u2713 \u2713 \u2713 Leveling Can Split \u2713 \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 \u2713 Manual Duration \u2713 Manual Duration Units \u2713 Marked \u2713 \u2713 \u2713 Milestone \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 Null \u2713 \u2713 \u2713 Outline Level \u2713 \u2713 \u2713 \u2713 Outline Number \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 \u2713 Parent Task Unique ID \u2713 \u2713 \u2713 Physical % Complete \u2713 \u2713 \u2713 Preleveled Finish \u2713 \u2713 \u2713 \u2713 Preleveled Start \u2713 \u2713 \u2713 \u2713 Priority \u2713 \u2713 \u2713 \u2713 Project \u2713 \u2713 \u2713 Recalc Outline Codes \u2713 \u2713 Recurring \u2713 \u2713 \u2713 \u2713 Recurring Data \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Duration \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resume \u2713 \u2713 \u2713 \u2713 Resume No Earlier Than \u2713 \u2713 \u2713 Rollup \u2713 \u2713 \u2713 \u2713 Scheduled Duration \u2713 Scheduled Finish \u2713 Scheduled Start \u2713 Splits \u2713 \u2713 \u2713 Sprint ID \u2713 Start \u2713 \u2713 \u2713 \u2713 Start Slack \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 \u2713 Steps \u2713 \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 \u2713 Subproject File \u2713 \u2713 \u2713 Subproject GUID \u2713 \u2713 Subproject Task ID \u2713 \u2713 \u2713 Subproject Task Unique ID \u2713 \u2713 \u2713 Subproject Tasks Unique ID Offset \u2713 \u2713 \u2713 Summary \u2713 \u2713 \u2713 \u2713 Summary Progress \u2713 \u2713 \u2713 Task Calendar GUID \u2713 \u2713 Task Mode \u2713 Task Name \u2713 \u2713 \u2713 \u2713 Total Slack \u2713 \u2713 \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 WBS \u2713 \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_1","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Duration \u2713 \u2713 \u2713 Baseline1 Duration Units \u2713 \u2713 Baseline1 Estimated Duration \u2713 Baseline1 Estimated Finish \u2713 Baseline1 Estimated Start \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Fixed Cost \u2713 \u2713 \u2713 Baseline1 Fixed Cost Accrual \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Duration \u2713 \u2713 \u2713 Baseline2 Duration Units \u2713 \u2713 Baseline2 Estimated Duration \u2713 Baseline2 Estimated Finish \u2713 Baseline2 Estimated Start \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Fixed Cost \u2713 \u2713 \u2713 Baseline2 Fixed Cost Accrual \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Duration \u2713 \u2713 \u2713 Baseline3 Duration Units \u2713 \u2713 Baseline3 Estimated Duration \u2713 Baseline3 Estimated Finish \u2713 Baseline3 Estimated Start \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Fixed Cost \u2713 \u2713 \u2713 Baseline3 Fixed Cost Accrual \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Duration \u2713 \u2713 \u2713 Baseline4 Duration Units \u2713 \u2713 Baseline4 Estimated Duration \u2713 Baseline4 Estimated Finish \u2713 Baseline4 Estimated Start \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Fixed Cost \u2713 \u2713 \u2713 Baseline4 Fixed Cost Accrual \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Duration \u2713 \u2713 \u2713 Baseline5 Duration Units \u2713 \u2713 Baseline5 Estimated Duration \u2713 Baseline5 Estimated Finish \u2713 Baseline5 Estimated Start \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Fixed Cost \u2713 \u2713 \u2713 Baseline5 Fixed Cost Accrual \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Duration \u2713 \u2713 \u2713 Baseline6 Duration Units \u2713 \u2713 Baseline6 Estimated Duration \u2713 Baseline6 Estimated Finish \u2713 Baseline6 Estimated Start \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Fixed Cost \u2713 \u2713 \u2713 Baseline6 Fixed Cost Accrual \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Duration \u2713 \u2713 \u2713 Baseline7 Duration Units \u2713 \u2713 Baseline7 Estimated Duration \u2713 Baseline7 Estimated Finish \u2713 Baseline7 Estimated Start \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Fixed Cost \u2713 \u2713 \u2713 Baseline7 Fixed Cost Accrual \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Duration \u2713 \u2713 \u2713 Baseline8 Duration Units \u2713 \u2713 Baseline8 Estimated Duration \u2713 Baseline8 Estimated Finish \u2713 Baseline8 Estimated Start \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Fixed Cost \u2713 \u2713 \u2713 Baseline8 Fixed Cost Accrual \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Duration \u2713 \u2713 \u2713 Baseline9 Duration Units \u2713 \u2713 Baseline9 Estimated Duration \u2713 Baseline9 Estimated Finish \u2713 Baseline9 Estimated Start \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Fixed Cost \u2713 \u2713 \u2713 Baseline9 Fixed Cost Accrual \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Deliverable Finish \u2713 Baseline10 Duration \u2713 \u2713 \u2713 Baseline10 Duration Units \u2713 \u2713 Baseline10 Estimated Duration \u2713 Baseline10 Estimated Finish \u2713 Baseline10 Estimated Start \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Fixed Cost \u2713 \u2713 \u2713 Baseline10 Fixed Cost Accrual \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 \u2713 Baseline Deliverable Finish \u2713 Baseline Deliverable Start \u2713 Baseline Duration \u2713 \u2713 \u2713 \u2713 Baseline Duration Units \u2713 \u2713 \u2713 Baseline Estimated Duration \u2713 Baseline Estimated Finish \u2713 Baseline Estimated Start \u2713 Baseline Finish \u2713 \u2713 \u2713 \u2713 Baseline Fixed Cost \u2713 \u2713 \u2713 Baseline Fixed Cost Accrual \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 \u2713 \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 \u2713 \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 \u2713 \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 \u2713 \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 \u2713 \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 \u2713 \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 \u2713 \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 \u2713 \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 \u2713 \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#enterprise-fields","title":"Enterprise Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 \u2713 Enterprise Duration2 Units \u2713 \u2713 Enterprise Duration3 Units \u2713 \u2713 Enterprise Duration4 Units \u2713 \u2713 Enterprise Duration5 Units \u2713 \u2713 Enterprise Duration6 Units \u2713 \u2713 Enterprise Duration7 Units \u2713 \u2713 Enterprise Duration8 Units \u2713 \u2713 Enterprise Duration9 Units \u2713 \u2713 Enterprise Duration10 Units \u2713 \u2713 Enterprise Project Date1 \u2713 Enterprise Project Date2 \u2713 Enterprise Project Date3 \u2713 Enterprise Project Date4 \u2713 Enterprise Project Number2 \u2713 Enterprise Project Number4 \u2713 Enterprise Project Number5 \u2713 Enterprise Project Number22 \u2713 Enterprise Project Text1 \u2713 \u2713 \u2713 Enterprise Project Text2 \u2713 \u2713 Enterprise Project Text3 \u2713 \u2713 Enterprise Project Text4 \u2713 \u2713 Enterprise Project Text5 \u2713 Enterprise Project Text6 \u2713 \u2713 Enterprise Project Text8 \u2713 Enterprise Project Text9 \u2713 Enterprise Project Text10 \u2713 Enterprise Project Text11 \u2713 Enterprise Project Text12 \u2713 Enterprise Project Text13 \u2713 Enterprise Project Text14 \u2713 Enterprise Project Text15 \u2713 Enterprise Project Text16 \u2713 Enterprise Project Text17 \u2713 Enterprise Project Text18 \u2713 Enterprise Project Text19 \u2713 Enterprise Project Text21 \u2713 Enterprise Project Text40 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#resource","title":"Resource","text":""},{"location":"mpp-field-guide/#core-fields_2","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Accrue At \u2713 \u2713 \u2713 \u2713 Active \u2713 \u2713 \u2713 \u2713 Actual Cost \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Availability Data \u2713 \u2713 \u2713 Available From \u2713 \u2713 \u2713 Available To \u2713 \u2713 \u2713 Booking Type \u2713 \u2713 Budget \u2713 \u2713 Budget Cost \u2713 \u2713 \u2713 Budget Work \u2713 \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 Calendar GUID \u2713 \u2713 Calendar Unique ID \u2713 \u2713 \u2713 \u2713 Code \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Center \u2713 Cost Per Use \u2713 \u2713 \u2713 Cost Rate A \u2713 \u2713 \u2713 Cost Rate B \u2713 \u2713 \u2713 Cost Rate C \u2713 \u2713 \u2713 Cost Rate D \u2713 \u2713 \u2713 Cost Rate E \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Default Units \u2713 \u2713 \u2713 \u2713 Email Address \u2713 \u2713 \u2713 GUID \u2713 \u2713 Generic \u2713 \u2713 \u2713 Group \u2713 \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink SubAddress \u2713 \u2713 \u2713 ID \u2713 \u2713 \u2713 \u2713 Initials \u2713 \u2713 \u2713 \u2713 Material Label \u2713 \u2713 \u2713 Max Units \u2713 \u2713 \u2713 Name \u2713 \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 \u2713 Overallocated \u2713 \u2713 \u2713 \u2713 Overtime Cost \u2713 \u2713 \u2713 Overtime Rate \u2713 \u2713 \u2713 Overtime Rate Units \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Peak \u2713 \u2713 \u2713 \u2713 Phonetics \u2713 Regular Work \u2713 \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Standard Rate \u2713 \u2713 \u2713 Standard Rate Units \u2713 \u2713 \u2713 Subproject Unique Resource ID \u2713 \u2713 Type \u2713 \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 Unit of Measure Unique ID \u2713 \u2713 \u2713 Windows User Account \u2713 \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713 \u2713 Workgroup \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_2","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Budget Cost \u2713 Baseline1 Budget Work \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 Baseline2 Budget Work \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 Baseline3 Budget Work \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 Baseline4 Budget Work \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 Baseline5 Budget Work \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 Baseline6 Budget Work \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 Baseline7 Budget Work \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 Baseline8 Budget Work \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 Baseline9 Budget Work \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 Baseline10 Budget Work \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 Baseline Budget Work \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields_1","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Outline Code1 \u2713 \u2713 \u2713 Outline Code1 Index \u2713 \u2713 \u2713 Outline Code2 \u2713 \u2713 \u2713 Outline Code2 Index \u2713 \u2713 \u2713 Outline Code3 \u2713 \u2713 \u2713 Outline Code3 Index \u2713 \u2713 \u2713 Outline Code4 \u2713 \u2713 \u2713 Outline Code4 Index \u2713 \u2713 \u2713 Outline Code5 \u2713 \u2713 \u2713 Outline Code5 Index \u2713 \u2713 \u2713 Outline Code6 \u2713 \u2713 \u2713 Outline Code6 Index \u2713 \u2713 \u2713 Outline Code7 \u2713 \u2713 \u2713 Outline Code7 Index \u2713 \u2713 \u2713 Outline Code8 \u2713 \u2713 \u2713 Outline Code8 Index \u2713 \u2713 \u2713 Outline Code9 \u2713 \u2713 \u2713 Outline Code9 Index \u2713 \u2713 \u2713 Outline Code10 \u2713 \u2713 \u2713 Outline Code10 Index \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#enterprise-fields_1","title":"Enterprise Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Enterprise \u2713 \u2713 Enterprise Data \u2713 Enterprise Duration1 Units \u2713 \u2713 Enterprise Duration2 Units \u2713 \u2713 Enterprise Duration3 Units \u2713 \u2713 Enterprise Duration4 Units \u2713 \u2713 Enterprise Duration5 Units \u2713 \u2713 Enterprise Duration6 Units \u2713 \u2713 Enterprise Duration7 Units \u2713 \u2713 Enterprise Duration8 Units \u2713 \u2713 Enterprise Duration9 Units \u2713 \u2713 Enterprise Duration10 Units \u2713 \u2713 Enterprise Unique ID \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#resource-assignment","title":"Resource Assignment","text":""},{"location":"mpp-field-guide/#core-fields_3","title":"Core Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Actual Cost \u2713 \u2713 \u2713 Actual Finish \u2713 \u2713 \u2713 Actual Overtime Cost \u2713 \u2713 \u2713 Actual Overtime Work \u2713 \u2713 \u2713 Actual Start \u2713 \u2713 \u2713 Actual Work \u2713 \u2713 \u2713 \u2713 Actual Work Protected \u2713 Assignment Delay \u2713 \u2713 \u2713 Assignment GUID \u2713 \u2713 Assignment Resource GUID \u2713 \u2713 Assignment Task GUID \u2713 \u2713 Assignment Units \u2713 \u2713 \u2713 \u2713 Budget Cost \u2713 \u2713 Budget Work \u2713 \u2713 Calculate Costs From Units \u2713 \u2713 \u2713 \u2713 Confirmed \u2713 \u2713 \u2713 Cost \u2713 \u2713 \u2713 \u2713 Cost Rate Table \u2713 \u2713 \u2713 Cost Variance \u2713 \u2713 \u2713 Created \u2713 \u2713 \u2713 Finish \u2713 \u2713 \u2713 \u2713 Finish Variance \u2713 \u2713 \u2713 Hyperlink \u2713 \u2713 \u2713 Hyperlink Address \u2713 \u2713 \u2713 Hyperlink Data \u2713 \u2713 \u2713 Hyperlink Screen Tip \u2713 \u2713 \u2713 Hyperlink Subaddress \u2713 \u2713 \u2713 Leveling Delay \u2713 \u2713 \u2713 Leveling Delay Units \u2713 \u2713 Linked Fields \u2713 \u2713 \u2713 Notes \u2713 \u2713 \u2713 Overtime Work \u2713 \u2713 \u2713 Owner \u2713 \u2713 Percent Work Complete \u2713 \u2713 \u2713 \u2713 Rate Source \u2713 \u2713 \u2713 \u2713 Regular Work \u2713 \u2713 \u2713 Remaining Cost \u2713 \u2713 \u2713 Remaining Overtime Cost \u2713 \u2713 \u2713 Remaining Overtime Work \u2713 \u2713 \u2713 Remaining Work \u2713 \u2713 \u2713 \u2713 Resource Request Type \u2713 \u2713 Resource Unique ID \u2713 \u2713 \u2713 \u2713 Response Pending \u2713 \u2713 \u2713 Resume \u2713 \u2713 \u2713 Start \u2713 \u2713 \u2713 \u2713 Start Variance \u2713 \u2713 \u2713 Stop \u2713 \u2713 \u2713 Task Unique ID \u2713 \u2713 \u2713 \u2713 Team Status Pending \u2713 \u2713 \u2713 Timephased Actual Overtime Work \u2713 \u2713 \u2713 Timephased Actual Work \u2713 \u2713 \u2713 Timephased Work \u2713 \u2713 \u2713 Unique ID \u2713 \u2713 \u2713 \u2713 Variable Rate Units \u2713 \u2713 Work \u2713 \u2713 \u2713 \u2713 Work Contour \u2713 \u2713 \u2713 Work Variance \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#baseline-fields_3","title":"Baseline Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Baseline1 Budget Cost \u2713 \u2713 Baseline1 Budget Work \u2713 \u2713 Baseline1 Cost \u2713 \u2713 \u2713 Baseline1 Finish \u2713 \u2713 \u2713 Baseline1 Start \u2713 \u2713 \u2713 Baseline1 Work \u2713 \u2713 \u2713 Baseline2 Budget Cost \u2713 \u2713 Baseline2 Budget Work \u2713 \u2713 Baseline2 Cost \u2713 \u2713 \u2713 Baseline2 Finish \u2713 \u2713 \u2713 Baseline2 Start \u2713 \u2713 \u2713 Baseline2 Work \u2713 \u2713 \u2713 Baseline3 Budget Cost \u2713 \u2713 Baseline3 Budget Work \u2713 \u2713 Baseline3 Cost \u2713 \u2713 \u2713 Baseline3 Finish \u2713 \u2713 \u2713 Baseline3 Start \u2713 \u2713 \u2713 Baseline3 Work \u2713 \u2713 \u2713 Baseline4 Budget Cost \u2713 \u2713 Baseline4 Budget Work \u2713 \u2713 Baseline4 Cost \u2713 \u2713 \u2713 Baseline4 Finish \u2713 \u2713 \u2713 Baseline4 Start \u2713 \u2713 \u2713 Baseline4 Work \u2713 \u2713 \u2713 Baseline5 Budget Cost \u2713 \u2713 Baseline5 Budget Work \u2713 \u2713 Baseline5 Cost \u2713 \u2713 \u2713 Baseline5 Finish \u2713 \u2713 \u2713 Baseline5 Start \u2713 \u2713 \u2713 Baseline5 Work \u2713 \u2713 \u2713 Baseline6 Budget Cost \u2713 \u2713 Baseline6 Budget Work \u2713 \u2713 Baseline6 Cost \u2713 \u2713 \u2713 Baseline6 Finish \u2713 \u2713 \u2713 Baseline6 Start \u2713 \u2713 \u2713 Baseline6 Work \u2713 \u2713 \u2713 Baseline7 Budget Cost \u2713 \u2713 Baseline7 Budget Work \u2713 \u2713 Baseline7 Cost \u2713 \u2713 \u2713 Baseline7 Finish \u2713 \u2713 \u2713 Baseline7 Start \u2713 \u2713 \u2713 Baseline7 Work \u2713 \u2713 \u2713 Baseline8 Budget Cost \u2713 \u2713 Baseline8 Budget Work \u2713 \u2713 Baseline8 Cost \u2713 \u2713 \u2713 Baseline8 Finish \u2713 \u2713 \u2713 Baseline8 Start \u2713 \u2713 \u2713 Baseline8 Work \u2713 \u2713 \u2713 Baseline9 Budget Cost \u2713 \u2713 Baseline9 Budget Work \u2713 \u2713 Baseline9 Cost \u2713 \u2713 \u2713 Baseline9 Finish \u2713 \u2713 \u2713 Baseline9 Start \u2713 \u2713 \u2713 Baseline9 Work \u2713 \u2713 \u2713 Baseline10 Budget Cost \u2713 \u2713 Baseline10 Budget Work \u2713 \u2713 Baseline10 Cost \u2713 \u2713 \u2713 Baseline10 Finish \u2713 \u2713 \u2713 Baseline10 Start \u2713 \u2713 \u2713 Baseline10 Work \u2713 \u2713 \u2713 Baseline Budget Cost \u2713 \u2713 Baseline Budget Work \u2713 \u2713 Baseline Cost \u2713 \u2713 \u2713 Baseline Finish \u2713 \u2713 \u2713 Baseline Start \u2713 \u2713 \u2713 Baseline Work \u2713 \u2713 \u2713 Timephased Baseline1 Cost \u2713 \u2713 \u2713 Timephased Baseline1 Work \u2713 \u2713 \u2713 Timephased Baseline2 Cost \u2713 \u2713 Timephased Baseline2 Work \u2713 \u2713 Timephased Baseline3 Cost \u2713 \u2713 Timephased Baseline3 Work \u2713 \u2713 Timephased Baseline4 Cost \u2713 \u2713 Timephased Baseline4 Work \u2713 \u2713 Timephased Baseline5 Cost \u2713 \u2713 Timephased Baseline5 Work \u2713 \u2713 Timephased Baseline6 Cost \u2713 \u2713 Timephased Baseline6 Work \u2713 \u2713 Timephased Baseline7 Cost \u2713 \u2713 Timephased Baseline7 Work \u2713 \u2713 Timephased Baseline8 Cost \u2713 \u2713 Timephased Baseline8 Work \u2713 \u2713 Timephased Baseline9 Cost \u2713 \u2713 Timephased Baseline9 Work \u2713 \u2713 Timephased Baseline10 Cost \u2713 \u2713 \u2713 Timephased Baseline10 Work \u2713 \u2713 \u2713 Timephased Baseline Cost \u2713 \u2713 \u2713 Timephased Baseline Work \u2713 \u2713 \u2713"},{"location":"mpp-field-guide/#custom-fields_2","title":"Custom Fields","text":"Field MPP8 MPP9 MPP12 MPP14 Cost1 \u2713 \u2713 \u2713 Cost2 \u2713 \u2713 \u2713 Cost3 \u2713 \u2713 \u2713 Cost4 \u2713 \u2713 \u2713 Cost5 \u2713 \u2713 \u2713 Cost6 \u2713 \u2713 \u2713 Cost7 \u2713 \u2713 \u2713 Cost8 \u2713 \u2713 \u2713 Cost9 \u2713 \u2713 \u2713 Cost10 \u2713 \u2713 \u2713 Date1 \u2713 \u2713 \u2713 Date2 \u2713 \u2713 \u2713 Date3 \u2713 \u2713 \u2713 Date4 \u2713 \u2713 \u2713 Date5 \u2713 \u2713 \u2713 Date6 \u2713 \u2713 \u2713 Date7 \u2713 \u2713 \u2713 Date8 \u2713 \u2713 \u2713 Date9 \u2713 \u2713 \u2713 Date10 \u2713 \u2713 \u2713 Duration1 \u2713 \u2713 \u2713 Duration1 Units \u2713 \u2713 \u2713 Duration2 \u2713 \u2713 \u2713 Duration2 Units \u2713 \u2713 \u2713 Duration3 \u2713 \u2713 \u2713 Duration3 Units \u2713 \u2713 \u2713 Duration4 \u2713 \u2713 \u2713 Duration4 Units \u2713 \u2713 \u2713 Duration5 \u2713 \u2713 \u2713 Duration5 Units \u2713 \u2713 \u2713 Duration6 \u2713 \u2713 \u2713 Duration6 Units \u2713 \u2713 \u2713 Duration7 \u2713 \u2713 \u2713 Duration7 Units \u2713 \u2713 \u2713 Duration8 \u2713 \u2713 \u2713 Duration8 Units \u2713 \u2713 \u2713 Duration9 \u2713 \u2713 \u2713 Duration9 Units \u2713 \u2713 \u2713 Duration10 \u2713 \u2713 \u2713 Duration10 Units \u2713 \u2713 \u2713 Finish1 \u2713 \u2713 \u2713 Finish2 \u2713 \u2713 \u2713 Finish3 \u2713 \u2713 \u2713 Finish4 \u2713 \u2713 \u2713 Finish5 \u2713 \u2713 \u2713 Finish6 \u2713 \u2713 \u2713 Finish7 \u2713 \u2713 \u2713 Finish8 \u2713 \u2713 \u2713 Finish9 \u2713 \u2713 \u2713 Finish10 \u2713 \u2713 \u2713 Flag1 \u2713 \u2713 \u2713 Flag2 \u2713 \u2713 \u2713 Flag3 \u2713 \u2713 \u2713 Flag4 \u2713 \u2713 \u2713 Flag5 \u2713 \u2713 \u2713 Flag6 \u2713 \u2713 \u2713 Flag7 \u2713 \u2713 \u2713 Flag8 \u2713 \u2713 \u2713 Flag9 \u2713 \u2713 \u2713 Flag10 \u2713 \u2713 \u2713 Flag11 \u2713 \u2713 \u2713 Flag12 \u2713 \u2713 \u2713 Flag13 \u2713 \u2713 \u2713 Flag14 \u2713 \u2713 \u2713 Flag15 \u2713 \u2713 \u2713 Flag16 \u2713 \u2713 \u2713 Flag17 \u2713 \u2713 \u2713 Flag18 \u2713 \u2713 \u2713 Flag19 \u2713 \u2713 \u2713 Flag20 \u2713 \u2713 \u2713 Number1 \u2713 \u2713 \u2713 Number2 \u2713 \u2713 \u2713 Number3 \u2713 \u2713 \u2713 Number4 \u2713 \u2713 \u2713 Number5 \u2713 \u2713 \u2713 Number6 \u2713 \u2713 \u2713 Number7 \u2713 \u2713 \u2713 Number8 \u2713 \u2713 \u2713 Number9 \u2713 \u2713 \u2713 Number10 \u2713 \u2713 \u2713 Number11 \u2713 \u2713 \u2713 Number12 \u2713 \u2713 \u2713 Number13 \u2713 \u2713 \u2713 Number14 \u2713 \u2713 \u2713 Number15 \u2713 \u2713 \u2713 Number16 \u2713 \u2713 \u2713 Number17 \u2713 \u2713 \u2713 Number18 \u2713 \u2713 \u2713 Number19 \u2713 \u2713 \u2713 Number20 \u2713 \u2713 \u2713 Start1 \u2713 \u2713 \u2713 Start2 \u2713 \u2713 \u2713 Start3 \u2713 \u2713 \u2713 Start4 \u2713 \u2713 \u2713 Start5 \u2713 \u2713 \u2713 Start6 \u2713 \u2713 \u2713 Start7 \u2713 \u2713 \u2713 Start8 \u2713 \u2713 \u2713 Start9 \u2713 \u2713 \u2713 Start10 \u2713 \u2713 \u2713 Text1 \u2713 \u2713 \u2713 Text2 \u2713 \u2713 \u2713 Text3 \u2713 \u2713 \u2713 Text4 \u2713 \u2713 \u2713 Text5 \u2713 \u2713 \u2713 Text6 \u2713 \u2713 \u2713 Text7 \u2713 \u2713 \u2713 Text8 \u2713 \u2713 \u2713 Text9 \u2713 \u2713 \u2713 Text10 \u2713 \u2713 \u2713 Text11 \u2713 \u2713 \u2713 Text12 \u2713 \u2713 \u2713 Text13 \u2713 \u2713 \u2713 Text14 \u2713 \u2713 \u2713 Text15 \u2713 \u2713 \u2713 Text16 \u2713 \u2713 \u2713 Text17 \u2713 \u2713 \u2713 Text18 \u2713 \u2713 \u2713 Text19 \u2713 \u2713 \u2713 Text20 \u2713 \u2713 \u2713 Text21 \u2713 \u2713 \u2713 Text22 \u2713 \u2713 \u2713 Text23 \u2713 \u2713 \u2713 Text24 \u2713 \u2713 \u2713 Text25 \u2713 \u2713 \u2713 Text26 \u2713 \u2713 \u2713 Text27 \u2713 \u2713 \u2713 Text28 \u2713 \u2713 \u2713 Text29 \u2713 \u2713 \u2713 Text30 \u2713 \u2713 \u2713"},{"location":"store/","title":"Store","text":"
Yes, MPXJ has merchandise! For a small range of MPXJ branded clothing, please visit the MPXJ store. All purchases made from the store help to suport the development of MPXJ.
Thank you!
"},{"location":"support/","title":"Support","text":"
Support and feature requests can be opened on MPXJ's issue tracker. I will respond to these as time permits.
For more pressing issues, commercial support is available via my company Timephased. I can also provide consultancy around the use of MPXJ and implementation services. Please contact me directly for further details.
"},{"location":"supported-formats/","title":"Supported Formats","text":"
MPX: The MPX file format can be read by versions of Microsoft Project up to and including Microsoft Project 2010, and written by versions up to Microsoft Project 98. MPXJ allows MPX files to be created, read and written. See this Microsoft support article for a definition of the file format.
MPP: The MPP file format is Microsoft's proprietary way of storing project data. MPXJ supports read only access to MPP files produced by Microsoft Project 98, Microsoft Project 2000, Microsoft Project 2002, Microsoft Project 2003, Microsoft Project 2007, Microsoft Project 2010, Microsoft Project 2013, Microsoft Project 2016, and Microsoft Project 2019. MPP template files, with the suffix MPT are also supported.
MSPDI: The MSPDI file format is Microsoft's XML file format for storing project data. Versions of Microsoft Project from 2002 onwards can read and write MSPDI files. MPXJ allows MSPDI files to be created, read, and written. The MSDPI file format has remained broadly unchanged since it was introduced, although several versions of Microsoft Project have tweaked the file format slightly, and have their own updated documentation. Documentation is available online here. Documentation for the Project 2003 MSPDI file format can be downloaded as part of the Office 2003 XML Reference Schemas package. Documentation for the Project 2007 MSPDI file format can be downloaded as part of the Project 2007 SDK. Documentation for the Project 2010 MSPDI file format can be downloaded as part of the Project 2010 Reference: Software Development Kit. Documentation for the Project 2013 MSPDI file format can be downloaded as part of the Project 2013 SDK.
MPD: The MPD file format is an Access database used to store one or more projects. The database schema used in these databases is also close to that used by Microsoft Project Server. MPXJ can read projects stored in an MPD file using a JDBC connection. It is possible that MPXJ could also read the same data from a Microsoft Project Server database using the same approach, but this is not something I've tested.
PLANNER: Planner is an Open Source project management tool which uses an XML file format to store project data. MPXJ can read and write the Planner file format.
PRIMAVERA P6: Primavera P6 is an industry-leading tool favoured by users with complex planning requirements. It can export project data in the form of XER or PMXML files, both of which MPXJ can read. It is also possible for MPXJ to connect directly to the P6 database via JDBC to read project data. MPXJ can also write PMXML and XER files to allow data to be exported in a form which can be consumed by P6. The PMXML schema forms part of the P6 distribution media, which can be downloaded from the Oracle e-Delivery site.
PRIMAVERA P3: Primavera P3 (Primavera Project Planner) is the forerunner of P6. It holds projects in Btrieve database files which MPXJ can read from a directory or from a zip archive. MPXJ can also read P3 data from PRX backup files.
PRIMAVERA SURETRAK: SureTrak holds projects in Btrieve database files which MPXJ can read from a directory or from a zip archive. MPXJ can also read SureTrak data from STX backup files.
POWERPROJECT: Asta Powerproject is a planning tool used in a number of industries, particularly construction. Powerproject can save data to PP files or to MDB database files, and MPXJ can read both of these formats.
PHOENIX: Phoenix Project Manager is an easy-to-use critical path method scheduling tool aimed primarily at the construction industry. Phoenix writes PPX files which MPXJ can read.
FASTTRACK: Fasttrack Schedule is general purpose planning tool. FastTrack writes FTS files which MPXJ can read.
GANTTPROJECT: GanttProject is an open source general purpose planning tool. GanttProject writes GAN files which MPXJ can read.
TURBOPROJECT: TurboProject is general purpose planning tool. TurboProject writes PEP files which MPXJ can read.
CONECPTDRAW PROJECT: ConceptDraw PROJECT is general purpose planning tool. ConceptDraw PROJECT writes CDPX, CDPZ and CDPTZ files which MPXJ can read.
SYNCHRO SCHEDULER: Synchro Scheduler is general purpose planning tool. Synchro Scheduler writes SP files which MPXJ can read.
GANTT DESIGNER: Gantt Designer is a simple Gantt chart drawing tool. Gantt Designer writes GNT files which MPXJ can read.
SDEF: SDEF is the Standard Data Exchange Format, as defined by the USACE (United States Army Corps of Engineers). SDEF is a fixed column format text file, used to import a project schedule up into the QCS (Quality Control System) software from USACE. MPXJ can read and write SDEF files. The specification for the file format can be found here.
SCHEDULE_GRID: Schedule grid files are produced when a schedule is exported from Sage 100 Contractor. MPXJ can read schedule grid files.
PROJECT COMMANDER: Project Commander files are the native file format used by the Project Commander application. Project Commander writes PC files which MPXJ can read.
DELTEK OPEN PLAN: Open Plan allows export of schedules to BK3 files, which MPXJ can read.
"},{"location":"users/","title":"MPXJ Users","text":"
Here is a list of organisations and projects currently using, or believed to be using MPXJ. Feel free to contact me if you would like to be featured in this list.
"}]} \ No newline at end of file diff --git a/docs/store/index.html b/docs/store/index.html index 08e9025fa6..cf5238f513 100644 --- a/docs/store/index.html +++ b/docs/store/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/summary.html b/docs/summary.html index 8599b5ec3b..bd210334f8 100644 --- a/docs/summary.html +++ b/docs/summary.html @@ -32,7 +32,7 @@
@@ -103,7 +103,7 @@
-
+
diff --git a/docs/support/index.html b/docs/support/index.html index ce319b75b1..2816a2f245 100644 --- a/docs/support/index.html +++ b/docs/support/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/supported-formats/index.html b/docs/supported-formats/index.html index d2797094f0..82a134b808 100644 --- a/docs/supported-formats/index.html +++ b/docs/supported-formats/index.html @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -68,9 +68,6 @@
diff --git a/docs/team.html b/docs/team.html index a82fb872a3..a405961149 100644 --- a/docs/team.html +++ b/docs/team.html @@ -32,7 +32,7 @@
diff --git a/docs/testapidocs/allclasses-frame.html b/docs/testapidocs/allclasses-frame.html index 733a9b425d..eae3b571f9 100644 --- a/docs/testapidocs/allclasses-frame.html +++ b/docs/testapidocs/allclasses-frame.html @@ -4,7 +4,7 @@
-
+
diff --git a/docs/testapidocs/allclasses-noframe.html b/docs/testapidocs/allclasses-noframe.html index b8288c4aa8..c08347985f 100644 --- a/docs/testapidocs/allclasses-noframe.html +++ b/docs/testapidocs/allclasses-noframe.html @@ -4,7 +4,7 @@
-
+
diff --git a/docs/testapidocs/constant-values.html b/docs/testapidocs/constant-values.html index 41dcadaf62..f376a48e78 100644 --- a/docs/testapidocs/constant-values.html +++ b/docs/testapidocs/constant-values.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/assignment/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/assignment/package-summary.html index 6e57a3219d..83df6147db 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/assignment/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/assignment/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/calendar/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/calendar/package-summary.html index 943f360665..6204c51376 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/calendar/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/calendar/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/legacy/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/legacy/package-summary.html index 0fb0cb917d..46aa379779 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/legacy/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/legacy/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/package-summary.html index 6783b14b90..54d2509088 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/primavera/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/primavera/package-summary.html index ae92308575..0cbdc73f3e 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/primavera/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/primavera/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/project/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/project/package-summary.html index 01899c6340..2260cd6828 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/project/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/project/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/resource/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/resource/package-summary.html index ab3af32d40..9bbed9c5a8 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/resource/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/resource/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/junit/task/package-summary.html b/docs/testapidocs/net/sf/mpxj/junit/task/package-summary.html index c1ecc4d4a2..fdf4eec1d0 100644 --- a/docs/testapidocs/net/sf/mpxj/junit/task/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/junit/task/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/net/sf/mpxj/mspdi/package-summary.html b/docs/testapidocs/net/sf/mpxj/mspdi/package-summary.html index 185a45f024..645c11e7fd 100644 --- a/docs/testapidocs/net/sf/mpxj/mspdi/package-summary.html +++ b/docs/testapidocs/net/sf/mpxj/mspdi/package-summary.html @@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@ diff --git a/docs/testapidocs/overview-summary.html b/docs/testapidocs/overview-summary.html index f23059c7a9..99ab9230b4 100644 --- a/docs/testapidocs/overview-summary.html +++ b/docs/testapidocs/overview-summary.html @@ -4,7 +4,7 @@
-
+