[SOLVED] Content Importer Exception XML element required

Greetings

Sorry if I put this in the wrong place, I’m new here but has been using Monogame for long time actually, having started first in XNA. I have tried few other frameworks and engines, but I while I like and dislike various things, I always return to Monogame as I feel it offers me greatest control and the insight into my own code.

But anyway, to keep it short (and keep personal introduction in more appropriate place), I’ve been making a tactical RPG game and need to load my own map into it. This time, I have decided to use XNA/Monogame content importer for it instead of manually doing work (like before), and after writing my own level editor, preparing all code, adding new library and referencing it… I stumble upon this error in the content pipeline:

Importer 'XmlImporter' had unexpected failure! Microsoft.Xna.Framework.Content.Pipeline.InvalidContentException: The Xml element 'TileSize' is required!

I don’t know what to do, as class which is being deserialized to has the required element. I have tried to look around, but to no avail; I didn’t manage to find anything useful about it; only a tutorial about having to write own content importer and an old bug submit for Monogame which was apparently solved.

To help, here’s the class in question and the (stripped down to minimum) of the accompanying XML file:

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MortalRealmSilkWars
{
public class Level
{
public int TileSize
{
get { return tileSize; }
set { tileSize = value; }
}

    public List<List<Tile>> TileGrid
    {
        get { return tileGrid; }
        set { tileGrid = value; }
    }
    public Point StartPoint
    {
        get { return startPoint; }
        set { startPoint = value; }
    }
    public string MapName
    {
        get { return mapName; }
        set { mapName = value; }
    }
    int tileSize;
    Point startPoint;
    List<List<Tile>> tileGrid;
    string mapName;
    public Level()
    {
    }
    public Point GetTileLocation(Point coordinates)
    {
        Point result = new Point();
        result.X = (coordinates.X - startPoint.X) / tileSize;
        result.Y = (coordinates.Y - startPoint.Y) / tileSize;`
        return result;
    }
}

And XML (replaced <> with { })

{?xml version=“1.0” encoding=“utf-8”?}
{XnaContent}
{Asset Type=“MortalRealmSilkWars.Level”}
{Level}
{TileSize}50{/TileSize}
{TileGrid}
{ArrayOfTile}
{Tile}
{Unwalkable}false{/Unwalkable}
{TileRectangle}
{Location}
{X}50{/X}
{Y}50{/Y}
{/Location}
{Size}
{Width}0{/Width}
0{/Height}
{/Size}
{X}50{/X}
{Y}50{/Y}
{Width}0{/Width}
{Height}0{/Height}
{/TileRectangle}
{TilePosition}
{X}50{/X}
{Y}50{/Y}
{/TilePosition}
{TileSpirits}
{Spirit}
{Name}Air{/Name}
{Amount}0.5{/Amount}
{/Spirit}
{Spirit}
{Name}Earth{/Name}
{Amount}0.5{/Amount}
{/Spirit}
{Spirit}
{Name}Light{/Name}
{Amount}0.5{/Amount}
{/Spirit}
{Spirit}
{Name}Heat{/Name}
{Amount}1{/Amount}
{/Spirit}
{/TileSpirits}
{TileItem}
{Name /}
{Amount}0{/Amount}
{/TileItem}
{/Tile}
{/ArrayOfTile}
{/TileGrid}
{StartPoint}
{X}60{/X}
{Y}60{/Y}
{/StartPoint}
{MapName}Test map{/MapName}
{/Level}
{/Asset}
{/XnaContent}

I have no idea what to do next, as class serializes into XML well and XML itself looks fine, so I need a big help.

Thank you in advance!

I had the same error. I think it’s a bug in XmlImporter:

There are a bunch of topics with this error… I’m pretty sure it’s a bug.

Well, after 5 days of bashing my head against the wall, through trial and error I have managed to not only figure out what’s the problem, but also how to solve it.

Long story short, it seems Content Pipeline is very, very, very, very, very, very, very picky about how the XML being imported and deserialized has to look like. And it turned out the XML I provided was not how it had to look like.

In order to help other people who may have gotten stuck at place similar to mine, I’m going to provide what I found out on my stuff and how to fix it.

I’ll provide pastebins of relevant code and XNA a bit later, I’m too tired right now.


1: XnaContent, Asset and Level tags

<XnaContent> tag could probably be achieved the better way than using XnaContent wrapper class, but I found it to be the simplest way to solve it.

Level tag is simply wrong, as the type of class is specified as attribute of the Asset tag. Due to that, Asset wrapper class is simply wrong as well. Simpler way is to declare public Level Asset { get; set; } inside XnaContent, and another is to mark your class with [XmlRoot(ElementName = "Asset")].

To get Type attribute, declare a public string of name Type inside class being serialized (in my case Level), mark it with [XmlAttribute], then simply put in typeof(T).ToString().


2: Deserializing lists

This was the main reason I posted this topic.
If you check original XML, you’ll see that List<List<Tile>> TileGrid was serialized into tags <TileGrid>, <ArrayOfTiles> and <Tile>.

For the reason I do not know, when deserializing list of objects, Content Pipeline really dislikes if each object is tagged with its type, and instead requires every object to be tagged with <Item>.

Solution? Decorate the list with [XmlArrayItem(ElementName = "Item")].

If the lists are nested (like List<List<T>>), the solution is same, just with one more parameter:
[XmlArrayItem(ElementName = "Item", NestingLevel = 0)]
[XmlArrayItem(ElementName = "Item", NestingLevel = 1)]
public List<List<Tile>> TileGrid { get; set; }

Such simple solution which took me 3 days to identify and solve.


3: Deserializing Monogame Point, VectorX, Rectangle etc.

One thing that caused me some headaches is the way Content Pipeline deserializes Xna/Monogame structures such as Microsoft.Xna.Framework.Point, which I’ll as an example; I think it is same for all such structures, though.

Basically, Content Pipeline requires it to be written in XML as a space-separated list, such as <Point>23 196</Point>. I do not know why though, someone else should provide an answer to that; I think it has something to do with list of points etc. based on some digging around.

The issue? XmlSerializer will deserialize it as
<Point>
<X>0</X>
<Y>0</Y>
<Point>
which I didn’t find a way to change.

So, the workaround is: mark all such public structures with [XmlIgnore].
Then, declare a public string or StringBuilder for each structure and mark it with [XmlElement(ElementName = <name of property with XmlIgnore>)].
Lastly, manually construct a space-separated list by concatenating/appending each value of the structure.


There, I think that’s it. I hope this will help at least a little bit.