Search code examples
c#arraysxmlxmlserializer

XML Deserialize an array that is not in an array container


I have an XML file (for Tiled tile editor): (snippet of the xml)

<map version="1.0" orientation="orthogonal" renderorder="right-down" width="64" height="64" tilewidth="32" tileheight="32" nextobjectid="1">
 <tileset firstgid="1" name="GrassyTile_01" tilewidth="32" tileheight="32" tilecount="4" columns="2">
  <image source="GrassyTile_01.png" width="64" height="64"/>
 </tileset>
 <tileset firstgid="5" name="BlackTile_01" tilewidth="32" tileheight="32" tilecount="1" columns="1">
  <image source="BlackTile_01.jpg" width="32" height="32"/>
 </tileset>

Regarding the "tileset" elements, there can be X amountof them, but they are not contained in an XmlArray, rather they just follow one-another.

I am looking for a method to use the XMLSerializer to Deserlialize these elements as an array, but I cannot find the correct way of doing this.

This is my code:

 [XmlRoot("map")]
        public class XMLMAP
        {
            [XmlAttribute("version")]
            public string Version;
            [XmlAttribute("orientation")]
            public string Orientation;
            [XmlAttribute("renderorder")]
            public string Renderorder;
            [XmlAttribute("width")]
            public int Width;
            [XmlAttribute("height")]
            public int Height;
            [XmlAttribute("tilewidth")]
            public int Tilewidth;
            [XmlAttribute("tileheight")]
            public int TileHeight;
            [XmlAttribute("nextobjectid")]
            public int NextObjectID;
            [XmlArray]
            public XMLMAP_TILESET[] TileSets;
            [XmlRoot("tileset")]
            public class XMLMAP_TILESET
            {
                [XmlAttribute("firstgid")]
                public string FirstGID;
                //No need for rest of code
            }
        }

Anyone know if this is possible or will I have to resort to an XMLReader?


Solution

  • Try redefining your XMLMAP class as:

    [XmlRoot("map")]
    public class XMLMAP
    {
        [XmlAttribute("version")]
        public string Version;
        [XmlAttribute("orientation")]
        public string Orientation;
        [XmlAttribute("renderorder")]
        public string Renderorder;
        [XmlAttribute("width")]
        public int Width;
        [XmlAttribute("height")]
        public int Height;
        [XmlAttribute("tilewidth")]
        public int Tilewidth;
        [XmlAttribute("tileheight")]
        public int TileHeight;
        [XmlAttribute("nextobjectid")]
        public int NextObjectID;
    
        [XmlElement("tileset")]
        public List<TileSet> TileSets;
    }
    
    [XmlRoot("tileset")]
    public class TileSet
    {
        [XmlAttribute("firstgid")]
        public string FirstGID;
    }
    

    Where XMLMAP contains a List<TileSet>, and TileSet is then defined as a seperate class containing all the required attributes etc.

    I can now deserialise with

    var serializer = new XmlSerializer(typeof(XMLMAP));
    
    var reader = new StreamReader(path);
    var map = (XMLMAP)serializer.Deserialize(reader);
    reader.Close();
    

    And can see that map contains a list of 2 TileSets

    Note that I could only do this after adding a closing </map> tag to the end of your supplied xml.

    Hope that helps