I need to delete specific employee node and also its child node based on the value of id.
For example, here I need to delete employee tag with id="2".
<company>
<employee>
<id>1</id>
<name>sa</name>
</employee>
<employee>
<id>2</id>
<name>ssa</name>
</employee>
</company>
Assuming you have loaded that into an XmlDocument named doc:
XmlElement el = (XmlElement)doc.SelectSingleNode("/company/employee[id=2]");
if(el != null) { el.ParentNode.RemoveChild(el); }
Try this one
XmlDocument xmlDoc = new XmlDocument();
XmlNode nodeToDelete = xmlDoc.SelectSingleNode("/root/XMLFileName[#ID="+nodeId+"]");
if (nodeToDelete != null)
{
nodeToDelete.ParentNode.RemoveChild(nodeToDelete);
}
xmlDoc.Save("XMLFileName.xml")
Related
I have the following problem, I want to select the book with the author "Johnny Dapp33", which unfortunately does not work.
XML Code:
<employees xmlns:bar="http://www.bar.org">
<employee id="Test1">
<name>Johnny Dapp</name>
<author>Al Pacino</author>
</employee>
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
</employees>
I would have tried it via ".SelectSingleNode", unfortunately I always fail with the XPath.
Thank you for your help!
Let's say we have a file called Employees.xml in our project directory.
We can load the xml file in our memory by using this assignment:
XmlDocument doc = new XmlDocument();
doc.Load("Employees.xml");
Second we try to find a single node (presuambly) by its id in a structure employees/employee (this is our path), no we have to add the search param (id in this case) like this:
XmlNode singleNode = doc.SelectSingleNode("/employees/employee[#id='Test1']");
Console.WriteLine(singleNode.OuterXml);
However if we only know the name we are looking for we can also search for that specific value like this. We search in the employee node for the node value of name with the value of Johnny Dapp33:
XmlNode singleNode = doc.SelectSingleNode("descendant::employee[name='Johnny Dapp33']");
Console.WriteLine(singleNode.OuterXml);
While dealing with XMl, it is better to use LINQ to XML API.
It is available in the .Net Framework since 2007.
c#
void Main()
{
const string filePath = #"e:\Temp\WizardZZ.xml";
XDocument xdoc = XDocument.Load(filePath);
var employee = xdoc.Descendants("employee")
.Where(d => d.Elements("name").FirstOrDefault().Value.Equals("Johnny Dapp33"));
Console.WriteLine(employee);
}
Output
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
If you need to use XPath (and there must be a very strong reason for it), you can use it with XElement:
var xml = """
<employees xmlns:bar="http://www.bar.org">
<employee id="Test1">
<name>Johnny Dapp</name>
<author>Al Pacino</author>
</employee>
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
</employees>
""";
var x = XElement.Parse(xml);
var employees = x.XPathSelectElements("/employee[name='Johnny Dapp33']");
if (employees is not null)
{
foreach (var employee in employees)
{
WriteLine((string)employee.Element("name") ?? "[name] not found");
}
}
else
{
WriteLine("did not find any employees");
}
I need to add a new element "Location" to every parent node "Emp" after the element "ID".
<Record>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
<Emp>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
</Record>
I followed example and the steps in below answer by Erik Philips
Add an XML node to multiple parent nodes(which have same name)
XmlNodeList xNodeList = doc.SelectNodes("/Record/Emp");
foreach (XmlNode item in xNodeList)
{
XmlElement xNewChild = doc.CreateElement("Location");
xNewChild.InnerText = "USA";
item.AppendChild(xNewChild);
}
doc.Save(path);
Instead of this
item.AppendChild(xNewChild);
i added new statement
item.InsertAfter(xNewChild, doc.SelectSingleNode("Emp//ID"));
This inserts the new element right after Emp node starts and not after ID.
<Record>
<Emp>
<Location>USA</Location>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
<Emp>
<Location>USA</Location>
<ID>12</ID>
<Name>ABC</Name>
</Emp>
</Record>
Can anyone suggest me where am i going wrong?
XmlDocument is an old API and has been superceded by XDocument, which provides a somewhat more pleasurable experience when dealing with XML.
Using XDocument you can:
var doc = XDocument.Parse(xmlString); //acquire your XDocument (perhaps by other means)
var targetElements = doc.XPathSelectElements("//Record/Emp/ID");
foreach (var element in targetElements)
{
var locationElement = new XElement("Location");
locationElement.Add("USA");
element.AddAfterSelf(locationElement);
}
I am new to C# and XML and I need help with following code, I have created an Element thru C# code and wanted to insert City Element in a XML file at two places and coded the following code. But C# code inserts Element only in 4th node not in 1st node, I am not able to figure it out what am I missing.Any help will be appreciated. It is working fine if I keep only one INSERTAFTER.
XmlElement childElement = doc.CreateElement("City"); // Creation of <City> ....... <City>
childElement.InnerText = "Hyderabad";// Adding Value <City> Hyderabad </City>
XmlNode SelectNode = doc.SelectSingleNode("Group/user"); //where to add XPATH expression
SelectNode.InsertAfter(childElement, SelectNode.LastChild);//selects 1st "user" node lastchild and insert after
XmlNode refNode = doc.SelectSingleNode("Group/user[4]");// Indicating 4 Node in XML file
refNode.InsertAfter(childElement, refNode.LastChild); //selects 4th "user" node lastchild and insert after
XML file:
<?xml version="1.0" encoding="utf-8"?>
<Group>
<user>
<Name age="39">John Hay</Name>
<RollNo>01</RollNo>
=== <City>Hyderabad</City> ===> is missing
</user>
<user>
<Name age="11">Ramsey</Name>
<RollNo>02 </RollNo>
</user>
<user>
<Name age="16">Roshan</Name>
<RollNo>03</RollNo>
</user>
<user>
<Name age="42">Rahiman</Name>
<RollNo>04</RollNo>
<City>Hyderabad</City> ==> This is fine.
</user>
</Group>
Can I reference any ELEMENT (Ex. RollNo) based on its Text.value and insert one more element ?
Thanks
You are moving the same instance of your city-node around your xml-document. You need to instantiate another one:
XmlElement childElement = doc.CreateElement("City"); // Creation of <City> ....... <City>
childElement.InnerText = "Hyderabad";// Adding Value <City> Hyderabad </City>
XmlNode SelectNode = doc.SelectSingleNode("Group/user"); //where to add XPATH expression
SelectNode.InsertAfter(childElement, SelectNode.LastChild);//selects 1st "user" node lastchild and insert after
childElement = doc.CreateElement("City"); // Creation of <City> ....... <City>
childElement.InnerText = "Hyderabad";// Adding Value <City> Hyderabad </City>
XmlNode refNode = doc.SelectSingleNode("Group/user[4]");// Indicating 4 Node in XML file
refNode.InsertAfter(childElement, refNode.LastChild); //selects 4th "user" node lastchild and insert after
/Edit: Cloning your city-node might be a bit more appropriate.
https://msdn.microsoft.com/de-de/library/system.xml.xmlelement.clonenode(v=vs.110).aspx
XmlElement childElement = doc.CreateElement("City"); // Creation of <City> ....... <City>
childElement.InnerText = "Hyderabad";// Adding Value <City> Hyderabad </City>
XmlNode SelectNode = doc.SelectSingleNode("Group/user"); //where to add XPATH expression
SelectNode.InsertAfter(childElement, SelectNode.LastChild);//selects 1st "user" node lastchild and insert after
XmlNode refNode = doc.SelectSingleNode("Group/user[4]");// Indicating 4 Node in XML file
refNode.InsertAfter(childElement.CloneNode(true), refNode.LastChild); //selects 4th "user" node lastchild and insert after
You can easily access specific nodex using text() in XPath...
Take a look at this example:
//get roll node by it's text
var rollNode = doc.SelectSingleNode("//user/RollNo[text()='03']");
//user to whom roll is child
var parentUserNode = rollNode.ParentNode;
//add some nodex
parentUserNode.InsertAfter(childElement, parentUserNode.LastChild);
This would be much easier using the LINQ to XML API rather than the old XmlDocument API. For example, to do this by order:
var doc = XDocument.Parse(xml);
var hyderabad = new XElement("City", "Hyderabad");
doc.Descendants("user").First().Add(hyderabad);
doc.Descendants("user").Skip(3).First().Add(hyderabad);
Or to select by RollNo:
var doc = XDocument.Parse(xml);
var roll4 = doc.Descendants("user").Single(x => (int) x.Element("RollNo") == 4);
roll4.Add(new XElement("City", "Hyderabad"));
See this fiddle for a demo.
I want to remove parent elements from an XML structure if child is empty.
My XML:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status>single</Status>
</Customer>
<customer>
<Name>Jack</Name>
<Age></Age>
<Status></Status>
</Customer>
</Customers>
Should become:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status>single</Status>
</Customer>
</Customers>
my code :
XmlElement element3 = xmlDocument.CreateElement("Age");
element3.InnerText = str3;
element1.AppendChild((XmlNode)element3);
XmlElement element4 = xmlDocument.CreateElement("Status");
element4.InnerText = str4;
element1.AppendChild((XmlNode)element4);
How can I remove the parent "customer", if age and status child are empty?
You can use XPath syntax along with SelectNodes() method to get specific nodes from XmlDocument easily.
Example to select <Customer> elements having child node <Age> and <Status> empty, then remove those selected elements :
var nodes = xmlDocument.DocumentElement.SelectNodes("//Customer[Age = '' and Status = '']");
foreach (XmlElement node in nodes)
{
node.ParentNode.RemoveChild(node);
}
UPDATE :
It seems that you're the one that construct the XML. So i'd suggest to check if str3 and str4 are empty, and if they are remove corresponding <Customer> element :
if(string.IsNullOrEmpty(str3) && string.IsNullOrEmpty(str4))
{
element1.ParentNode.RemoveChild(element1);
}
I understand that you're creating a new file and adding each element after the validation. I think this should work for you:
XDocument input = XDocument.Load("customers.xml");
XDocument output = new XDocument();
output.Add(new XElement("Customers"));
IEnumerable<XElement> elements = input.Element("Customers").Elements("customer");
foreach (XElement el in elements)
{
string age = el.Element("Age").Value;
string status = el.Element("Status").Value;
if (age != "" || status != "")
{
output.Element("Customers").Add(el);
}
}
output.Save("customers.xml");
So I'm currentlty trying to parse an XML file which looks like so:
<employees>
<employee>
<id>1</id>
<projects>
<projectID>7</projectID>
<projectID>3</projectID>
</projects>
</employee>
<employee>
<id>2</id>
<projects>
<projectID>4</projectID>
</projects>
</employee>
</employees>
I'm trying to read in each employee and any number of projects which appear. The Employee object is a string and list(int).
Currently I have:
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList xmlNodes = doc.DocumentElement.SelectNodes("/employees/employee");
foreach (XmlNode xmlNode in xmlNodes)
{
string id;
List<int> projects = new List<int>();
id = xmlNode.SelectSingleNode("id").InnerText;
//this is the bit. What I have works but it feels like it could
//be majorly refined. Is there a better way to construct the foreach below?
foreach (XmlNode node in xmlNode.ChildNodes.Item(1))
//index 1 is the projects node
{
projects.Add(int.Parse(node.InnerText));
}
//
Employee e = new Employee(id, projects);
e.Add(e);
}
If the XML file itself is an issue it can be changed to accomodate the parsing.
Thank you.
It will be much easier with LINQ to XML:
var xDoc = XDocument.Load(path);
var employees = (from e in xDoc.Root.Elements("employee")
let projects = e.Element("projects")
.Elements("projectID")
.Select(p => (int)p)
.ToList()
let id = (string)e.Element("id")
select new Employee(id, projects)).ToList();
You need using System.Linq and using System.Xml.Linq to make it work.