简体   繁体   中英

3 Attempts to delete XML node using C#

I've tried deleting a node from my XML file 3 different ways; and each way I've come up empty. I am querying a SQL database and grabbing a filename, I want to delete the entire node were the file name in the XML document is = to the SQL database result.

I'm not sure what's wrong in my code:

Background Information

fn44 is the Filename grabbed from a SQL database (all my info is in a SQL table, I need an XML file for use with JavaScript)

XML:

<?xml version="1.0" encoding="utf-8"?>
<xml>
  <bannerMain>
    <department>main</department>
    <filename>resdrop.png</filename>
    <title>This is a Title</title>
    <text>&lt;![CDATA[caption <a href="">text</a>]]&gt;</text>
  </bannerMain>
</xml>

Attempt 1 (I know that I'm not getting to the child correctly, can't seem to figure out how to fix it):

XDocument doc = XDocument.Load(Server.MapPath("~/uploads/banners.xml"));
var q = from node in doc.Descendants("bannerMain")
        let fina = node.Descendants("filename")/*PROBLEM LINE*/
        where fina != null && fina == myReader[0]/*Gets filename from SQL database*/
select node;
q.ToList().ForEach(x => x.Remove());
doc.Save(Server.MapPath("~/uploads/banners.xml"));

Attempt 2 (should work in my mind but doesn't)

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(Server.MapPath("~/uploads/banners.xml"));
XmlNode nodeToDelete = xmlDoc.SelectSingleNode("/xml/bannerMain[@filename=" 
+ fn44 + "]");
if (nodeToDelete != null)
{
   nodeToDelete.ParentNode.RemoveChild(nodeToDelete);
}
xmlDoc.Save(Server.MapPath("~/uploads/banners.xml"));

Attempt 3 (similar to attempt 2)

string nodeToDelete = fn44;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(Server.MapPath("~/uploads/banners.xml"));
XmlNode node = xmlDoc.SelectSingleNode(string.Format("//*[filename=\"{0}\"]"
, nodeToDelete));
if (node != null)
   xmlDoc.SelectSingleNode("xml/bannersMain").RemoveChild(node);
xmlDoc.Save(Server.MapPath("~/uploads/banners.xml"));

I want to delete the whole node where the filename is = to the filename that is grabbed from the SQL database. Any help/resources is much appreciated.

SOLVED: There's a few different options in the below answers that work out well.

Solution 1:

var xDoc = XDocument.Load(Server.MapPath("~/uploads/banners.xml"));
string fileName = fn44; //Use whatever value you found in SQL DB...

xDoc.Descendants("filename").Where(c => c.Value == fileName).Select(x => x.Parent).Remove();
xDoc.Save(Server.MapPath("~/uploads/banners.xml"));

Solution 2:

XDocument doc = XDocument.Load(Server.MapPath("~/uploads/banners.xml"));
var q = from node in doc.Descendants("bannerMain")
        let fina = node.Element("filename")
        where fina != null && fina.Value == fn44
        select node;
q.Remove();
doc.Save(Server.MapPath("~/uploads/banners.xml"));

That seems to work for me:

        string xmlfile = Server.MapPath("~/uploads/banners.xml");
        var xDoc = XDocument.Load(xmlfile);
        string fileName = "resdrop.png"; // Value from SQL DB

        xDoc.Descendants("filename")
            .Where(c => c.Value == fileName)
            .Select(x => x.Parent)
            .Remove();
        xDoc.Save(xmlfile);

Your problem with attempt #1 is that you are trying to compare an IEnumerable<XElement> to your reader value, this should work (assuming each bannerMain only has a single filename element):

var q = from node in doc.Descendants("bannerMain") 
        let fina = node.Element("filename")//only single filename, so get just that XElement
        where fina != null && fina.Value == reader[0]//assumes reader[0] is a string value
        select node;

To remove them just do this:

q.Remove();
doc.Save(Server.MapPath("~/uploads/banners.xml"));

I ran this through LINQPad and after doing q.Remove(); , here were the contents of doc:
<xml /> .

It's a little verbose but here is a non-linq snippet:

void DeleteNode(string fileName)
{
    XmlDocument doc = new XmlDocument();
    doc.Load(Server.MapPath("~/uploads/banners.xml"));

    //Get all the bannerMain nodes.
    XmlNodeList nodelist = doc.SelectNodes("/xml//bannerMain");

    if (nodelist != null)
    {
        foreach (XmlNode node in nodelist)
        {
            //Look for then filename child. If it contains desired value
            //delete the entire bannerMain node. Assumes order of child nodes
            //may not be a constant.
            foreach (XmlNode child in node.ChildNodes)
            {
                if (child.Name == "filename" && child.InnerText == name)
                {
                    node.ParentNode.RemoveChild(node);
                }
            }
        }

        doc.Save(Server.MapPath("~/uploads/banners.xml"));
    }
}

For Attempt #2, remove the @ sign for the filename. The @ symbol represents an Attribute, but the filename is a child-node.

If your phrase doesn't work, I'd rephrase it a little from:

"/xml/bannerMain[filename=

to

"//bannerMain[filename=

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