简体   繁体   中英

Updating specific XML elements in C#

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 (eg 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,

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.

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.

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM