Remove an item from XML file using C# - c#

I'm trying to write and remove items (categories) that I've stored in an XML file. I've figured out how to add using new XElement and doc.Root.Add but I don't know how to remove and item that has the same title as the input.
XML:
<?xml version="1.0" encoding="utf-8"?>
<categories>
<category title="Horror"></category>
<category title="Romance"></category>
<category title="Health"></category>
<category title="SciFi"></category>
<category title="Programming" />
<category title="History" />
</categories>
C#:
public static void RemoveFromCategoryXMLFile(string title)
{
XmlDocument doc = new XmlDocument();
doc.Load("../../DAL/XML_Categories/Categories.xml");
XmlNode node = doc.SelectSingleNode($"/categories/category[#name='{title}']");
if (node != null)
{
XmlNode parent = node.ParentNode;
parent.RemoveChild(node);
doc.Save("../../DAL/XML_Categories/Categories.xml");
}
}
I want the item that matches the string title to be removed from the document. Right now nothing happens and it seems like the XmlNode returns null.

Using XDocument is recommended, as it is a newer class for parsing XML. With such class it's enought to use such code:
var title = "Horror";
var xml = XDocument.Load(#"path to XML");
xml.Root.Elements("category").Where(e => e.Attribute("title").Value == title).Remove();
xml.Save(#"path to output XML");

Related

Xml parser doesn't work

<?xml version="1.0" encoding="utf-8"?>
<response list="true">
<audio>
<aid>253663595</aid>
<artist>Example</artist>
<duration>389</duration>
<lyrics_id>57485771</lyrics_id>
<genre>18</genre>
</audio>
<audio>
<aid>253663595</aid>
<artist>Example1</artist>
<duration>400</duration>
<lyrics_id>57485772</lyrics_id>
<genre>20</genre>
</audio>
</response>
Source code
XmlDocument allAudio = new XmlDocument();
allAudio.Load(#"e:\Audio.xml");
StreamWriter write_text = File.CreateText(#"e:\Audio.txt");
XmlNodeList audioNodes = allAudio.GetElementsByTagName("audio");
foreach (XmlNode audioNode in audioNodes)
{
XmlNode artistNode = audioNode["artist"];
write_text.WriteLine(String.Format("{0}", artistNode.Value));
}
write_text.Close();
Hi, I can't parse xml. I want write some node values in file, but as result I get an empty txt file.
You want: artistNode.InnerText
Not: artistNode.value

C# remove attribute from root node

I tries to parse a XML file (get it from Dependacy Graph in VS 2012).
Here is sample of my .xml file
<?xml version="1.0" encoding="utf-8"?>
<DirectedGraph xmlns="http://schemas.microsoft.com/vs/2009/dgml">
<Nodes>
<Node Id="#101" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h" Label="unknwnbase.h" />
<Node Id="#103" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h" Label="wtypesbase.h" />
in here, I needs to remove attribute "xmlns" from DirectedGraph.
here's my source to remove this
XmlNodeList rootNode = xmlDoc.GetElementsByTagName("DirectedGraph");
foreach (XmlNode node in rootNode)
{
node.Attributes.RemoveNamedItem("xmlns");
}
but this code doesn't work. If I don't delete this I can't select node like
XmlNodeList nodes = xmlDoc.DocumentElement.SelectNodes("/DirectedGraph/Nodes/Node");
What should I do?
If you like you can work with the namespace instead of removing the declaration:
var xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<DirectedGraph xmlns=""http://schemas.microsoft.com/vs/2009/dgml"">
<Nodes>
<Node Id=""#101"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h"" Label=""unknwnbase.h"" />
<Node Id=""#103"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h"" Label=""wtypesbase.h"" />
</Nodes>
</DirectedGraph>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("d", "http://schemas.microsoft.com/vs/2009/dgml");
var nodes = doc.DocumentElement.SelectNodes("/d:DirectedGraph/d:Nodes/d:Node", manager);
Console.WriteLine(nodes.Count);
Use:
private static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (XAttribute attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
Taken from: How to remove all namespaces from XML with C#?.
You might also want to check out: XmlSerializer: remove unnecessary xsi and xsd namespaces.

How to modify an external xml file and save it locally in C#

I'm new to C# and want to manipulate a external xml file. Here is that file:
<results>
<root />
<category id="" title="" />
<category />
<category />
</results>
I want this to be modified something like:
<results>
<root />
<categories>
<category id="" title=""/>
<category />
<category />
</categories>
</results>
This works, it replaces all of the elements named category found directly under the root element (root element is results) and adds new element named categories. category elements are then added to categories and category elements are removed from under the results element. In the end categories element is added. You can also save the document by calling it's Save method:
XDocument doc = XDocument.Load("Data.xml");
var categoriesElement = new XElement("categories");
var categoryElements = doc.Root.Elements("category");
foreach(var el in categoryElements.ToList())
{
categoriesElement.Add(new XElement(el));
el.Remove();
}
doc.Element("results").Add(categoriesElement);
//doc.Save(<filepath>);
XElement elem = XElement.Parse(xml);
elem = new XElement("results",
new XElement("root", elem.Element("root").Value),
new XElement("categories", elem.Descendants("category"))
);
Ideally the xml can be transformed using xslt. Basics on xslt transforation can be found below,
http://support.microsoft.com/kb/307322
http://www.w3schools.com/xsl/
Using xslt makes you solution or code more managable. Hope this helps

How does one read an XML file which has children with the same name as their ancestors?

I have trouble reading the below XML file on C# Visual web dev 2010.
As you can see Category can be a name of child as well as a parent.
When I try xmldataset.ReadXml it will come up with an error which says table Category can not be a child of itself.
Is there any other way to read this kind of XML.
A quick sample guide will be much appreciated.
<Categories>
<Category id="10000000">
<name>Clothing</name>
<Children>
<Category id="10010000">
<name>Handbags & Luggage</name>
<Children>
<Category id="10010800">
<name>Travel Accessories</name>
</Category>
</Children>
</Category>
</Children>
</Category>
</Categories>
I think xpath will give you what you want.
XmlNodeList nodes = myXmlDoc.SelectNodes("//name");
The "//" should return all <name> nodes where ever they are in the xml document.
You can then do what ever you want with the list of <name> nodes. For example
foreach (XmlNode node in nodes)
{
console.WriteLine(node.InnerText);
}
For those who want to know,
I sorted it out with this:
XmlTextReader xr = new XmlTextReader("test.xml");
int i=0;
string[] ss;
while (xr.Read())
{
Console.Write(xr.Name);
if (xr.Name.ToString() == "name") { ss[i] = xr.ReadString(); i++ };
}
If you just want the name fields in an array, then try the following code. There might be minor syntax errors!
XmlDocument xd;
XmlNodeList xnl;
int i;
string[] s;
xd = new XmlDocument();
xd.Load(xmlFileName);
xnl = xd.SelectNodes("//Category/name");
i = 0;
s = new string[xnl.Count];
foreach(XmlNode xn in xnl)
{
// xn will be an object of type XmlElement,
// which exposes the value of the text it contains through the InnerText property
s[i++] = xn.InnerText;
}
// an array of strings named 's' is available at this point.
// NB: I have omitted all manner of error checking here for clarity of code.
Update: I had not read your sample XML properly. I had been specifying the wrong XML path. I was specifying the path to read <Category name="Blah">...</Category> whereas your sample has <Category><name>Blah></name>...</Category>. Apologies.
Please see my comment regarding your own solution as well, though to be fair, using XmlReader is going to be a lot faster than using XmlDocument.
Using LINQ To XML the following code
XDocument xmlDoc = XDocument.Load(new StringReader(#"<Categories>
<Category id='10000000'>
<name>Clothing</name>
<Children>
<Category id='10010000'>
<name>Handbags & Luggage</name>
<Children>
<Category id='10010800'>
<name>Travel Accessories</name>
</Category>
</Children>
</Category>
</Children>
</Category>
</Categories>
"));
var names = xmlDoc.Root.Descendants("name")
.Select(n => n.Value).ToList();
names.ForEach(n => Console.WriteLine(n));
outputs
Clothing
Handbags & Luggage
Travel Accessories
This was tested with LINQPad.

How do I modify node value while iterating with XPathNodeIterator?

I'm navigating XML document with XPathNodeIterator, and I want to change some nodes' values.
I can't figure out how :(
Here's the code I'm using:
XPathDocument docNav = new XPathDocument(path);
XPathNavigator nav = docNav.CreateNavigator();
nav.MoveToRoot();
XPathNodeIterator itemsIterator = nav.Select("/foo/bar/item");
while (mediumsIterator.MoveNext())
{
XPathNodeIterator subitemsIterator = itemsIterator.Current.Select("SubitemsList/name");
while (subitemsIterator.MoveNext())
{
XPathNodeIterator nodesIterator = itemsIterator.Current.Select("Param");
nodesIterator.MoveNext();
String the_params = nodesIterator.Current.Value;
// check if I need to modify nodesIterator.Current.Value
// ...
// ok I do - how?
}
}
And the XML file sample:
<?xml version="1.0" encoding="utf-8"?>
<foo>
<bar>
<item>
<Param />
<SubitemsList>
<name>name one</name>
<name>name two</name>
...
</SubitemsList>
</item>
...
</bar>
</foo>
Or maybe there's a better way to do this?
I found a way:
Replace XPathDocument with XmlDocument
When I get to the needed node
...
XmlNode node = ((IHasXmlNode)nodesIterator.Current).GetNode();
node.InnerText = "new text";

Categories

Resources