Remove an XML element based on child index - c#

I found this question:
How to remove an xml element from file?
Which seems to work fine if you know some info within the element you want to delete.
But I have a OnItemDeleting function in ASP.NET where I only have (I think) the Selected Index of the item in a ListView.
In my C# file I have defined two alternatives (A and B) as you can see, it looks like this:
System.Diagnostics.Debug.WriteLine("IN ON ITEM DELETING.");
ListView1.SelectedIndex = e.ItemIndex;
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(path);
XmlNodeList nodes = xmldoc.GetElementsByTagName("EmployeeInformation");
for (int i = 0; i < nodes.Count; i++)
{
if (i == ListView1.SelectedIndex)
{
nodes[i].RemoveChild(nodes[i]); // Alt. A
xmldoc.RemoveChild(nodes[i]); // Alt. B
break;
}
}
xmldoc.Save(path);
BindDatalist();
If I try something like A, I dont know how to replace the nodes in the XmlDocument with the nodes in the XmlNodeList, and if I do like B it just doesn't work and also its weird.
The XML file looks like this:
<EmployeeInformation>
<Details>
<Name>Goofy</Name>
<Emp_id>Goooof</Emp_id>
<Qualification>BBA</Qualification>
</Details>
<Details>
<Name>Donald</Name>
<Emp_id>Duck</Emp_id>
<Qualification>MTech</Qualification>
</Details>
<Details>
<Name>Donald</Name>
<Emp_id>Trump</Emp_id>
<Qualification>MCA</Qualification>
</Details>
</EmployeeInformation>
So lets say I want to remove the Donald Trump item by clicking a button next to it. The selectedIndex would be 2.

In your case looping XmlNodeList not required.
try this
XmlDocument doc = new XmlDocument();
doc.Load(path);
if (ListView1.SelectedIndex < doc.DocumentElement.ChildNodes.Count)
{
doc.DocumentElement.RemoveChild(doc.DocumentElement.ChildNodes[ListView1.SelectedIndex]);
doc.Save(path);
}

Specifying that the node to be deleted from the XlmNodeList is a parent node solved the problem:
ListView1.SelectedIndex = e.ItemIndex;
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(path);
XmlNodeList nodes = xmldoc.GetElementsByTagName("Details");
for (int i = 0; i < nodes.Count; i++)
{
if (i == e.ItemIndex)
{
nodes[i].ParentNode.RemoveChild(nodes[i]);
break;
}
}
xmldoc.Save(path);
BindDatalist();

Related

Cannot remove empty XML node using XPath expression #"//*[not(node())]"

I have the following node in my xml file :
<PERSON>
<LEOKA_DATA> </LEOKA_DATA>
</PERSON>
I am not able to remove the LEOKA tag using the following code (snippet):
string file = CommonVariables.MainDir + #"\Schemas\RemoveEmptyTags.xsl";
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(tempFile); //tempfile is the xml file
XmlNodeList emptyElements = xmlDocument.SelectNodes(#"//*[not(node())]");
if (emptyElements != null)
for (int i = emptyElements.Count - 1; i >= 0; i--)
{
var parentNode = emptyElements[i].ParentNode;
if (parentNode != null)
{
if (emptyElements[i].Name != "LINE")
parentNode.RemoveChild(emptyElements[i]);
}
}
}
catch (FileNotFoundException ex)
{ **something here** }
However, the code above works if the node is like below (notice no space between start tag and end tag) :
<LEOKA></LEOKA>
I also tried using the following code but didn't work :
var doc = XDocument.Parse(tempfile);
var emptyElements = from descendant in doc.Descendants()
where string.IsNullOrWhiteSpace(descendant.Value)
select descendant;
emptyElements.Remove();
Any help would be really appreciated. Please let me know if you need more details. Thanks.
I would modify your XPath expression as follows:
XmlNodeList emptyElements = xmlDocument.SelectNodes(#"//*[not(node()[
not(self::text()[normalize-space() = ''])
])]");
In other words, exclude elements that have a child other than an empty text node, where "empty" means having no text value other than whitespace.

How can I append an XML document to an xml node in c# withour the root node?

I have tried this to get(read) the whole xml.
here I'm able to copy the whole xml in xmlDoc, but I don't need the root node...
XmlNode node = ...... //node from targetxml
node.AppendChild(targetxml.ImportNode(xmlDoc.DocumentElement));
I have also tried this, but not working properly not giving me all the elements in the root node
for (int i = 0; i < nodeList.Count; i++)
{
node.AppendChild(xmlDoc.ImportNode(readxml.DocumentElement.FirstChild, true));
readxml.DocumentElement.RemoveChild(readxml.DocumentElement.FirstChild);
}
How can I trim the root node???
it some what like this
//before appending
<tests program="XXX">//root node
//some data
</tests>
//after appending
<tests program="XXX">//root node
//some data
<tests program="XXX">//don't need this(tests) node but require all the child node
//other data (all this data is required)
</tests>
</tests>
how can i remove the inner test node
right now i m doing like this
XmlNodeList nodeList = readxml.SelectNodes("/tests/*");
for (int i = 0; i < nodeList.Count; i++)
{
node.AppendChild(xmlDoc.ImportNode(readxml.DocumentElement.FirstChild, true));
readxml.DocumentElement.RemoveChild(readxml.DocumentElement.FirstChild);
}
but any alternate way???

How to reverse the contents of an Xml file?

