You wrote:
writer.WriteStartElement("Asset Type=\"ProjectWitch.Animation\"");
That is not how you add an attribute using XmlTextWriter
. I think the correct would be:
writer.WriteStartElement("Asset");
writer.WriteAttributeString("Type", "ProjectWitch.Animation");
And make sure you're not missing any WriteEndElement
call.
By the way, the most recent and recommended method of handling XML in C# is the XDocument API. You should consider making the switch, because it works at an higher level, and you don't need to manually start and end your tags. Example:
// Create content
var root = new XElement("Player", // Create root node
new XAttribute("Id", "1"), // Add attribute
new XElement("Name", "Jon Skeet") // Add child node with value
);
// Save to disk
XDocument document = new XDocument(root);
document.Save("file.xml");
Which would produce the following XML:
<?xml version="1.0" encoding="utf-8"?>
<Player Id="1">
<Name>Jon Skeet</Name>
</Player>
Edit 1
Just wondering though with using the XDocument API, as you can see i'm saving alot of data, more importantly the Rectangles & Vector2s. Its quite fiddly i find to save these currently and i don't want to have a new element for each field i.e X/Y/Width/Height but rather like it is currently. Is that possible using the XDocument Api?
In the comments you raised concerns about being able to do something like this:
<Rect>
81 71 51 59
80 71 13 43
121 71 12 22
130 82 7 41
89 63 11 23
</Rect>
You were using methods such as XmlTextWriter.WriteValue
and XmlTextWriter.WriteWhiteSpace
to do this incremental sort of writing. As far as I know you can't write to an XElement
this way, but coupled with a StringBuilder
object (which you can reuse) it's easy to get a similar behavior:
var stringBuilder = new StringBuilder(); // Create only once
stringBuilder.Clear();
foreach(var r in rectangles)
{
stringBuilder.AppendLine(
String.Format("{0}\t{1}\t{2}\t{3}", r.X, r.Y, r.Width, r.Height)
);
}
var rectElement = new XElement("Rect", stringBuilder.ToString());
The StringBuilder
has both Append
and AppendLine
methods which will still allow you to construct your values similarly to what you were doing before.
But there are many other ways to do this, some more efficient, others easier. Personally, I would do:
public static string SerializeRectangle(Rectangle r)
{
return String.Format("{0}\t{1}\t{2}\t{3}", r.X, r.Y, r.Width, r.Height);
}
var rectElement = new XElement("Rect", String.Join("\n", rectangles.Select(SerializeRectangle)));
Edit 2
Last comment, in terms of reading the file, how would that work?
Here's a simple loading example without error handling. In a real scenario you should always check if Element
or Attribute
returns null:
var document = XDocument.Load("file.xml");
var player = document.Element("Player");
int id = int.Parse(player.Attribute("Id").Value);
string name = player.Element("Name").Value;
If there's more than one element with a certain name, use the Elements
method instead to retrieve all of them at once.