How to delete selected node from XML in C#? - c#

I am New To C# I have problem...
I want to delete selected node from My XMl File
Here I just tried with this code but I didn't get please can any one help in that
private void btnDelete_Click(object sender, EventArgs e)
{
xdoc.Load(strFilename);
string Xpath = string.Format("root/{0}/{1}",_strProCat,_strProdType);
xdoc.SelectSingleNode(Xpath).RemoveAll();
xdoc.Save(strFilename);
MessageBox.Show("Deleted Successfully");
}
Here My Xml File
<root>
<product category="Soaps">
<product type="Washing">
<product name="Rin">
<Id>100</Id>
<AvailProducts>30</AvailProducts>
<Cost>20.00</Cost>
</product>
<product name="Tide">
<Id>101</Id>
<AvailProducts>30</AvailProducts>
<Cost>15.00</Cost>
</product>
</product>
</product>
</root>
Just I want to delete Node which product name="Tide"

You can simple use the below code:
private void btnDelete_Click(object sender, EventArgs e)
{
var xDoc = XDocument.Load(strFilename);
foreach (var elem in xDoc.Document.Descendants("product"))
{
foreach (var attr in elem.Attributes("name"))
{
if (attr.Value.Equals("Tide"))
elem.RemoveAll();
}
}
xDoc.Save(destinationFilename);
MessageBox.Show("Deleted Successfully");
}
Happy Coding...

Something like this should do it:
xdoc.Elements("product").Where(x=> x.Element("name").Value == "Tide").FirstOrDefault().Remove();

