Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

A Simple PList Parser in C#

5.00/5 (4 votes)
19 Jun 2012CPOL2 min read 48.7K  
A simple plist parser within 100 lines of C# code.

Introduction

Recently I've been put in charge of making a texture packaging tool at work. We are using pure C# (4.0) for our tools. I need to read and parse plist files in my code. I searched the Internet, but unfortunately it seems it's lacking a plist parser in C#. I understood plist grammar very quick even by reading a few sample files, since it would be easy to analyze for a human as well easy to recognize for a parser. I decided to reinvent this wheel.

Show me the code

The implementation is quite simple, I did it in about an hour. Let's take a quick look at the whole code: 

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Data
{
    public class PList : Dictionary<string, dynamic>
    {
        public PList()
        {
        }

        public PList(string file)
        {
            Load(file);
        }

        public void Load(string file)
        {
            Clear();

            XDocument doc = XDocument.Load(file);
            XElement plist = doc.Element("plist");
            XElement dict = plist.Element("dict");

            var dictElements = dict.Elements();
            Parse(this, dictElements);
        }

        private void Parse(PList dict, IEnumerable<XElement> elements)
        {
            for (int i = 0; i < elements.Count(); i += 2)
            {
                XElement key = elements.ElementAt(i);
                XElement val = elements.ElementAt(i + 1);

                dict[key.Value] = ParseValue(val);
            }
        }

        private List<dynamic> ParseArray(IEnumerable<XElement> elements)
        {
            List<dynamic> list = new List<dynamic>();
            foreach (XElement e in elements)
            {
                dynamic one = ParseValue(e);
                list.Add(one);
            }

            return list;
        }

        private dynamic ParseValue(XElement val)
        {
            switch (val.Name.ToString())
            {
                case "string":
                    return val.Value;
                case "integer":
                    return int.Parse(val.Value);
                case "real":
                    return float.Parse(val.Value);
                case "true":
                    return true;
                case "false":
                    return false;
                case "dict":
                    PList plist = new PList();
                    Parse(plist, val.Elements());
                    return plist;
                case "array":
                    List<dynamic> list = ParseArray(val.Elements());
                    return list;
                default:
                    throw new ArgumentException("Unsupported");
            }
        }
    }
}

It's never more clear, isn't it?

The LINQ and dynamic type benefit this lightweight class. It would cost more lines without them. This class is a recursive data structure, although we can't see PList property defined in it; the base class is Dictionary<string, dynamic>, and values in it could be a value of string/int/float/bool/PList/List<dynamic>. The parsing methods are recursive, since the recursive structure. The Parse method enumerates all key-value pairs in a piece of XML data and fill the parsed string-dynamic pairs into the PList structure; each step it will call the ParseValue method to parse a value; the ParseValue method calls data conversion methods or ParseArray or Parse recursively according to the type indicated in the name of a XML node; the ParseArray method enumerates all sub XML nodes and parse them to dynamic type by calling ParseValue recursively. Of course we could use object instead of dynamic out there, but we had to add more type discrimination when we were retrieving a value from a PList, that is something I'd like to avoid. 

Using the code

To parse a plist file, just code it as:

C#
PList plist = new PList();
plist.Load("file_path.plist");

or:

C#
PList plist = new PList("file_path.plist");

To retrieve the parsed data it's all the same as using a generic Dictionary, considering the PList is derived from Dictionary<string, dynamic>. The code might looks crude, because I'd like to only show the main idea here without disturbing noise. I think you could and should polish it before using it, for example adding some error/exception handling, or adding a serialization method, etc. Those could be very simple tasks.

Have fun 

Making a plist parser in C# is easier than I expected, and it works fine for me. I hope it would help you too. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)