0
votes

I'd like to do this the right way if possible. I have XML data as follows:

<?xml version="1.0" encoding="utf-8"?>
    <XnaContent>
        <Asset Type="PG2.Dictionary">
            <Letters TotalInstances="460100">
                <Letter Count="34481">&#97;</Letter>
                ...
                <Letter Count="1361">&#122;</Letter>
            </Letters>
            <Words Count="60516">
                <Word>aardvark</Word>
                ...
                <Word>zebra</Word>
            </Words>
        </Asset>
    </XnaContent>

and I'd like to load this in (using Content.Load< Dictionary >) into one of these

namespace PG2
{
    public class Dictionary
    {
        public class Letters
        {
            public int totalInstances;

            public List<Character> characters;

            public class Character
            {
                public int count;
                public char character;
            }
        }

        public class Words
        {
            public int count;
            public HashSet<string> words;
        }

        Letters letters;
        Words words;
    }
}

Can anyone help with either instructions or pointers to tutorials? I've found a few which come close but things seem to have changed slightly between 3.1 and 4.0 in ways which I don't understand and a lot of the documentation assumes knowledge I don't have. My understanding so far is that I need to make the Dictionary class Serializable but I can't seem to make that happen. I've added the XML file to the content project but how do I get it to create the correct XNB file?

Thanks! Charlie.

2

2 Answers

1
votes

This may help http://blogs.msdn.com/b/shawnhar/archive/2009/03/25/automatic-xnb-serialization-in-xna-game-studio-3-1.aspx. I found it useful to work the other way round to check that my xml data was correctly defined. Instantate your dictionary class set all the fields then serialize it to xml using a XmlSerializer to check the output.

0
votes

You need to implement a ContentTypeSerializer for your Dictionary class. Put this in a content extension library and add a reference to the content extension library to your content project. Put your Dictionary class into a game library that is reference by both your game and the content extension project.

See: http://blogs.msdn.com/b/shawnhar/archive/2008/08/26/customizing-intermediateserializer-part-2.aspx

Here is a quick ContentTypeSerializer I wrote that will deserialize your Dictionary class. It could use better error handling.

using System;
using System.Collections.Generic;
using System.Xml;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;

namespace PG2
{
    [ContentTypeSerializer]
    class DictionaryXmlSerializer : ContentTypeSerializer<Dictionary>
    {
        private void ReadToNextElement(XmlReader reader)
        {
            reader.Read();

            while (reader.NodeType != System.Xml.XmlNodeType.Element)
            {
                if (!reader.Read())
                {
                    return;
                }
            }
        }

        private void ReadToEndElement(XmlReader reader)
        {
            reader.Read();

            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                reader.Read();
            }
        }

        private int ReadAttributeInt(XmlReader reader, string attributeName)
        {
            reader.MoveToAttribute(attributeName);
            return int.Parse(reader.Value);
        }

        protected override Dictionary Deserialize(IntermediateReader input, Microsoft.Xna.Framework.Content.ContentSerializerAttribute format, Dictionary existingInstance)
        {
            Dictionary dictionary = new Dictionary();
            dictionary.letters = new Dictionary.Letters();
            dictionary.letters.characters = new List<Dictionary.Letters.Character>();
            dictionary.words = new Dictionary.Words();
            dictionary.words.words = new HashSet<string>();

            ReadToNextElement(input.Xml);
            dictionary.letters.totalInstances = ReadAttributeInt(input.Xml, "TotalInstances");

            ReadToNextElement(input.Xml);

            while (input.Xml.Name == "Letter")
            {
                Dictionary.Letters.Character character = new Dictionary.Letters.Character();

                character.count = ReadAttributeInt(input.Xml, "Count");

                input.Xml.Read();
                character.character = input.Xml.Value[0];

                dictionary.letters.characters.Add(character);
                ReadToNextElement(input.Xml);
            }

            dictionary.words.count = ReadAttributeInt(input.Xml, "Count");

            for (int i = 0; i < dictionary.words.count; i++)
            {
                ReadToNextElement(input.Xml);
                input.Xml.Read();
                dictionary.words.words.Add(input.Xml.Value);
                ReadToEndElement(input.Xml);
            }

            ReadToEndElement(input.Xml);    // read to the end of words
            ReadToEndElement(input.Xml);    // read to the end of asset

            return dictionary;
        }

        protected override void Serialize(IntermediateWriter output, Dictionary value, Microsoft.Xna.Framework.Content.ContentSerializerAttribute format)
        {
            throw new NotImplementedException();
        }
    }
}