If you want XPath with XmlDocument then following is the way to do it..
XmlDocument xdoc = new XmlDocument();
xdoc.Load(strFilename);
string Xpath = string.Format("root/product[#category='{0}']/product[#type='{1}']/product[#name='{2}']", "Soaps", "Washing", "Tide");
xdoc.SelectSingleNode(Xpath).RemoveAll();
xdoc.Save(strFilename);
Update
As per your Requirement To Remove the empty node, try following code to remove empty node as
XmlNodeList emptyElements = xdoc.SelectNodes(#"//*[not(node())]");
for (int i = emptyElements.Count - 1; i > -1; i--)
{
XmlNode nodeToBeRemoved = emptyElements[i];
nodeToBeRemoved.ParentNode.RemoveChild(nodeToBeRemoved);
}
Now your final full flesh code will look like as
string Xpath = string.Format("root/product[#category='{0}']/product[#type='{1}']/product[#name='{2}']", "Soaps", "Washing", "Tide");
xdoc.SelectSingleNode(Xpath).RemoveAll();
XmlNodeList emptyElements = xdoc.SelectNodes(#"//*[not(node())]");
for (int i = emptyElements.Count - 1; i > -1; i--)
{
XmlNode nodeToBeRemoved = emptyElements[i];
nodeToBeRemoved.ParentNode.RemoveChild(nodeToBeRemoved);
}
xdoc.Save(strFilename);

Related

How to update xml file without using Linq?

I have this xml file:
<students>
<student>
<name>Mark</name>
<age>20</age>
</student>
<student>
<name>Adam</name>
<age>32</age>
</student>
I want to change the age of Adam, for that I did:
XmlDocument doc = new XmlDocument();
doc.Load("/path/to/sutdents.xml");
XmlNode n = doc.SelectSingleNode("/students/student[name='" + student.name +
"']");
if (n != null)
{
n.SelectNodes("age").Item(0).FirstChild.Value = new_value;
}
but I get "n" as a null value.
I tried another way to do that by searching for the node using foreach and make change, but I get Null Exception:
XmlDocument doc = new XmlDocument();
doc.Load("/path/to/sutdents.xml");
XmlNodeList nodes = doc.SelectNodes("/students/student");
foreach (XmlNode node in nodes)
{
if (node.FirstChild.InnerText == student.name)
{
node.SelectSingleNode("age").InnerText = new_value;
}
}
what I missing here please?
Thanks in advance
I tried to run your code. that is work! check what is the value of student.name.
XML [sutdents.xml]
<?xml version="1.0" standalone="yes"?>
<students>
<student>
<name>Mark</name>
<age>20</age>
</student>
<student>
<name>Adam</name>
<age>32</age>
</student>
</students>
sample code:
XmlDocument doc = new XmlDocument();
doc.Load("sutdents.xml");
XmlNode n = doc.SelectSingleNode("/students/student[name='Adam']");
if (n != null)
{
n.SelectNodes("age").Item(0).FirstChild.Value = "44";
}
doc.Save("sutdents.xml");
i hope this helps;
When Using foreach:
XmlNodeList studentsList = doc.ChildNodes[0].SelectNodes("student");
foreach (XmlNode node in studentsList)
{
if (node.ChildNodes[0].InnerText == student.name) //name
{
node.ChildNodes[1].InnerText = new_value; //age
}
}
Your Code is Correct here is a screen shot of your debugged code with same xml and mentioned code, check you are passing student.name with correct value and case sensitive.
Try this using XDocument:
private static void UpdateXML(string xmlpath, string studentName, int age)
{
var doc = XDocument.Load(xmlpath);
//Get student
var student = doc.Descendants("student").Where(att => att.Element("name") != null && att.Element("name").Value.Equals(studentName)).FirstOrDefault();
if (student != null)
student.Element("age").Value = age.ToString();
doc.Save(xmlpath);
}

XML represantation of treeview nodes

I am trying to import and export to treeview from XML file. But i am having this issue. sample treeview have one root node and two child nodes of same parent. The codes i am using for exporting and importing doesn't work. When I export the treeview the saved XML file is like this:
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
BBBCCC</AAA>
When I import that xml file to treeview it look like this after import xml to treeview . Codes that i am using for export and import are:
//Open the XML file, and start to populate the treeview
private void populateTreeview()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Open XML Document";
dlg.Filter = "XML Files (*.xml)|*.xml";
dlg.FileName = Application.StartupPath + "\\..\\..\\example.xml";
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
//Just a good practice -- change the cursor to a
//wait cursor while the nodes populate
this.Cursor = Cursors.WaitCursor;
//First, we'll load the Xml document
XmlDocument xDoc = new XmlDocument();
xDoc.Load(dlg.FileName);
// Now, clear out the treeview,
// and add the first (root) node
treeView1.Nodes.Clear();
treeView1.Nodes.Add(new TreeNode(xDoc.DocumentElement.Name));
TreeNode tNode = new TreeNode();
tNode = (TreeNode)treeView1.Nodes[0];
// We make a call to addTreeNode,
// where we'll add all of our nodes
addTreeNode(xDoc.DocumentElement, tNode);
// Expand the treeview to show all nodes
treeView1.ExpandAll();
}
catch(XmlException xExc)
{
// Exception is thrown is there is an error in the Xml
MessageBox.Show(xExc.Message);
}
catch(Exception ex) //General exception
{
MessageBox.Show(ex.Message);
}
finally
{
this.Cursor = Cursors.Default; //Change the cursor back
}
}
}
// This function is called recursively until all nodes are loaded
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
XmlNode xNode;
TreeNode tNode;
XmlNodeList xNodeList;
if (xmlNode.HasChildNodes) // The current node has children
{
xNodeList = xmlNode.ChildNodes;
for(int x = 0; x <= xNodeList.Count - 1; x++)
{
// Loop through the child nodes
xNode = xmlNode.ChildNodes[x];
treeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = treeNode.Nodes[x];
addTreeNode(xNode, tNode);
}
}
else //No children, so add the outer xml (trimming off whitespace)
treeNode.Text = xmlNode.OuterXml.Trim();
}
private XmlTextWriter xr;
public void exportToXml2(TreeView tv, string filename)
{
xr = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
xr.WriteStartDocument();
//Write our root node
xr.WriteStartElement(treeView1.Nodes[0].Text);
foreach (TreeNode node in tv.Nodes)
{
saveNode2(node.Nodes);
}
//Close the root node
xr.WriteEndElement();
xr.Close();
}
private void saveNode2(TreeNodeCollection tnc)
{
foreach (TreeNode node in tnc)
{
// If we have child nodes, we'll write
// a parent node, then iterate over
// the children
if (node.Nodes.Count > 0)
{
xr.WriteStartElement(node.Text);
saveNode2(node.Nodes);
xr.WriteEndElement();
}
else //No child nodes, so we just write the text
{
xr.WriteString(node.Text);
}
}
}
Where is the problem?
You are using language other than English . please convert and save .
var text = File.ReadAllText(file, Encoding.GetEncoding(codePage));
how-to-read-text-files-with-ansi-encoding-and-non-english-letters
File.WriteAllText(filepath, filetext, Encoding.Unicode);
or
new System.IO.StreamWriter(new FileStream(file_name,FileMode.OpenOrCreate),Encoding.ASCII);
read-write-text-file-ansi-utf8-unicode
how-to-convert-utf7-string-into-ansi-in-csharp
The code is fine. The xml should look like this
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
<BBB/>
<CCC/>
</AAA>
ok, I modified a few lines and I managed what i want to.
Firstly, I add char array for special characters. And use them for trim() function.
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
**char[] karakter = new char[] { '<', '>', '/' };**
XmlNode xNode;
TreeNode tNode;
XmlNodeList xNodeList;
if (xmlNode.HasChildNodes) //The current node has children
{
xNodeList = xmlNode.ChildNodes;
for (int x = 0; x <= xNodeList.Count - 1; x++)
{
xNode = xmlNode.ChildNodes[x];
treeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = treeNode.Nodes[x];
addTreeNode(xNode, tNode);
}
}
else
{
treeNode.Text = xmlNode.OuterXml.Trim(**karakter**);
}
secondly, if there is no child nodes I used WriteRaw method instead of WriteString method.Because special characters are replaced by WriteString method.
private void saveNode2(TreeNodeCollection tnc)
{
foreach (TreeNode node in tnc)
{
if (node.Nodes.Count > 0)
{
xr.WriteStartElement(node.Text);
saveNode2(node.Nodes);
xr.WriteEndElement();
}
else
{
**xr.WriteRaw($"<{node.Text}/>");**
}
}
But when I try to save treeview with two roots, It doesn't write the last root. Any opinion? Childs of last root is written as childs of first root. Other then that codes work.

how to select child nodes in particular xml node?

I want to delete selected row and update the xml file and then load the grid view with updated data. When debugging I get null value for nodelist.
This is my xml file
<?xml version="1.0" encoding="utf-8" ?>
<PERSONES>
<person>
<name>Dilan Perera</name>
<age>22</age>
</person>
<person>
<name>Thusitha Badde</name>
<age>24</age>
</person>
</PERSONES>
Here is the button click event. The problem is I get null value for nodelist
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
GridViewRow row = (GridViewRow)GridView1.Rows[e.RowIndex];
string age = row.Cells[2].Text.Trim(); // i get correct value for age here
XmlDocument doc2 = new XmlDocument();
doc2.Load(Server.MapPath("names.xml"));
XmlNode nodeList = doc2.SelectSingleNode(string.Format("PERSONES/person[#age='{0}']", age));
doc2.DocumentElement.RemoveChild(nodeList);
doc2.Save(Server.MapPath("names.xml"));
getdata();
}
The xpath query is incorrect, # means attribute, so remove # in the age check, then it will filter the element.
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
GridViewRow row = (GridViewRow)GridView1.Rows[e.RowIndex];
string age = row.Cells[2].Text.Trim(); // i get correct value for age here
XmlDocument doc2 = new XmlDocument();
doc2.Load(Server.MapPath("names.xml"));
XmlNode nodeList = doc2.SelectSingleNode(string.Format("PERSONES/person[age='{0}']", age));
doc2.DocumentElement.RemoveChild(nodeList);
doc2.Save(Server.MapPath("names.xml"));
getdata();
}
I have just tested this and it works.
XmlDocument doc2 = new XmlDocument();
doc2.Load(Server.MapPath("names.xml"));
XmlNode ageNode = doc2.SelectSingleNode(string.Format("//PERSONES/person/age[text() = '{0}']", age));
if (ageNode != null)
{
var personNode = ageNode.ParentNode;
doc2.DocumentElement.RemoveChild(personNode);
doc2.Save(Server.MapPath("names.xml"));
}

