<?xml version="1.0" standalone="yes"?>
<Subject>
<Book>
<Name>ASP.NET</Name>
<Author>ABC</Author>
<Published>2018</Published>
<Price>$100</Price>
</Book>
</Subject>
Above is the xml file i have. I want to store xml nodes and values using Dictionary or Collections in C# and display those on message box using winforms.
Output should be as:
Name: ASP.NET
Author: ABC
Published: 2018
Price: $100
I have tried the following but getting lots of errors...
var doc = XDocument.Load(#"xmlfile.xml");
var rootNodes = doc.Root.DescendantNodes().OfType<XElement>();
var keyValuePairs = from n in rootNodes
select new
{
TagName = n.Name,
TagValue = n.Value
};
var allitems = new Dictionary<string, string>();
foreach (var node in rootNodes)
{
allitems.Add(node.Name.ToString(), node.Value);
//string str = string.Join("",allitems);
MessageBox.Show(allitems);
}
You should first parse the XML into objects (Convert XML String to Object).
Then you can simply implement the ToString() method of that type, to print it up nicely.
I think for this part, you need to convert it into .cs file and XML cannot retrieve the messagebox...
Inside of the .cs file, you also can try to put the code for messagebox
MessageBox.Show( // put something over there and you want to show this output );
Related
I am trying to create a list of user id's from an xml document in C#. Here is my latest try:
string xml = WebexAutomation.LstSummaryUser();
XDocument doc = XDocument.Parse(xml)
var result = doc.Descendants("webExId").Single().Value;
Console.WriteLine(result);
My XML looks like it has multiple users and I am trying to create list of each webExId
<?xml version="1.0" encoding="ISO-8859-1"?>
<serv:message xmlns:serv="http://www.webex.com/schemas/2002/06/service" xmlns:com="http://www.webex.com/schemas/2002/06/common" xmlns:use="http://www.webex.com/schemas/2002/06/service/user">
<serv:header>
<serv:response>
<serv:result>SUCCESS</serv:result>
<serv:gsbStatus>PRIMARY</serv:gsbStatus>
</serv:response>
</serv:header>
<serv:body>
<serv:bodyContent xsi:type="use:lstsummaryUserResponse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<use:user>
<use:webExId>kkkk</use:webExId>
<use:firstName>kkkk</use:firstName>
<use:lastName>llllll</use:lastName>
<use:email>kkkkkk</use:email>
<use:registrationDate>06/07/2014 01:17:13</use:registrationDate>
<use:active>DEACTIVATED</use:active>
<use:timeZoneID>11</use:timeZoneID>
</use:user>
<use:user>
<use:webExId>jjjj</use:webExId>
<use:firstName>ssss</use:firstName>
<use:lastName>dddd</use:lastName>
<use:email>dfdfdf</use:email>
<use:registrationDate>06/10/2013 12:23:52</use:registrationDate>
<use:active>DEACTIVATED</use:active>
<use:timeZoneID>11</use:timeZoneID>
</use:user>
<use:matchingRecords>
<serv:total>44</serv:total>
<serv:returned>10</serv:returned>
<serv:startFrom>1</serv:startFrom>
</use:matchingRecords>
</serv:bodyContent>
</serv:body>
</serv:message>
Any suggestions?
Try this instead
var webExId = XName.Get("webExId", "http://www.tempuri.org");
var webExIds = doc.Descendants(webExId);
Not asking for anyone to code this solution for me - just looking for guidance on the best approach. I'm working on an .aspx file in VS2015 using C# code behind.
I've found countless threads explaining how to sort nodes within an XML file. But, I have not found any threads on how to sort multiple XML files with the same structure, according to a common child node attribute.
My situation: I have a directory of hundreds of XML files named, simply, 0001.xml through 6400.xml. Each XML file has the same structure. I want to sort the files (not the nodes) according to the attribute of a child node.
Each XML file has an "item" parent node and has child nodes "year", "language", and "author", among others. For example:
<item id="0001">
<year>2011</year>
<language id="English" />
<author sortby="Smith">John F. Smith</author>
<content></content>
</item>
If, instead of listing the files in order 0001 thru 6400, I instead want to list them in alphabetical order according to the item/author node's #sortby attribute, how would I do that?
One idea that I had was to create a temporary XML file that gathers the information needed from each XML file. Then, I can sort the temporary XML file and then loop through the nodes to display the files in the proper order. Something like this...
XDocument tempXML = new XDocument();
// add parent node of <items>
string[] items = Directory.GetFiles(directory)
foreach (string item in items)
{
// add child node of <item> with attributes "filename", "year", "language", and "author"
}
// then sort the XML nodes according to attributes
Does this make sense? Is there a smarter way to do this?
Sorting
We can show xml files sorted using a bit of LINQ to Xml, with this following code:
var xmlsWithFileName = Directory.GetFiles(directory)
.Select(fileName => new { fileName, xml = XDocument.Parse(File.ReadAllText(fileName)) })
.OrderBy(tuple => tuple.xml.Element("item").Element("author").Attribute("sortby").Value);
Each element of xmlsWithFileName will have
xml property, that contains de XML in XDocument
fileName property, that contains the path of the XML file
Assuming that in your target directory you have this xml files:
0001.xml
<item id="0001">
<year>2011</year>
<language id="English" />
<author sortby="Smith">John F.Smith</author>
<content></content>
</item>
0002.xml
<item id="0002">
<year>2012</year>
<language id="Portuguese" />
<author sortby="Monteiro">Alberto Monteiro</author>
<content></content>
</item>
You can use this code to test
public static void ShowXmlOrderedBySortByAttribute(string directory)
{
var xmlsWithFileName = Directory.GetFiles(directory)
.Select(fileName => new { fileName, xml = XDocument.Parse(File.ReadAllText(fileName)) })
.OrderBy(tuple => tuple.xml.Element("item").Element("author").Attribute("sortby").Value);
foreach (var xml in xmlsWithFileName)
{
Console.WriteLine($"Filename: {xml.fileName}{Environment.NewLine}Xml content:{Environment.NewLine}");
Console.WriteLine(xml.xml.ToString());
Console.WriteLine("================");
}
}
And the output of this code is:
Filename: c:\temp\teste\0002.xml
Xml content:
<item id="0002">
<year>2012</year>
<language id="Portuguese" />
<author sortby="Monteiro">Alberto Monteiro</author>
<content></content>
</item>
================
Filename: c:\temp\teste\0001.xml
Xml content:
<item id="0001">
<year>2011</year>
<language id="English" />
<author sortby="Smith">John F.Smith</author>
<content></content>
</item>
================
As you can see, the XML 0002.xml appear in first position, then the 0001.xml
Edit: And now that I think about it, you probably want the file contents and not the file name, if that's the case, you could instead replace the "items" array in this example with a collection of strings containing the file contents and use GetAuthor to go through that string and return the author name.
I think the best solution would be to add these file names to some sort of collection that can be sorted. This will take your file names and add them to a Lookup:
var lookup = items.ToLookup(a => GetAuthor(a)).OrderBy(a => a.Key);
This is going to rely on a method that uses the file name to get the author name:
private string GetAuthor(string filename)
{
string author = String.Empty;
// get author name logic
return author;
}
And finally, to interate through your list:
foreach (IGrouping<string, string> author in lookup)
{
foreach (string file in author)
{
Console.WriteLine(String.Format("{0}: {1}", author.Key, file ));
}
}
If you decide you want to sort the list based on more than one criteria, you'll have to take a different approach and create a custom object, add those to a list and use a custom IComparer, but this example will allow you to avoid all that if you only care about the author name.
If I understand what you are saying correctly, this is how I would go about it:
SortedDictionary<string, string> dict = new SortedDictionary<string, string>();
var files = Directory.GetFiles(#"[path to files]", "*.xml");
foreach (var item in files)
{
XDocument doc = XDocument.Load(item);
var sortvalue = (from lv1 in doc.Descendants("somesortvalue")
select lv1.Value).First();
dict.Add(sortvalue, item);
}
Then you can do a foreach on the dict.keys and the filenames will be sorted by the dictionary functionality.
Have two ways to sort data of XML file by InnerText of it's nodes
Use Linq
You can load all Item to list and orderby by Element of childnode.
You can make a function with one para is name of childnode to do that.
You can use XSLT to transform
Refer Sorting of XML file by XMLElement's InnerText for more detail
Hope it help!
You can load items using XElement and sort them this way:
var items = System.IO.Directory.GetFiles(#"path", "*.xml")
.Select(file => System.Xml.Linq.XElement.Load(file));
.OrderBy(x => x.Element("author").Attribute("sortby").Value)
.ToList();
Also if you need file names, you can select an object containing FileName and Item:
var items = System.IO.Directory.GetFiles(#"path", "*.xml")
.Select(file => new
{
FileName = file,
Item = System.Xml.Linq.XElement.Load(file)
})
.OrderBy(x => x.Item.Element("author").Attribute("sortby").Value)
.Select(x=>x.FileName) /*or .Select(x=>x.Item)*/
.ToList();
Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);
Friends,
My school project is having an xml data file:
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>Somewhere</add>
<mobile>0000</mobile>
.
.
.
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>
My Windowsform "EditPatients_Load" is able to fetch all info of patient Jhon, and now let's assume that the Admin needs to change some information in the form & resubmit.
Then how to write back all values to Jhon's account in the same xml
file????
I'm not able to makeup the logical code, even if I check the node if (patients.paptient.name = "nameComboBox.text").... how to make sure that I'm writing other values on proper place?
Rgrdz,
Try this:
//string xml =
//#"<patients><patient><regNo>2012/Mar/003</regNo><name>Jhon</name><add>Somewhere
//</add><mobile>0000</mobile><stay>2</stay><costofroom>100</costofroom><total>200</total>
//</patient></patients>";
XDocument xmlDoc = XDocument.Load(#"c:\abc.xml");
var items = (from item in xmlDoc.Descendants("patient")
where item.Element("name").Value == "Jhon"
select item);
if (items.Count() > 0)
{
var item = items.First();
item.SetElementValue("add", "New New Address");
xmlDoc.Save(#"c:\abc.xml", SaveOptions.None);
}
You can get single element using
var item = (from item in xmlDoc.Descendants("patient")
where item.Element("name").Value == "Jhon"
select item).FirstOrDefault();
then update it using SetElementValue() method.
//Updated Xml
<?xml version="1.0" encoding="utf-8"?>
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>New Address</add>
<mobile>0000</mobile>
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>
Reference:
Update XML with C# using Linq
I would take the xml serialization/deserialization route to solve this:
http://support.microsoft.com/kb/815813
How to Deserialize XML document
That way you can work with objects and not have to parse xml files manually.
If you're using .NET 3.5 onward you can use the XDocument class like the following. I'm assuming your content is in a .xml file.
XDocument xdoc = XDocument.Load(#"C:\Tmp\test.xml");
//this would ensure you get the right node and set its text content/value
xdoc.Element("patients")
.Element("patient").Element("add").Value = "some new address?";
xdoc.Save(#"C:\Tmp\test.xml");
The file test.xml would change to:
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>some new address?</add>
<mobile>0000</mobile>
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>
I'm having trouble trying to update my xml file with a new value. I have a class Person, which only contains 2 strings, name and description. I populate this list and write it as an XML file. Then I populate a new list, which contains many of the same names, but some of them contains descriptions that the other list did not contain. How can I check if the name in the current XML file contains a value other than "no description", which is the default for "nothing"?
Part of the xml file:
<?xml version="1.0" encoding="utf-8"?>
<Names>
<Person ID="2">
<Name>Aaron</Name>
<Description>No description</Description>
</Person>
<Person ID="2">
<Name>Abdi</Name>
<Description>No description</Description>
</Person>
</Names>
And this is the method for writing the list to the xml file:
public static void SaveAllNames(List<Person> names)
{
XDocument data = XDocument.Load(#"xml\boys\Names.xml");
foreach (Person person in names)
{
XElement newPerson = new XElement("Person",
new XElement("Name", person.Name),
new XElement("Description", person.Description)
);
newPerson.SetAttributeValue("ID", GetNextAvailableID());
data.Element("Names").Add(newPerson);
}
data.Save(#"xml\boys\Names.xml");
}
In the foreach loop how do I check if the person's name is already there, and then check if the description is something other than "no description", and if it is, update it with the new information?
I'm not sure I understand properly what you want, but I'm assuming you want to update the description only when the name is already there and the description is currently No description (which you should probably change to an empty string, BTW).
You could put all the Persons into a Dictionary based by name:
var doc = …;
var persons = doc.Root.Elements()
.ToDictionary(x => (string)x.Element("Name"), x => x);
and then query it:
if (persons.ContainsKey(name))
{
var description = persons[name].Element("Description");
if (description.Value == "No description")
description.Value = newDescription;
}
That is, if you care about performance. If you don't, you don't need the dictionary:
var person = doc.Root.Elements("Person")
.SingleOrDefault(x => (string)x.Element("Name") == name);
if (person != null)
{
var description = person.Element("Description");
if (description.Value == "No description")
description.Value = newDescription;
}
You can use the Nodes-Method on XElement and check manually.
But i will advise you to use the XPathEvaluate-Extension Method
For XPath expression take a look at:
How to check if an element exists in the xml using xpath?
I think you could create a peoplelist which only contains people not in the xml.
like ↓
var containlist = (from p in data.Descendants("Name") select p.Value).ToList();
var result = (from p in peoplelist where !containlist.Contains(p.Name) select p).ToList();
so that , you would no need to change anything with your exist method ...
just call it after..
SaveAllNames(result);