Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

got another question here. Its not about actually writing/reading files in XML, i already know how to-do this. But rather something that has bugged me for awhile. Ok, so when i write out my files, they look like this:

<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
 <Asset Type="ProjectWitch.Animation">
      <Filename>C:\Users\Daniel Randell\Desktop\Project Witch\Project Witch (MAIN)\Project_Witch (MAIN)\Project_Witch (MAIN)Content\player.png</Filename>
      <CurrentFrame>0</CurrentFrame>
      <Number_Of_Frames>1</Number_Of_Frames>
      <Max_Time_Per_Frame>0</Max_Time_Per_Frame>
      <Animate_Once>0</Animate_Once>
      <Using_Image>1</Using_Image>
      <Rect>
        0    166  64   58   
      </Rect>
      <Vector2>
        12   12   
      </Vector2>
      <Rect>
        81   71   51   59   False
        80   71   13   43   True 
        121  71   12   22   True 
        130  82   7    41   True 
        89   63   11   23   True 
      </Rect>
 </Asset Type="ProjectWitch.Animation">

As you can see the problem, it should write out at the end:

      </Asset>
 </XnaContent>

But it's always writes out the:

 </Asset Type="ProjectWitch.Animation"> 

Its a bit annoying to keep having to look into the XML files and deleting this, so i'm wondering what i'm doing wrong?

Saving Code: http://pastebin.com/yyC3q3aS

Thanks for any help :).

share|improve this question

1 Answer 1

up vote 6 down vote accepted

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.

share|improve this answer
    
Thanks again Dave! 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? –  dan369 Jan 8 '12 at 18:30
1  
Sure I don't see any limitations in using XDocument. There's two options. Either you save them as attributes, e.g. <Rectangle X="0" Y="0" Width="100" Height="100" />. Or you serialize/deserialize them into string, e.g. <Rectangle>0,0,100,100</Rectangle> and doing a string.Split(',') when reading it back. –  David Gouveia Jan 8 '12 at 18:35
    
Just looked again at your example, and just in case the previous comment wasn't clear enough, I'll edit in my post a little example of how you could proceed. –  David Gouveia Jan 8 '12 at 18:43
    
Thanks again :), Really liking XDocument already, a-lot more straight-forward to use. –  dan369 Jan 8 '12 at 18:54
    
Quickly, last comment, in terms of reading the file, how would that work? –  dan369 Jan 8 '12 at 18:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.