How do I delete an entry from an XML file?

I have the xml information populate in a listBox(lstAnimals). I can delete from the listBox with the following code:
private void btnAdopt_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Complete Adoption?", "Found a Happy Home!", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
if (lstAnimals.SelectedIndex >= 0)
lstAnimals.Items.Remove(lstAnimals.SelectedItem);
}
else
{
return;
}
However, when the list is updated/program opened, that entry repopulates into the listBox. How can I delete this from the XML document simultaneously with the lixtBox?
Here is the xml:
<?xml version="1.0" encoding="UTF-8"?>
<Animals>
<Animal>
<Name>Bruce</Name>
<Type>Dog</Type>
<Age>Adult</Age>
</Animal>
<Animal>
<Name>Gizmo</Name>
<Type>Cat</Type>
<Age>Senior</Age>
</Animal>
</Animals>
I was asked how I populate my listBox, so here is the code:
private void UpdateList()
{
var an = XElement.Load(#"Animals.xml")
.Descendants("Animal")
.OrderBy(xe => (xe.Element("Name").Value))
.ToList<XElement>();
lstAnimals.Items.Clear();
foreach (var a in an)
lstAnimals.Items.Add(new Animal()
{
name = a.Element("Name").Value.ToString(),
type = a.Element("Type").Value,
age = a.Element("Age").Value
});
}
Picture of what the listBox presents as:
http://img.photobucket.com/albums/v84/Shades9323/shelterapp_zps4c22868c.jpg
Add this code into your button click event
string text = lstAnimals.SelectedItem.ToString();
string animalName = text.Substring(0, text.IndexOf("is")).Trim();
XDocument xDoc = XDocument.Load("Animals.xml"); //here is your filepath
XElement element = (from x in xDoc.Descendants("Animal")
where x.Element("Name").Value == animalName
select x).First();
element.Remove();
xDoc.Save("Animals.xml");
lstAnimals.Items.Remove(lstAnimals.SelectedItem);
Ofcourse if you add Id property to your animals,it will be easier.Just store id variable into your listBox Items "Tag" property..
You can use XmlDocument removeChild method similar to this
XmlDocument doc ;
doc = new XmlDocument();
doc.Load("path to your XML file");
XmlNode animalNode;
XmlNode root = doc.DocumentElement;
animalNode=root.SelectSingleNode("descendant::Animal[Name='" + lstAnimals.SelectedItem + "']");
doc.RemoveChild(animalNode) ;
//save the XML file
Here how you can do it using linq to xml
private void btnAdopt_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Complete Adoption?", "Found a Happy Home!", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
if (lstAnimals.SelectedIndex >= 0)
{
lstAnimals.Items.Remove(lstAnimals.SelectedItem);
XDocument xDoc = XDocument.Load("test.xml");
xDoc.Descendants("Animal").Where(x => x.Element("Name").Value.ToString() == lstAnimals.SelectedItem ).Remove();
xDoc.Save("test1.xml");
}
}
else
{
return;
}

