Reputation: 59
I am building a game in C# which will store multiple user's data in an XML file. I am having trouble figuring out how to update XML data for only the current player (e.g. Jack):
<?xml version="1.0" encoding="utf-8"?>
<PlayerStats>
<Name>Jack</Name>
<WinCount>15</WinCount>
<PlayCount>37</PlayCount>
<Name>John</Name>
<WinCount>12</WinCount>
<PlayCount>27</PlayCount>
</PlayerStats>
The element in the XML file should match a string variable "strPlayerName" from C# (Jack). Then, only Jack's WinCount and PlayCount numbers should be updated.
How can I match the element with the strPlayerName string variable and then update the and numbers in the XML doc for only this player? Thanks,
Upvotes: 1
Views: 3037
Reputation: 36053
Change your XML structure to be as follows:
<?xml version="1.0" encoding="utf-8" ?>
<PlayerStats>
<Player>
<Name>Jack</Name>
<WinCount>15</WinCount>
<PlayCount>37</PlayCount>
</Player>
<Player>
<Name>John</Name>
<WinCount>12</WinCount>
<PlayCount>27</PlayCount>
</Player>
</PlayerStats>
Create some classes to hold your XML data:
[XmlRoot("PlayerStats")]
public class PlayerStats
{
[XmlElement(ElementName = "Player")]
public List<Player> Players { get; set; }
}
public class Player
{
public string Name { get; set; }
public int WinCount { get; set; }
public int PlayCount { get; set; }
}
Then you can do the following to read it, update and re-write the file.
PlayerStats stats;
using (var fileStream = new System.IO.FileStream("Sample.XML", System.IO.FileMode.Open))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(PlayerStats));
stats = (PlayerStats)xmlSerializer.Deserialize(fileStream);
}
var player = stats.Players.Where(p => p.Name == "Jack").FirstOrDefault();
if (player != null)
{
// Update the record
player.WinCount = player.WinCount + 1;
player.PlayCount = player.PlayCount + 1;
// Save back to file
using (var fileStream = new System.IO.FileStream("Sample.XML", System.IO.FileMode.Create))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(PlayerStats));
xmlSerializer.Serialize(fileStream, stats);
}
}
Upvotes: 0
Reputation: 434
As Matthew Watson recommended, a good solution would be using XML and Serialization.
Create an xml in your project and make sure its properties are set to none for Build Action and Copy Always or Copy if Newer for Copy to Output Directory.
Here is an example of the xml file:
<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfPlayer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Player>
<Name>Jack</Name>
<WinCount>15</WinCount>
<PlayCount>37</PlayCount>
</Player>
<Player>
<Name>John</Name>
<WinCount>12</WinCount>
<PlayCount>27</PlayCount>
</Player>
</ArrayOfPlayer>
Now we will use this XML to deserialize it into a List of Players. I have a helper class for serialization below. You would read the XML file contents and pass it to the Deserialize method as shown. When you wish to save the Players list, pass the list to Serializer and save back to your file.
Serializer helper class:
public static class Serializer
{
public static string SerializeObject(object objectToSerialize)
{
XmlSerializer x = new XmlSerializer(objectToSerialize.GetType());
StringWriter writer = new StringWriter();
x.Serialize(writer, objectToSerialize);
return writer.ToString();
}
public static T DeserializeObject<T>(string serializedObject)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(serializedObject);
return (T)xs.Deserialize(reader);
}
}
Using the class to Deserialize:
//Change this as needed to read your XML file.
string playersXML = File.ReadAllText(@"./Players.xml");
List<Player> players = Serializer.DeserializeObject<List<Player>>(playersXML);
Using the class to serialize and save the list:
string newPlayersXML = Serializer.SerializeObject(players);
//Change this as needed to point to the XML location
File.WriteAllText(@"./Players.xml", newPlayersXML);
And finally the Player class:
public class Player
{
public string Name { get; set; }
public int WinCount { get; set; }
public int PlayCount { get; set; }
}
You would use your Player class and the list as you need in the code.
Upvotes: 1
Reputation: 101652
Supposing your XML file looked like this:
<PlayerStats>
<Player>
<Name>Jack</Name>
<WinCount>15</WinCount>
<PlayCount>37</PlayCount>
</Player>
<Player>
<Name>John</Name>
<WinCount>12</WinCount>
<PlayCount>27</PlayCount>
</Player>
</PlayerStats>
Here's how you could update John's stats using the XmlNode
API:
string name = "John";
XmlNode player = doc.SelectNodes("/PlayerStats/Player")
.OfType<XmlNode>()
.FirstOrDefault(n => n["Name"].InnerText == name);
if (player != null)
{
player["WinCount"].InnerText = "21";
player["PlayCount"].InnerText = "22";
}
or with LINQ to XML:
var player2 = xe.Descendants("Player")
.FirstOrDefault(n => (string)n.Element("Name") == name);
if (player != null)
{
player2.Element("WinCount").SetValue(21);
player2.Element("PlayCount").SetValue(22);
}
Though as others have said, for a task like this, serializing, deserializing is probably the way to go.
Upvotes: 0