XML field replacement in C# - 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");

Related

XmlDocument, preformatted xml: Add new line after XML declaration only

I need to add a line after xml declaration to process a file on an external system that rejects it if missing.
I had formatted the doc by myself on creation and signing it, so I don't want to mess with formatting as corrupts the signature (it has also third-party external signed documents)
.
Yes, I can open it as text, use replace "?><" by "?>\r\n<", save it, or do everything manually, but I want to do it "the XmlDocument" way.
What I have:
<?xml version="1.0" encoding="ISO-8859-1"?><LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
What I need:
<?xml version="1.0" encoding="ISO-8859-1"?>
<LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
Relevant code:
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
var dec = xmlDoc.CreateXmlDeclaration("1.0", Constantes.SaveEncoding.EncodingName,"no");
using (var sw = new StreamWriter(salida, false, Constantes.SaveEncoding))
{
xmlDoc.Save(sw);
}
Note I am not using indentations and PreserveWhitespace has not worked fine for me.
Any suggestions or best way to do it?

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.

Issue with loading xml in C# containing google kml

I am trying to access the second element in this xml (google kml type) of file and the issue I am having is I get returned null values for my code unless I remove out the <kml xmlns="http://earth.google.com/kml/2.0"> and the related close from the source file. Here is the code I'm using. (mind you this works if I remove the specified line so what I'm looking for is a clean way to process this file without editing the supplied source file.)
XmlDocument doc = new XmlDocument();
doc.Load("2014_q2.xml");
XmlNodeList xnlNodes = doc.SelectNodes("/kml/Document/Folder");
var Node2Use = xnlNodes.Item(1);
here is the top of the source file:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<open>1</open>
<Folder>
<name>Pts_2014_q3_point Drawing</name>
<Placemark>
<description>HOLTSVILLE</description>
<name>00501</name>
<Style>
<IconStyle>
<color>ffc0c0c0</color>
I have a break on the var Node2Use = xnlNodes.Item(1); line so I can see the contents and thats where I see that I have a zero value where I should have 2 for Folder (like mentioned I get the 2 when I remove out that kml tagged line.)
You need to include the namespace. Something like this:
XmlDocument doc = new XmlDocument();
doc.Load("2014_q2.xml");
XNamespace ns = "http://earth.google.com/kml/2.0";
XmlNodeList xnlNodes = doc.SelectNodes(ns + "/kml/Document/Folder");

How to delete specific node by attribute from XML?

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....

Select correct and incorrect XML nodes in two separate files

Ok, I have to do the following IN C# ( C Sharp ), I am new to C Sharp programming.
I have got the following ( see below )XML file. It is required from me to select using XPath all coreect nodes in a separate .txt file, and all incorrect nodes as well in a separate .txt file.
The correct nodes need to satisfy the following conditions in XPath:
ResourceCatalog/ Resource
ResourceCatalog / ResourceGroup / Resource
ResourceCatalog ........... ResourceGroup / Resource
This is the original XML file:
<?xml version="1.0" encoding="utf-8"?>
<ResourceCatalog>
<Resource name ="Res1"></Resource>
<Resource>
<Name>Res3</Name>
</Resource>
<Service>
<Resource name ="Res2"></Resource>
<ResourceGroup name="Group2">
<Resource name ="Res4"></Resource>
<Resource>
<Name>Res6</Name>
</Resource>
</ResourceGroup>
</Service>
<ResourceGroup name="Group1">
<ResourceGroup name="Group12">
<Service>
<Resource name ="Res8"></Resource>
</Service>
<Resource name ="Res5"></Resource>
<Resource>
<Name>Res7</Name>
</Resource>
</ResourceGroup>
<Resource name ="Res9"></Resource>
</ResourceGroup>
</ResourceCatalog>
I know this question is old, but i hate to see an SO question i come across go unanswered and since it might benefit someone in the future - you could use an XPath like the following:
//Resource
This will select all nodes in the XML document with the name Resource, which seems to match the criteria outlined in your question. The following is a non-optimal, non-generic approach to solving this problem (since it requires the inverse XPath to be manually generated), but will work:
private static void SortNodes(string xml)
{
const string correctXPath = #"//Resource";
const string incorrectXPath = #"//*[not(contains(name(), 'Resource'))]";
var document = new XmlDocument();
document.LoadXml(xml);
var correctNodes = document.SelectNodes(correctXPath);
var incorrectNodes = document.SelectNodes(incorrectXPath);
foreach (var node in correctNodes)
{
// Put into 'correct' txt file
}
foreach (var node in incorrectNodes)
{
// Put into 'incorrect' txt file
}
}
If your XML file is large you may also be better off using an XmlTextReader, rather than loading the entire document into an XmlDocument structure.
However if i were going to solve this myself, i would use XSLT since all you want to do is transform XML to another text form. Off-hand i don't know the XSLT to use though so you would need to do more research on that. There are plenty of examples online and this is a fairly simple scenario.

Categories

Resources