Home > Software design >  Deleting nodes from xml with c#
Deleting nodes from xml with c#

Time:09-18

I have an xml file. It contains records as in the example below.

<Simulator>
  <Flight ID="1" Description="1sunny" Date="2022-09-09">
    <Instructor Num="6">
      <Name>matt</Name>
      <Surname>matt</Surname>
      <Rank>matt</Rank>
    </Instructor>
  </Flight>
</Simulator>

When I delete it with the delete function, I see such a result and this result breaks my auto generate id function. How can I get the flight tag to be deleted completely?

<Simulator>
  <Flight />
</Simulator>

Delete function

private void b_delete_Click(object sender, EventArgs e)
        {
            var xDoc = XDocument.Load(input);
            foreach (var elem in xDoc.Document.Descendants("Flight"))
            {
                foreach (var attr in elem.Attributes("ID"))
                {
                    if (attr.Value.Equals("1"))
                        elem.RemoveAll();
                }
            }
            xDoc.Save(input);
            MessageBox.Show("Deleted Successfully");
        }

CodePudding user response:

Instead of using a loop, you can get the right element with the LINQ Where extension method. This is the reason why the XDocument stuff is in the System.Xml.Linq Namespace

(I am using C# 11's raw string feature for this test):

string xml = """
    <Simulator>
        <Flight ID="1" Description="1sunny" Date="2022-09-09">
            <Instructor Num="6">
                <Name>matt</Name>
                <Surname>matt</Surname>
                <Rank>matt</Rank>
            </Instructor>
        </Flight>
    </Simulator>
    """;
var xDoc = XDocument.Parse(xml);

xDoc.Root?.Descendants("Flight")
    .Where(f => f.Attribute("ID")?.Value == "1")
    .Remove();

Console.WriteLine(xDoc);

Prints:

<Simulator />

IntelliSense told me that Root and Attribute("ID") can be null. Therefore I used the C# Null-Conditional Operator (? Operator).

If you want to remove only one element, you can speed up the process by using FirstOrDefault instead of Where:

xDoc.Root?.Descendants("Flight")
    .FirstOrDefault(f => f.Attribute("ID")?.Value == "1")
    ?.Remove();

This will stop looping at the first element found. This requires another ? as FirstOrDefault will return null if no matching element was found, whereas Where returns an empty enumeration.

Note that with Where we are using

public static void Remove<T>(this IEnumerable<T?> source) where T : XNode;

with T as XElement, but with FirstOrDefault we call the XNode.Remove(); method.

CodePudding user response:

Just use Remove extension methodon result of Descendants method:

using System.Xml.Linq;

var xDoc = XDocument.Load(input);

xDoc.Document.Descendants("Flight")
    .Remove();

using var writer = new FileStream(output, FileMode.Append);

xDoc.Save(writer);
  • Related