Edit this page

Importing XML from MS Project

Although RadGanttView does not support direct binding or importing of MS Project files we have prepared a class that would help you import an MS Project saved as xml.

public class MsProjectImporter
{
    private Dictionary<int, List<DataRow>> tasksByLevel;
    private DataSet dataSet;
    public DataSet GetData(TextReader reader)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(reader);
        this.InitializeDataStructures();
        this.ExtractTasks(doc);
        ImporterNode root = this.BuildTasksHierarchy();
        this.SaveTasksDataTable(root);
        this.SaveLinksDataTable(doc);
        return this.dataSet;
    }
    private void InitializeDataStructures()
    {
        this.tasksByLevel = new Dictionary<int, List<DataRow>>();
        DataTable tasks = new DataTable("Tasks");
        tasks.Columns.Add("Id", typeof(int));
        tasks.Columns.Add("ParentId", typeof(int));
        tasks.Columns.Add("Title", typeof(string));
        tasks.Columns.Add("Start", typeof(DateTime));
        tasks.Columns.Add("End", typeof(DateTime));
        tasks.Columns.Add("Progress", typeof(decimal));
        tasks.Columns.Add("Outline", typeof(string));
        DataTable links = new DataTable("Links");
        links.Columns.Add("StartId", typeof(int));
        links.Columns.Add("EndId", typeof(int));
        links.Columns.Add("LinkType", typeof(int));
        this.dataSet = new DataSet();
        this.dataSet.Tables.Add(tasks);
        this.dataSet.Tables.Add(links);
    }
    private ImporterNode BuildTasksHierarchy()
    {
        ImporterNode root = null;
        foreach (int key in this.tasksByLevel.Keys)
        {
            if (key == 0)
            {
                root = new ImporterNode();
                root.Row = this.tasksByLevel[key][0];
                continue;
            }
            foreach (DataRow row in this.tasksByLevel[key])
            {
                List<string> outlineIndexes = new List<string>(row["Outline"].ToString().Split('.'));
                ImporterNode parent = root;
                while (outlineIndexes.Count > 1)
                {
                    parent = parent.Children[int.Parse(outlineIndexes[0]) - 1];
                    outlineIndexes.RemoveAt(0);
                }
                ImporterNode newNode = new ImporterNode();
                newNode.Row = row;
                newNode.Row["ParentId"] = parent.Row["Id"];
                parent.Children.Add(newNode);
            }
        }
        return root;
    }
    private void ExtractTasks(XmlDocument doc)
    {
        foreach (XmlNode node in doc.DocumentElement["Tasks"].ChildNodes)
        {
            if (node["OutlineNumber"] == null)
            {
                continue;
            }
            DataRow row = this.dataSet.Tables["Tasks"].NewRow();
            int outlineLevel = int.Parse(node["OutlineLevel"].InnerText);
            int id = int.Parse(node["UID"].InnerText);
            row["Id"] = id;
            row["ParentId"] = 0;
            row["Title"] = node["Name"].InnerText;
            row["Start"] = DateTime.Parse(node["Start"].InnerText);
            row["End"] = DateTime.Parse(node["Finish"].InnerText);
            row["Progress"] = decimal.Parse(node["PercentComplete"].InnerText);
            row["Outline"] = node["OutlineNumber"].InnerText;
            if (this.tasksByLevel.ContainsKey(outlineLevel))
            {
                this.tasksByLevel[outlineLevel].Add(row);
            }
            else
            {
                this.tasksByLevel.Add(outlineLevel, new List<DataRow>() { row });
            }
        }
    }
    private void SaveTasksDataTable(ImporterNode root)
    {
        Queue<ImporterNode> queue = new Queue<ImporterNode>();
        foreach (ImporterNode node in root.Children)
        {
            queue.Enqueue(node);
        }
        while (queue.Count > 0)
        {
            ImporterNode node = queue.Dequeue();
            foreach (ImporterNode item in node.Children)
            {
                queue.Enqueue(item);
            }
            this.dataSet.Tables["Tasks"].Rows.Add(node.Row);
        }
        dataSet.Tables["Tasks"].Columns.Remove("Outline");
    }
    private void SaveLinksDataTable(XmlDocument doc)
    {
        foreach (XmlNode node in doc.DocumentElement["Tasks"].ChildNodes)
        {
            XmlNode predecessor = node["PredecessorLink"];
            if (predecessor != null)
            {
                int id = int.Parse(node["UID"].InnerText);
                int startId = int.Parse(predecessor["PredecessorUID"].InnerText);
                int linkType = int.Parse(predecessor["Type"].InnerText);
                this.dataSet.Tables["Links"].Rows.Add(startId, id, linkType);
            }
        }
    }
}
public class ImporterNode
{
    private DataRow row;
    private List<ImporterNode> children;
    public ImporterNode()
    {
        this.children = new List<ImporterNode>();
    }
    public DataRow Row
    {
        get { return row; }
        set { row = value; }
    }
    public List<ImporterNode> Children
    {
        get { return children; }
    }
}

