Create/delete element on XMLNode c#

There are multiple ways to work with XML files. I’ll show two options below.

Test.xml:

<root>
  <staff id="1">
    <name>Name 1</name>
    <phone>123456</phone>
  </staff>
  <staff id="2">
    <name>Name 2</name>
    <phone>123457</phone>
    <phone>123458</phone>
  </staff>
</root>

Option 1 (LINQ to XML):

Add the following using directive:

  • using System.Xml.Linq;

CreateXmlLinq:

private void CreateXmlLinq(string filename)
{
    XElement root = new XElement("root",
                        new XElement("staff", new XAttribute("id", "1"),
                            new XElement("name", "Name 1"),
                            new XElement("phone", "123456")),

                        new XElement("staff", new XAttribute("id", "2"),
                            new XElement("name", "Name 2"),
                            new XElement("phone", "123457"),
                            new XElement("phone", "123458"))
                        );

    root.Save(filename);
}

Usage:

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "XML File (*.xml)|*.xml";
    sfd.FileName = "Test.xml";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        //save to file
        CreateXmlLinq(sfd.FileName);
        Debug.WriteLine($"Info: Saved to {sfd.FileName}");
    }
}

To remove phone number 123458 where staff id = 2:

RemovePhone:

private void RemovePhone(string filename, string id, string phoneNumber)
{
    //load from file
    XElement root = XElement.Load(filename);

    //remove specified phone number
    root.Elements("staff").Where(s => s.Attribute("id").Value == id).Elements("phone").Where(p => p.Value == phoneNumber).Remove();

    //save to file
    root.Save(filename);
}

Option 2 (XML Serialization):

For this approach, we’ll use nested classes.

Add the following using directives to each of the classes:

  • using System.Collections.Generic;
  • using System.Xml;
  • using System.Xml.Serialization;

You can name the classes whatever you like, I’ve chosen to prepend the word “Xml”. Additionally for the nested classes, I’ve chosen to append the ancestors’ names. In this case, there is only one ancestor (the parent) “root”.

  • XmlRoot
  • XmlRootStaff: (“XmlRoot” + “Staff)

XmlRoot.cs:

[XmlRoot(ElementName = "root", IsNullable = false)]
public class XmlRoot
{
    [XmlElement(ElementName = "staff")]
    public List<XmlRootStaff> Staff { get; set; } = new List<XmlRootStaff>();
}

XmlRootStaff.cs:

public class XmlRootStaff
{
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }

    [XmlElement(ElementName = "name")]
    public string Name { get; set; }

    [XmlElement(ElementName = "phone")]
    public List<string> Phone { get; set; } = new List<string>();
}

To deserialize the XML (read from file) we’ll use the following method:

DeserializeXMLFileToObject:

public static T DeserializeXMLFileToObject<T>(string xmlFilename)
{
    T rObject = default(T);

    try
    {
        if (string.IsNullOrEmpty(xmlFilename))
        {
            return default(T);
        }

        using (System.IO.StreamReader xmlStream = new System.IO.StreamReader(xmlFilename))
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            rObject = (T)serializer.Deserialize(xmlStream);
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine($"Error (DeserializeXMLFileToObject) - {ex.Message}");
        throw;
    }

    return rObject;
}

Usage (deserialize):

private XmlRoot _root = null;
             ...

using (OpenFileDialog ofd = new OpenFileDialog())
{
    ofd.Filter = "XML File (*.xml)|*.xml";
    ofd.FileName = "Test.xml";

    if (ofd.ShowDialog() == DialogResult.OK)
    {
        //deserialize
        _root = HelperXml.DeserializeXMLFileToObject<XmlRoot>(ofd.FileName);
    }
}

To serialize the XML (write to file) we’ll use the following method:

SerializeObjectToXMLFile:

public static void SerializeObjectToXMLFile(object obj, string xmlFilename)
{
    try
    {
        if (string.IsNullOrEmpty(xmlFilename))
        {
            return;
        }//if

        System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
        settings.OmitXmlDeclaration = false;
        settings.Indent = true;
        settings.NewLineHandling = System.Xml.NewLineHandling.Entitize;

        using (System.Xml.XmlWriter xmlWriter = System.Xml.XmlWriter.Create(xmlFilename, settings))
        {
            //specify namespaces
            System.Xml.Serialization.XmlSerializerNamespaces ns = new System.Xml.Serialization.XmlSerializerNamespaces();
            ns.Add(string.Empty, "urn:none");

            //create new instance
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());

            //write XML to file
            serializer.Serialize(xmlWriter, obj, ns);

        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine($"Error (SerializeObjectToXMLFile) - {ex.Message}");
        throw;
    }
}

Usage (serialize):

private XmlRoot _root = null;
                     ...

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "XML File (*.xml)|*.xml";
    sfd.FileName = "Test.xml";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        //create new instance
        _root = new XmlRoot();

       //add data
       _root.Staff.Add(new XmlRootStaff() { Id = "1", Name = "Name 1", Phone = new List<string>() { "123456" } });
       _root.Staff.Add(new XmlRootStaff() { Id = "2", Name = "Name 2", Phone = new List<string>() { "123457", "123458" } });

        //serialize - save to file
        SerializeObjectToXMLFile(_root, sfd.FileName);
        Debug.WriteLine($"Info: Saved to {sfd.FileName}");
    }
}

To remove phone number 123458 where staff id = 2:

private void RemovePhone(string id, string phoneNumber)
{
    if (_root != null)
    {
        for (int i = 0; i < _root.Staff.Count; i++)
        {
            if (_root.Staff[i].Id == id)
            {
                //remove
                _root.Staff[i].Phone.Remove(phoneNumber);
                break;
            }
        }
    }
}

Resources:

Leave a Comment