I have an xml file and what I want to do is reverse its elements. I mean the first element should be last and last should be first. I want all the elements to reverse.
Ex. This should be
<Elements>
<Element1>
<Element2>
<Element3>
<Element4>
</ Elements>
This
<Elements>
<Element4>
<Element3>
<Element2>
<Element1>
</ Elements>
Can anyone help me achieve this?
Push them on a stack an then pop them off to rebuild it in reverse order. Do this recursively for every set of nested elements in the document.
Read them in and call .Reverse();
Alternatively use an .OrderByDescending()
Ok. Guys I've created a solution for reverse.
XmlDocument xd = new XmlDocument();
using (write = XmlWriter.Create(path2))
{
write.WriteStartDocument();
write.WriteStartElement("Customers");
write.WriteEndElement();
write.WriteEndDocument();
}
xd.Load(path2);
for (int i = count - 1; i >= 0; i--)
{
XmlNode node = xdoc.ChildNodes[1].ChildNodes[i];
//XComment com = new XComment("-------Reversed-------");
XmlNode xnode = xd.CreateNode(XmlNodeType.Element, "Customer", null);
XmlNode nodeId = xd.CreateElement("Id");
nodeId.InnerText = node.ChildNodes[0].InnerText;
XmlNode nodeName = xd.CreateElement("Name");
nodeName.InnerText = node.ChildNodes[1].InnerText;
XmlNode nodeAge = xd.CreateElement("Age");
nodeAge.InnerText = node.ChildNodes[2].InnerText;
xnode.AppendChild(nodeId);
xnode.AppendChild(nodeName);
xnode.AppendChild(nodeAge);
xd.DocumentElement.AppendChild(xnode);
xd.Save(path2);
}
The above code first loads the contents of the file whose elements have to be reversed. Then it creates a new file and stores the elements in that file in reverse order.
Hopefully this will help someone.

Discovering XML Childnodes in C#

I need to take in XML with common parent nodes but with varying child nodes. Once I get it, I need to grab the tag names of the child nodes and use those names as headers. In the following example, all incoming XML will be wrapped as follows:
<customers>
<customer>
...varying child nodes that do not have child nodes themselves
</customer>
</customers>
I have found that this works:
List<string> headerList = new List<string>();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(someXML);
XmlNodeList xnl = xmlDoc.SelectNodes("customers/customer");
foreach (XmlNode xn in xnl)
{
for (int x = 0; x < xn.ChildNodes.Count; x++)
{
headerList.Add(xn.ChildNodes[x].Name.ToString());
}
}
Is there a better way to do this?
Thanks in advance.
This should do the trick;
XDocument doc = XDocument.Load(someXML);
var headerList = doc.Descendants("customer").Elements().Select(x => x.Name);
Not necessarily "better", but it's a bit more concise I guess.

XMLReader reading XML file based on attribute value

I am trying to read the following file, I can read the attributes, but I can't go into the specific element (Address in this case) and read its elements based on the attribute of that (Address) element. Shortly I need to distinguish between work and home addresses. I need to do this with XMLReader class. Can you help?
<Address Label="Work">
<Name>Name1</Name>
<Street>PO 1</Street>
<City>City1</City>
<State>State 1</State>
</Address>
<Address Label="Home">
<Name>Name2</Name>
<Street>PO 2</Street>
<City>City2</City>
<State>State 2</State>
</Address>"
Okay, here are some notes to think about. XMLReader in the sense i understand you use it (with no code example) is that you iterate over the document, since the XMLReader is forward-only, and read-only.
Because of this you need to iterate until you find the node you need. In the example below i find the address element labeled "work" and extract that entire node. Then query on this node as you want.
using (var inFile = new FileStream(path, FileMode.Open))
{
using (var reader = new XmlTextReader(inFile))
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Address" && reader.GetAttribute(0) == "Work")
{
// Create a document, which will contain the address element as the root
var doc = new XmlDocument();
// Create a reader, which only will read the substree <Address> ... until ... </Address>
doc.Load(reader.ReadSubtree());
// Use XPath to query the nodes, here the "Name" node
var name = doc.SelectSingleNode("//Address/Name");
// Print node name and the inner text of the node
Console.WriteLine("Node: {0}, Inner text: {1}", name.Name, name.InnerText);
}
break;
}
}
}
}
Edit
Made an example that not uses LINQ
XML:
<Countries>
<Country name ="ANDORRA">
<state>Andorra (general)</state>
<state>Andorra</state>
</Country>
<Country name ="United Arab Emirates">
<state>Abu Z¸aby</state>
<state>Umm al Qaywayn</state>
</Country>
Java:
public void datass(string file)
{
string file = HttpContext.Current.Server.MapPath("~/App_Data/CS.xml");
XmlDocument doc = new XmlDocument();
if (System.IO.File.Exists(file))
{
//Load the XML File
doc.Load(file);
}
//Get the root element
XmlElement root = doc.DocumentElement;
XmlNodeList subroot = root.SelectNodes("Country");
for (int i = 0; i < subroot.Count; i++)
{
XmlNode elem = subroot.Item(i);
string attrVal = elem.Attributes["name"].Value;
Response.Write(attrVal);
XmlNodeList sub = elem.SelectNodes("state");
for (int j = 0; j < sub.Count; j++)
{
XmlNode elem1 = sub.Item(j);
Response.Write(elem1.InnerText);
}
}
}
Using XPath you can easily write concise expressions to navigate an XML document.
You would do something like
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(myXMLString);
XmlNode homeAddress = xDoc.SelectSingleNode("//Address[#Label='Work']");
Then do whatever you want with homeAddress.
Read more here on w3schools on XPath.

Categories