insert node in xml file - c#

i have a xml file that looks like the following, and i need to edit it in c# to insert a new node:
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
</User>
<User>
<Name>David Chris</Name>
<test>
<Date>01.02.2009</Date>
<points>25</points>
</test>
<test>
<Date>14.01.2010</Date>
<points>231</points>
</test>
</User>
i need to insert another "in this example a third" Element to the user called "John Smith" with all the sub elements..
so the xml will become :
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
<test>
<Date>30.10.2011</Date>
<points>21</points>
</test></b>
</User>
<User>
<Name>David Chris</Name>
<test>
<Date>01.02.2009</Date>
<points>25</points>
</test>
<test>
<Date>14.01.2010</Date>
<points>231</points>
</test>
</User>
any help is really appreciated ..
thanks a lot ..

Simple (assuming you're using .NET 3.5 or higher):
Load the document (e.g. using XDocument.Load)
Add the relevant element (create a new XElement, find the insertion point, call insertionPoint.Add(newElement))
Save the document (XDocument.Save)
LINQ to XML makes almost all XML-based tasks simpler than older APIs... if the above isn't a good enough start, I'd strongly recommend reading a tutorial on LINQ to XML.
There's no simple way of inserting the new element without reading the old file totally, manipulating it and then writing it out totally. In theory you could do it in a streaming fashion with XmlReader and XmlWriter, but they're almost always more trouble than they're worth.

class Program
{
static void Main()
{
var doc = XDocument.Load("test.xml");
var johnSmith = doc
.Descendants("User")
.Descendants("Name")
.Where(x => x.Value == "John Smith")
.Select(x => x.Parent)
.First();
johnSmith.Add(
new XElement("test",
new XElement("Date", "30.10.2011"),
new XElement("points", "21")
)
);
doc.Save("new.xml");
}
}

For .NET Framework 3.5 and higher: XDocument
For .NET Framework 1.1 and higher: XmlDocument

Here you go:
class Program
{
static void Main(string[] args)
{
XElement main = XElement.Load(#"users.xml");
// write new data to new file
string newDate = "01.01.2012";
string newPoints = "42";
main.Descendants("User")
.Descendants("Name")
.Where(e => e.Value == "John Smith")
.Select(e => e.Parent)
.First()
.Add(new XElement("test",
new XElement("date", newDate),
new XElement("points", newPoints)
)
);
main.Save("users2.xml");
}
}

Related

c#: Add element to second nesting in xml

I have a XML which looks like:
<users>
<user id="0">
<name>John</name>
<lastName>Smith</lastName>
<bills>
<bill id="0">
<name>Water</name>
<forMonth>2013-12-01</forMonth>
<money>235</money>
<lastDayToPay>2014-01-02</lastDayToPay>
<payed>False</payed>
</bill>
<bill id="1">
<name>Telephone</name>
<forMonth>2013-11-01</forMonth>
<money>690</money>
<lastDayToPay>2014-01-01</lastDayToPay>
<payed>True</payed>
</bill>
</bills>
</user>
How can i add new bill for the user, i have problem accessing "bills" node and adding element to it. I'm using c#.
use following code
XmlDocument myDocument = new XmlDocument();
myDocument.Load(XMLFile);
XmlNode newNode = myDocument.CreateElement("bill");
//add values;
var requiredNode = myDocument.ChildNodes.OfType<XmlElement>().Where(o => o.Name == "bills").First();
requiredNode.AppendChild(newNode);
myDocument.Save(XMLFile);

C# Parsing specific xml

I wonder how do I parse a specific person by the id in the xml below?
Also lets say I wanna loop through them all and add them to a listview, How do I do that with XmlDocument?
<users>
<user id="Marcus">
<website>www.google.com</website>
<type>1</type>
</user>
<user id="John">
<website>www.youtube.com</website>
<type>1</type>
</user>
<user id="Josh">
<website>www.google.com</website>
<type>2</type>
</user>
</users>
Here's a linq to xml example -
using System.Xml.Linq;
var doc = XDocument.Parse(#"...");
var element = doc.XPathSelectElement("/users/user[#id='John']");
var website = element.XPathSelectElement("website").Value;
var type = int.Parse(element.XPathSelectElement("type").Value);

read xml file using linq

i have the following xml file
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
</User>
</Users>
and i would like to use linq to extract the dates and the points of the tests where username is "John Smith"..
how would i build my linq ?
i have done the following, but is not working as i wish :
XElement main = XElement.Load(#"users.xml");
string t = "John Smith";
var v = from user in main.Elements("User")
where t == users.Element("Name").Value
select users;
MessageBox.Show(v.First().Element("Date").Value.ToString());
I'm not sure what format you want the output to be, but this samples code should get the date and points. This projects the results into an anonymous type:
class Program
{
static void Main(string[] args)
{
XElement main = XElement.Load(#"users.xml");
var results = main.Descendants("User")
.Descendants("Name")
.Where(e => e.Value == "John Smith")
.Select(e => e.Parent)
.Descendants("test")
.Select(e => new { date = e.Descendants("Date").FirstOrDefault().Value, points = e.Descendants("points").FirstOrDefault().Value });
foreach (var result in results)
Console.WriteLine("{0}, {1}", result.date, result.points);
Console.ReadLine();
}
}
And the output is:
23.05.2011, 33
22.06.2011, 29
Try this out
class Program
{
static void Main(string[] args)
{
XElement main = XElement.Parse(
#"<Users>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
</User>
</Users>");
var users =
from m in main.Elements("User")
where (string)m.Element("Name") == "John Smith"
select (m.Descendants("test").Descendants("Date").FirstOrDefault().Value);
foreach (var user in users)
Console.WriteLine(user);
Console.ReadLine();
}
}
Regards
XDocument main = XDocument.Load(#"users.xml");
string t = "John Smith";
var v = from user in main.Descendants("User")
where t == user.Element("Name").Value
select user;
MessageBox.Show(v.First().Element("Date").Value.ToString());
should do the trick.
And about your other question to add another node to John Smith, this would be the solution:
class Program
{
static void Main(string[] args)
{
XElement main = XElement.Parse(
#"<Users>
<User>
<Name>Alex</Name>
<test>
<Date>08.05.2011</Date>
<points>4</points>
</test>
</User>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
</User>
</Users>");
var users =
from m in main.Elements("User")
where (string)m.Element("Name") == "John Smith"
select (m.Descendants("test").Descendants("Date").FirstOrDefault().Value);
XElement Mercury = main.Elements("User").Where(p => (String)p.Element("Name") == "John Smith").FirstOrDefault();
Mercury.Add(new XElement("test", new XElement("Date", "06.06.2011"), new XElement("points", "01")));
foreach (var user in main.Elements())
Console.WriteLine(user);
Console.ReadLine();
}
}
Giving the next expected result:
<User>
<Name>Alex</Name>
<test>
<Date>08.05.2011</Date>
<points>4</points>
</test>
</User>
<User>
<Name>John Smith</Name>
<test>
<Date>23.05.2011</Date>
<points>33</points>
</test>
<test>
<Date>22.06.2011</Date>
<points>29</points>
</test>
<test>
<Date>06.06.2011</Date>
<points>01</points>
</test>
</User>

XML string to XML document

I have a whole XML document in a String which i need to convert to a XML document and parse tags in the document
This code sample is taken from csharp-examples.net, written by Jan Slama:
To find nodes in an XML file you can use XPath expressions. Method XmlNode.Selec­tNodes returns a list of nodes selected by the XPath string. Method XmlNode.Selec­tSingleNode finds the first node that matches the XPath string.
XML:
<Names>
<Name>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Name>
<Name>
<FirstName>James</FirstName>
<LastName>White</LastName>
</Name>
</Names>
CODE:
XmlDocument xml = new XmlDocument();
xml.LoadXml(myXmlString); // suppose that myXmlString contains "<Names>...</Names>"
XmlNodeList xnList = xml.SelectNodes("/Names/Name");
foreach (XmlNode xn in xnList)
{
string firstName = xn["FirstName"].InnerText;
string lastName = xn["LastName"].InnerText;
Console.WriteLine("Name: {0} {1}", firstName, lastName);
}
Using Linq to xml
Add a reference to System.Xml.Linq
and use
XDocument.Parse(string xmlString)
Edit: Sample follows, xml data (TestConfig.xml)..
<?xml version="1.0"?>
<Tests>
<Test TestId="0001" TestType="CMD">
<Name>Convert number to string</Name>
<CommandLine>Examp1.EXE</CommandLine>
<Input>1</Input>
<Output>One</Output>
</Test>
<Test TestId="0002" TestType="CMD">
<Name>Find succeeding characters</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>abc</Input>
<Output>def</Output>
</Test>
<Test TestId="0003" TestType="GUI">
<Name>Convert multiple numbers to strings</Name>
<CommandLine>Examp2.EXE /Verbose</CommandLine>
<Input>123</Input>
<Output>One Two Three</Output>
</Test>
<Test TestId="0004" TestType="GUI">
<Name>Find correlated key</Name>
<CommandLine>Examp3.EXE</CommandLine>
<Input>a1</Input>
<Output>b1</Output>
</Test>
<Test TestId="0005" TestType="GUI">
<Name>Count characters</Name>
<CommandLine>FinalExamp.EXE</CommandLine>
<Input>This is a test</Input>
<Output>14</Output>
</Test>
<Test TestId="0006" TestType="GUI">
<Name>Another Test</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>Test Input</Input>
<Output>10</Output>
</Test>
</Tests>
C# usage...
XElement root = XElement.Load("TestConfig.xml");
IEnumerable<XElement> tests =
from el in root.Elements("Test")
where (string)el.Element("CommandLine") == "Examp2.EXE"
select el;
foreach (XElement el in tests)
Console.WriteLine((string)el.Attribute("TestId"));
This code produces the following output:
0002
0006
Depending on what document type you want you can use XmlDocument.LoadXml or XDocument.Load.
Try this code:
var myXmlDocument = new XmlDocument();
myXmlDocument.LoadXml(theString);

Deleting whole sections of my XML file

I have a userlist for a program I'm designing, and all the users are stored to an XML file, like so:
<?xml version="1.0"?>
<Users>
<User ID="1">
<nickname>Tom</nickname>
<password>Sams</password>
<host>ahost#asd.com</host>
<email>badrandom#as.com</email>
<isloggedin>true</isloggedin>
<permission>10</permission>
</User>
<User ID="2">
<nickname>ohai</nickname>
<password>asdalkdj9u</password>
<host>meh#meh.com</host>
<email>my#email</email>
<isloggedin>false</isloggedin>
<permission>1</permission>
</User>
<User ID="3">
<nickname>ohai</nickname>
<password>sercret</password>
<host>my#host</host>
<email>my#email</email>
<isloggedin>false</isloggedin>
<permission>1</permission>
</User>
<User ID="4">
<nickname>mib_hr6qhr</nickname>
<password>YXNsa2RhZGxrYXNk</password>
<host>adb7e51b#webchat.mibbit.com</host>
<email>alskd#alskd.com</email>
<isloggedin>true</isloggedin>
<permission>1</permission>
</User>
</Users>
Now, based on the users ID number, I need to be able to delete all reference to that user.
So say, I have ID number 3, how can I completely delete userid number 3's existence from the xml file?
I'm looking for code examples, but any help would be greatly appreciated!
One approach using the XML DOM (.NET 1.x and up) would be to just load the file, find user no. 3, and remove that node, and save the file back:
XmlDocument doc = new XmlDocument();
doc.Load("yourXmlFile.xml");
XmlNode userNo3 = doc.SelectSingleNode("//Users/User[#ID='3']");
if(userNo3 != null)
{
userNo3.ParentNode.RemoveChild(userNo3);
}
doc.Save("YourNewXmlFile.xml");
Marc
Assuming you have the XML loaded in an XDocument:
using System.Linq;
using System.Xml.Linq;
void Delete()
{
XDocument document = LoadXML();
document.Elements("Users")
.Single(e => e.Attribute("ID").Value == "3")
.Remove();
}
Of course, this assumes that the user you request will always be present in the XML. To be safe, you should use SingelOrDefault() and check for a null value before deleting.
The problem with linq and DOM approach is that there is a round-trip (parsing/serialization) which can be efficient, vtd-xml has something called incremental update, here is an article that explains it... http://www.codeproject.com/KB/XML/xml_processing_future.aspx
VTDGen vg = new VTDGen();
if (vg.parseFile("your.xml", false)){
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/users/user[#ID='3']");
XMLModifier xm = new XMLModifier(vn);
if (ap.evalXPath()!=-1){
xm.remove();
xm.output("new.xml");
}
}

Categories