How to delete specific node by attribute from XML? - c#

I am novice and struggling in some XML operations Like open and Delete. I have done the Add part.
Partys.xml
<?xml version="1.0" encoding="utf-8"?>
<Partys>
<Customers>
<Customer CustomerID="1">
<PersonalName>
<LastName>Baker</LastName>
<FirstName>Eugene</FirstName>
</PersonalName>
<Citizenship>Africa</Citizenship>
</Customer>
<Customer CustomerID="2">
<PersonalName>
<LastName>Baker</LastName>
<FirstName>Eugene</FirstName>
</PersonalName>
<Citizenship>Africa</Citizenship>
</Customer>
</Customers>
</Partys>
Q: I want to open the node detail customer where CustomerID (Attribute) is 1. What is the C# code for this?
Q: I want to delete the node customer where CustomerID (Attribute) is 2. What is the C# code for this?

You could try something like this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Parties.xml");
XmlNode t = xmlDoc.SelectSingleNode("/Partys/Customers/Customer[#CustomerID='2']");
t.ParentNode.RemoveChild(t);
xmlDoc.Save();
Once you have t, you can do whatever you want with it including show it in the Console (by accessing the various properties)
Here, we have deleted the node and saved back to file, but you could do whatever you want with the XmlDocument....

Related

How to add data after xml in c# and read the xml after?