Public Class MsProjectImporter
    Private tasksByLevel As Dictionary(Of Integer, List(Of DataRow))
    Private dataSet As DataSet
    Public Function GetData(reader As TextReader) As DataSet
        Dim doc As New XmlDocument()
        doc.Load(reader)
        Me.InitializeDataStructures()
        Me.ExtractTasks(doc)
        Dim root As ImporterNode = Me.BuildTasksHierarchy()
        Me.SaveTasksDataTable(root)
        Me.SaveLinksDataTable(doc)
        Return Me.dataSet
    End Function
    Private Sub InitializeDataStructures()
        Me.tasksByLevel = New Dictionary(Of Integer, List(Of DataRow))()
        Dim tasks As New DataTable("Tasks")
        tasks.Columns.Add("Id", GetType(Integer))
        tasks.Columns.Add("ParentId", GetType(Integer))
        tasks.Columns.Add("Title", GetType(String))
        tasks.Columns.Add("Start", GetType(DateTime))
        tasks.Columns.Add("End", GetType(DateTime))
        tasks.Columns.Add("Progress", GetType(Decimal))
        tasks.Columns.Add("Outline", GetType(String))
        Dim links As New DataTable("Links")
        links.Columns.Add("StartId", GetType(Integer))
        links.Columns.Add("EndId", GetType(Integer))
        links.Columns.Add("LinkType", GetType(Integer))
        Me.dataSet = New DataSet()
        Me.dataSet.Tables.Add(tasks)
        Me.dataSet.Tables.Add(links)
    End Sub
    Private Function BuildTasksHierarchy() As ImporterNode
        Dim root As ImporterNode = Nothing
        For Each key As Integer In Me.tasksByLevel.Keys
            If key = 0 Then
                root = New ImporterNode()
                root.Row = Me.tasksByLevel(key)(0)
                Continue For
            End If
            For Each row As DataRow In Me.tasksByLevel(key)
                Dim outlineIndexes As New List(Of String)(row("Outline").ToString().Split("."c))
                Dim parent As ImporterNode = root
                While outlineIndexes.Count > 1
                    parent = parent.Children(Integer.Parse(outlineIndexes(0)) - 1)
                    outlineIndexes.RemoveAt(0)
                End While
                Dim newNode As New ImporterNode()
                newNode.Row = row
                newNode.Row("ParentId") = parent.Row("Id")
                parent.Children.Add(newNode)
            Next
        Next
        Return root
    End Function
    Private Sub ExtractTasks(doc As XmlDocument)
        For Each node As XmlNode In doc.DocumentElement("Tasks").ChildNodes
            If node("OutlineNumber") Is Nothing Then
                Continue For
            End If
            Dim row As DataRow = Me.dataSet.Tables("Tasks").NewRow()
            Dim outlineLevel As Integer = Integer.Parse(node("OutlineLevel").InnerText)
            Dim id As Integer = Integer.Parse(node("UID").InnerText)
            row("Id") = id
            row("ParentId") = 0
            row("Title") = node("Name").InnerText
            row("Start") = DateTime.Parse(node("Start").InnerText)
            row("End") = DateTime.Parse(node("Finish").InnerText)
            row("Progress") = Decimal.Parse(node("PercentComplete").InnerText)
            row("Outline") = node("OutlineNumber").InnerText
            If Me.tasksByLevel.ContainsKey(outlineLevel) Then
                Me.tasksByLevel(outlineLevel).Add(row)
            Else
                Me.tasksByLevel.Add(outlineLevel, New List(Of DataRow)() From { _
                 row _
                })
            End If
        Next
    End Sub
    Private Sub SaveTasksDataTable(root As ImporterNode)
        Dim queue As New Queue(Of ImporterNode)()
        For Each node As ImporterNode In root.Children
            queue.Enqueue(node)
        Next
        While queue.Count > 0
            Dim node As ImporterNode = queue.Dequeue()
            For Each item As ImporterNode In node.Children
                queue.Enqueue(item)
            Next
            Me.dataSet.Tables("Tasks").Rows.Add(node.Row)
        End While
        dataSet.Tables("Tasks").Columns.Remove("Outline")
    End Sub
    Private Sub SaveLinksDataTable(doc As XmlDocument)
        For Each node As XmlNode In doc.DocumentElement("Tasks").ChildNodes
            Dim predecessor As XmlNode = node("PredecessorLink")
            If predecessor IsNot Nothing Then
                Dim id As Integer = Integer.Parse(node("UID").InnerText)
                Dim startId As Integer = Integer.Parse(predecessor("PredecessorUID").InnerText)
                Dim linkType As Integer = Integer.Parse(predecessor("Type").InnerText)
                Me.dataSet.Tables("Links").Rows.Add(startId, id, linkType)
            End If
        Next
    End Sub
End Class
Public Class ImporterNode
    Private m_row As DataRow
    Private m_children As List(Of ImporterNode)
    Public Sub New()
        Me.m_children = New List(Of ImporterNode)()
    End Sub
    Public Property Row() As DataRow
        Get
            Return m_row
        End Get
        Set(value As DataRow)
            m_row = value
        End Set
    End Property
    Public ReadOnly Property Children() As List(Of ImporterNode)
        Get
            Return m_children
        End Get
    End Property
End Class

After you have this code in your project you can load the data from the xml into RadGanttView like this:

string fileLocation = @"C:\file.xml";
MsProjectImporter importer = new MsProjectImporter(); 
StringReader reader = new StringReader(fileLocation); 
DataSet dataSet = importer.GetData(reader);
this.radGanttView1.DataSource = dataSet;

Dim fileLocation As String = "C:\file.xml"
Dim importer As New MsProjectImporter()
Dim reader As New StringReader(fileLocation)
Dim dataSet As DataSet = importer.GetData(reader)

See Also