Querying XML document

I am trying to query an xml document, but this code doesn't read xml parts with closed tag notation but reads fine xelement. Can anyone spot what I'm doing wrong?
I have program generated XML document which gives closed tagged file hence its an issue now..
<?xml version="1.0" encoding="utf-8" ?>
<Student>
<Person name="John" city="Auckland" country="NZ" />
<Person>
<Course>GDICT-CN</Course>
<Level>7</Level>
<Credit>120</Credit>
<Date>129971035565221298</Date>
</Person>
<Person>
<Course>GDICT-CN</Course>
<Level>7</Level>
<Credit>120</Credit>
<Date>129971036040828501</Date>
</Person>
</Student>
class Program
{
static void Main(string[] args)
{
XDocument xDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "Customers.xml");
IEnumerable<XElement> rows = from row in xDoc.Descendants("Person") select row;
foreach(XElement xEle in rows)
{
IEnumerable<XAttribute>attlist = from att in xEle.DescendantsAndSelf().Attributes() select att;
foreach(XAttribute xatt in attlist)
{
Console.WriteLine(xatt);
}
Console.WriteLine("-------------------------------------------");
}
Console.ReadLine();
}
}
Since you have added Course and other attributes as XElement, so you need to loop on XElements instead of attributes -
foreach (XElement xEle in rows)
{
IEnumerable<XAttribute> attlist = from att in xEle.DescendantsAndSelf()
.Attributes() select att;
foreach (XAttribute xatt in attlist)
{
Console.WriteLine(xatt);
}
foreach (XElement elemnt in xEle.Descendants())
{
Console.WriteLine(elemnt.Value);
}
Console.WriteLine("-------------------------------------------");
}
First you must navigate to Person level and iterate through Persons, then for each Person you can iterate through its attributes.
private static void Main(string[] args)
{
//string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
//XDocument xDoc = XDocument.Load(path + "\\Student Data\\data.xml");
XDocument xDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "Customers.xml");
IEnumerable<XElement> xElements = xDoc.Descendants("Person");
foreach (XElement element in xElements)
{
foreach (XAttribute attribute in element.Attributes())
{
Console.WriteLine(attribute);
}
Console.WriteLine("-------------------------------------------");
}
Console.ReadLine();
}

Categories