I've got to create a file with xml header and after that i have to put normal data, smthing like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
Data of the file....
I've already got the code to write it to the file.
Code for that part:
private void setHeader(FileStream output, string nod2, string nod3, string )
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
doc.AppendChild(docNode);
XmlNode header = doc.CreateElement("Header");
doc.AppendChild(header);
XmlNode algorithm = doc.CreateElement("Algorithm");
algorithm.InnerText = "alg";
header.AppendChild(algorithm);
XmlNode node2= doc.CreateElement("nod2");
node2.InnerText = nod2;
header.AppendChild(node2);
XmlNode node3= doc.CreateElement("nod3");
node3.InnerText = nod3;
header.AppendChild(node3);
XmlNode node= doc.CreateElement("node");
header.AppendChild(node);
XmlNode user1 = doc.CreateElement("User");
node.AppendChild(user1);
XmlNode mail = doc.CreateElement("Email");
user1.AppendChild(mail);
XmlNode sessionKey = doc.CreateElement("SessionKey");
user1.AppendChild(sessionKey);
doc.Save(output);
}
It work's pretty well, but when i want to read it with
private void readHeader(FileStream input, out string algorithm)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
}
I got an error that when the "Data of the file..." starts: "Data on the root level is invalid".
Is there a way to do it with the data after whole xml, or have i to add the data as a node?
This can be done in multiple ways. In comments, you've indicated that the best way is unacceptable for reasons outside the scope of the discussion. For completeness, I'm going to put that one first anyway. Skip down to tl;dr for what I think you'll have to end up doing.
The preferred way to do this is to base64 encode the encrypted data and put it in a CDATA block:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<File>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
<Data><![CDATA[
ICAgIFhtbE5vZGUgYWxnb3JpdGhtID0gZG9jLkNyZWF0ZUVsZW1lbnQoIkFsZ29yaXRobSIpOw0K
ICAgIGFsZ29yaXRobS5Jbm5lclRleHQgPSAiYWxnIjsNCiAgICBoZWFkZXIuQXBwZW5kQ2hpbGQo
YWxnb3JpdGhtKTsNCiAgICBYbWxOb2RlIG5vZGUyPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMiIp
Ow0KICAgIG5vZGUyLklubmVyVGV4dCA9IG5vZDI7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5v
ZGUyKTsNCiAgICBYbWxOb2RlIG5vZGUzPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMyIpOw0KICAg
IG5vZGUzLklubmVyVGV4dCA9IG5vZDM7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5vZGUzKTs=
]]></Data>
</File>
That's the canonical answer to this question.
But you've told me that in your case, a requirement has been imposed that you can't do it that way.
Second choice is MIME (actually, MIME might be the first choice and the above might be the second). But I have a feeling they won't like MIME either.
Third choice, read the file as a string and search for some marker that's inserted between the XML and the binary data, something like a MIME boundary.
tl;dr
If they won't let you add such a marker to the file (and I bet they won't), search for the first occurrence of the substring "</Header>":
var xml = File.ReadAllText(filePath);
var endTag = "</Header>";
var headerXML = xml.Substring(0, xml.IndexOf(endTag) + endTag.Length);
var xdHeader = new XmlDocument();
xdHeader.LoadXml(headerXML);
I tested your code with writing directly to a file, doc.Save(#"c:\temp\test1.xml");
And loading from that file works fine. So there is nothing wrong with your xml document. Check your FileStream. Do you flush and close it properly? Does it have UTF-8 encoding?
What's the input in the node strings. Nothing that is invalid according to xml rules?
After a single root node, only comments and processor instructions can be written to xml. So, you can try to write your data in the comments.
It will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
...
</Header>
<!-- your data -->
<!-- another data -->
This method has limitations: your data may not contain -- (double-hyphen) and may not end in -.
But it is better, of course, not to do so.

DataContractSerializer and "URL" xml node

I am trying to deserialize a XML file by using DataContractSerializer which containes node called "URL". Like this one:
<?xml version="1.0" encoding="utf-8"?>
<products>
<product ID="8717973147527">
<name>Something</name>
<price currency="EUR">9.00</price>
<URL>http://google.com</URL>
<images>
<image>http://google.com</image>
</images>
</product>
</products>
After deserialization property mapped to URL stays null. If I rename the xml node to "url" (lower case) or any other word it is working fine. The problem is that I am not able to change the XML, so I must find a way to deserialize it. Can anyone help me?
You can use the XmlAttribute to set the name as you expect it on the XML file as:
[Serializable]
public class ClassName
{
// Here set the Xml Name Attribute
[XmlAttribute("URL")]
string Url;
...

C# Open, Edit then Save XML to File

How would I go about editing this XML file:
<?xml version="1.0" encoding="utf-8" ?>
<employees>
<employee id="657434365436543" name="Joe Bloggs" group="Manager" subgroup="Deputy">
<contactDetails>
<homePhone>6535436543</homePhone>
<mobilePhone>654365436543</mobilePhone>
</contactDetails>
<personelFile>
<rightToWork>
<type>Permanent</type>
<expires>Never</expires>
</rightToWork>
<nationalInsurance>6543655543</nationalInsurance>
<startDate>01/09/2009</startDate>
</personelFile>
<holidays>
<entitlements>
<holidays>22</holidays>
<bankHolidays>8</bankHolidays>
<personalDays>1</personalDays>
</entitlements>
<taken>
<holidays>1</holidays>
<bankHolidays>0</bankHolidays>
<personalDays>0</personalDays>
</taken>
<remaining>
<holidays>21</holidays>
<bankHolidays>8</bankHolidays>
<personalDays>1</personalDays>
</remaining>
<booked>
<holidays>22</holidays>
<bankHolidays>8</bankHolidays>
<personalDays>1</personalDays>
</booked>
<remainingtobook>
<holidays>0</holidays>
<bankHolidays>0</bankHolidays>
<personalDays>0</personalDays>
</remainingtobook>
</holidays>
<shifts>
<monday>
<start>0800</start>
<end>1300</end>
</monday>
<tuesday>
<start>0800</start>
<end>1300</end>
</tuesday>
<wednesday>
<start>0800</start>
<end>1300</end>
</wednesday>
<thursday>
<start></start>
<end></end>
</thursday>
<friday>
<start>0800</start>
<end>1300</end>
</friday>
<saturday>
<start>0800</start>
<end>1200</end>
</saturday>
<sunday>
<start></start>
<end></end>
</sunday>
</shifts>
</employee>
</employees>
So far I have the following to select the correct employee from the XML:
XmlTextReader employeesReader = new XmlTextReader("Employees.xml");
var employeesXdoc = XDocument.Load(employeesReader);
var employees = from employee in employeesXdoc.Descendants("employee")
where employee.Attribute("id").Value.ToString() == employeeSelect.Value.ToString()
select new
{
nodes = employee.Nodes()
};
foreach (var employee in employees)
{
// WHAT TO PUT HERE?
}
I'm guessing I've found the right place to insert the editing for the file but then I need to know how to correctly edit it and then save it to the file without losing everything else contained there (otherwise I'd just overwrite the whole file.
Thanks for any help.
A good idea is also to use the xml-serializer-class.
There you can work with usual objects and save it to the xml later :)
http://msdn.microsoft.com/en-us/library/ms733901.aspx
Here is a useful link for updating an XML file without rewriting it in its entirety on each save:
http://support.microsoft.com/kb/301233
the general idea is to use a XMLDocument instead of a XMLTextReader and load your .xml file into the XMLDocument object. then grab the root node and start navigating/querying. once you have found the nodes you wish to edit, make your changes. then when you are done, use XMLDocument.Save(path) to save your chagnes.
IO streams are one way phenoma so you can;t use an reader/writer unless you want to overwrite the existing file.

How to select xml root node when root node has attribute?

I am trying to select all the child nodes of root node of an xml document using XPath query.
My xml file looks something like following :
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<automotive_industry>
<automotive />
<rail_global_services />
</automotive_industry>
</root>
AND
<?xml version="1.0" encoding="UTF-8" ?>
<root xmlns="http://www.my_department.my_company.com/project_name">
<automotive_industry>
<automotive />
<rail_global_services />
</automotive_industry>
</root>
C# Code to select root node is as follows :
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNodeList allNodes = gazetteDocument.SelectNodes("root");
This code works fine, it selects all the child nodes of root node when root node does not have any attribute that is, it works for 1st xml file but does not work for 2nd xml file because 2nd file has xmlns attribute.
Does anyone knows how to select all the child nodes of root node when root node has attributes??
EDIT :
I found one XPath query : /* This query selects root node no matter whether it has any attribute or not. Once root node is selected, I can iterate through its all the child nodes .
Although the namespace in your XML document is fine, you need to use it in your SelectNodes.
Use this code for your second XML:
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(gazetteDocument.NameTable);
nsmgr.AddNamespace("ns", "http://www.my_department.my_company.com/project_name");
XmlNodeList allNodes = gazetteDocument.SelectNodes("ns:root", nsmgr);
The better way would be to use XDocument and corresponding classes. They are a lot easier to work with.
I don't know the old xml methods of C#, but you could always open the file to read as normal text, and then read to the first node and parse it however you like.
You can use GetElementsByTagName method below are the snippet of my code
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNodeList allNodes = gazetteDocument.GetElementsByTagName("root");

XML field replacement in C#

ok, so, i have an xml file that looks like this:
<?xml version="1.0"?>
<Users>
<User ID="1">
<nickname>Tom</nickname>
<password>a password</password>
<host>anemail#hello.com</host>
<email>anemail</email>
<isloggedin>false</isloggedin>
<permission>10</permission>
</User>
<User ID="2">
<nickname>ohai</nickname>
<password>sercret</password>
<host>my#host</host>
<email>my#email</email>
<isloggedin>false</isloggedin>
<permission>1</permission>
</User>
<Users>
now, first, i will have a return of what their ID number is, so, ill have "2".
from that, i will need to go into, and edit the fields in it, and resave the xml.
so basically what i need, is to open the file, find the info for User ID="2", and resave the xml, with DIFFERENT values inside of user 2, without affecting the rest of the document.
examlpe:
<User ID="2">
<nickname>ohai</nickname>
<password>sercret</password>
<host>my#host</host>
<email>my#email</email>
<isloggedin>false</isloggedin>
<permission>1</permission>
</User>
//do the alterations here, and end up with
<User ID="2">
<nickname>ohai</nickname>
<password>somthing that is different than before</password>
<host>the most current host that they were seen as</host>
<email>my#email</email>
<isloggedin>false</isloggedin>
<permission>1</permission>
</User>
etc.
Summary:
i need to open a text file, return the information via ID number, edit the information, re-save the file. without affecting anything other than user 2
~Thanks!
There are multiple ways you could do this - this is with an XmlDocument, which works in .NET 1.x and up, and works fine as long as your XML document isn't too long:
// create new XmlDocument and load file
XmlDocument xdoc = new XmlDocument();
xdoc.Load("YourFileName.xml");
// find a <User> node with attribute ID=2
XmlNode userNo2 = xdoc.SelectSingleNode("//User[#ID='2']");
// if found, begin manipulation
if(userNo2 != null)
{
// find the <password> node for the user
XmlNode password = userNo2.SelectSingleNode("password");
if(password != null)
{
// change contents for <password> node
password.InnerText = "somthing that is different than before";
}
// find the <host> node for the user
XmlNode hostNode = userNo2.SelectSingleNode("host");
if(hostNode != null)
{
// change contents for <host> node
hostNode.InnerText = "the most current host that they were seen as";
}
// save changes to a new file (or the old one - up to you)
xdoc.Save("YourFileNameNew.xml");
}
If you're using .NET 3.5 and up, you could also check into Linq-to-XML for a probably even easier way to manipulate your XML document.
Marc
Check out this question, should have your answer using Linq-to-XML. This involves writing out to a Console window, but the theory is the same.
Linq to XML - update/alter the nodes of an XML Document
You may use XmlDocument for this:
var doc = new XmlDocument();
doc.Load("1.xml");
var node = doc.SelectSingleNode(#"//User[#ID='2']");
node.SelectSingleNode("password").InnerText="terces";
doc.Save("1.xml");

Categories

Resources