Reputation: 313
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><![CDATA[caption <a href="">text</a>]]></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"));
Upvotes: 3
Views: 901
Reputation: 4987
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);
Upvotes: 4
Reputation: 11955
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=
Upvotes: 1
Reputation: 1135
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"));
}
}
Upvotes: 1
Reputation: 5636
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 />
.
Upvotes: 2