Reading special field from variable XML File c# - c#

I have got a file called xmlfile.xml:
<Personen>
<Person>
<Vorname>Manfred</Vorname>
<Telefon/>
<Zuname>Fischer</Zuname>
<Alter>45</Alter>
<Adresse Ort="Bonn" Strasse="Neuestr.34"></Adresse>
</Person>
</Personen>
There are two problems. First of all are the fields of '' variable. So maybe the xmlfile contains 3 persons or another value (of course it contains at least one). Now I need to print out the 'Vorname' of each Person, how can I do so? I tried this code (just a short view):
reader.ReadToFollowing("Person");
string isbn = reader.GetAttribute("Alter");
Console.WriteLine("age: " + isbn);
Console.ReadLine();
But it doesn't print out the age (Alter), how to get it working to print out the age of each person, in case there are more then one.

Just do a quick search and you'll find plenty of resource to read XML via fabulous Linq:
LINQ to read XML
For example to extract persons:
XDocument xdoc = XDocument.Load(yourFileName));
var persons = from lv1 in xdoc.Descendants("Person")
select lv1.Value;

Related

Matching a string with XML with value stored over multiple elements

I want to find out if some string has a match in an XML file.
for example:
string test="New York, USA";
in an XML file formated this way:
<?xml version="1.0"?>
<line>
<word>New</word>
<word>York,</word>
<word>USA</word>
</line>
so that every word may or may not be in a different element
What is the most easiest way to do this?
I was thinking about matching each word separately while saving the partial results but it seems to me like there have to be easier way.
If you want to compare word by word you can compare this using two string lists.
using below you can get xml to List
List<string> list = doc.Root.Descendants("line").Descendants()
.Select(element => element.Value)
.ToList();
Then take your comparison string to list
string words = "New York, USA";
List<string> result = words.Split(' ').ToList();
Compare both lists using Intersect(). refer this
var matcheditems = list.Intersect(result);
Hope this will help you.

How to do operations (avg, cnt, etc) while parsing xml (c#)?

I have the following xml:
<bookstore>
<book IMDB="11-023-2022">
<title>Hamlet 2</title>
<comments>
<user rating="2">good enough</user>
<user rating="1">didnt read it</user>
<user rating="5">didnt read it but title is good</user>
</comments>
</book>
</bookstore>
I have an AverageUserRating property which i supposed to fill while parsing in the following format, I also have no idea how to cast comments into list. I tried everything, I can't use nuget packages like xpath. Thank you for your help.
return xdoc.Descendants("book").Select(n => new Books()
{
IMDB = n.Attribute("IMDB").Value,
Title = n.Element("title").Value,
//Comments = (List<string>)(n.Elements("user")), ???
//AverageUserRating= ???
}).ToList();
Comments = n.Element("comments").Elements("user").Select(u => u.Value).ToList(),
Explation:
1) Element("comments"), returns the child html element named "comments"
2) Elements("user"), returns all childrens elements named "user"
3) .Select(u => u.Value), select from every user element the value, that is the comment that you need
4) .ToList() converts into a list of strings
AverageUserRating = n.Element("comments").Elements("user").Select(u => u.Attribute("rating").Value).Select(r => Convert.ToInt32(r)).Average()
Explation:
1) Element("comments"), returns the child html element named "comments"
2) Elements("user"), returns all childrens elements named "user"
3) .Select(u => u.Attribute("rating").Value), selects from any element the value of the attribute "rating"
4) .Select(r => Convert.ToInt32(r)) converts the string value of the attribute into an int32 (pay attention, if the value is not a number, it throws an exception)
5) .Average() It calculates the aritmetic average and returns a double
Maybe, you should process original XML with XSLT to get the data you need automatically. Then, resulting doc could be easier to parse. Take a look here as an example Calculate average with xslt
It uses HTML as output format, you can do the same with XML.
Another option can be to create the classes with the same structure as your original XML so then you could employ automatic deserialization. Then, use LINQ or any other way to get the stats.

How to search the XML tag?

I want to search the tags in XML.
My XML is:-
<school>
<student>
<firstname>Vijay</firstname>
<lastname>Prabhu</lastname>
<age>27</age>
<photo>/NewExample;component/Images/icon_man.png</photo>
</student>
<student>
<firstname>Arun</firstname>
<lastname>Prasath</lastname>
<age>5</age>
<photo>/NewExample;component/Images/icon_man.png</photo>
</student>
<student>
<firstname>Satheesh</firstname>
<lastname>Kumar</lastname>
<age>27</age>
</student>
</school>
Here I want to check <photo> tag is available or not.
I have try like this.
var school= from ack in xdoc.Descendants("school")
select ack;
for(int i =0;i<school.count();i++)
{
if(school.ElementAt(i).Element("photo").Name.LocalName.Equals("photo"));
Console.WriteLine("Tag is available in==>"+i);
else
Console.WriteLine("Tag is Not available in==>"+i);
}
It is working. But when I use this same in another example with diff elements it showing error.
Please let me know any other effective way to search the Tags in c#.
Thanks in advance.
Get all students. Then try to retrieve photo element from student element. If it is equal to null then photo no exist in current student:
var students = xdoc.Root.Elements("student");
int i = 1;
string format = "Tag is {0}available in {1}";
foreach(var student in students)
Console.WriteLine(format, student.Element("photo") == null ? "not " : "",i++);
Output:
Tag is available in 1
Tag is available in 2
Tag is not available in 3
You can write extension to make code more readable
public static bool HasElement(this XElement parent, XName name)
{
return parent.Element(name) != null;
}
E.g. selecting all students which have photo will look like
from student in xdoc.Root.Elements("student")
where student.HasElement("photo")
select student
You also can use XPath for same task
xdoc.XPathSelectElements("school/student[photo]")

Parsing xml string to get certain tag values within

I have an xml string and have different records within and i want to extract the id within each record. Here is a sample of the xml:
<UploadsInformation >
<Record>
<TaskGUID>48A583CA-A532-419A-9CDB-292764CEC541</TaskGUID>
</Record>
<Record>
<TaskGUID>ED6BA682-2BB2-4ADF-8355-9C605E16E088</TaskGUID>
</Record>
<Record>
<TaskGUID>D20D7042-FC5B-4CF7-9496-D2D9DB68CF52</TaskGUID>
</Record>
<Record>
<TaskGUID>F5DB10C5-D517-4CDA-8AAA-4E3F50B5FF3C</TaskGUID>
</Record>
</UploadsInformation>
This is what i have as a string to extract the information that i need but not sure if it correct or not because when i debug the string seems to be the xml file and not just the specified guid.
string data = new XDocument(new XElement("Record",
uploads.Select(guid => new XElement("TaskGUID", guid.ToString()))))
.ToString();
uploads is: List<Guid?> uploads
If I understand your question correctly, you want to extract the Guids from the source XML, which you indicate is a string.
You can create an XDocument from a string with the following command:
XDocument doc = XDocument.Parse(xmlString);
XNamespace ns = "http://schemas.acatar.com/2013/03/Malt.Models";
List<string> uploads = doc.Descendants(ns + "TaskGUID")
.Select(x => x.Value).ToList();
string uploadString = String.Join(",", uploads);
I used XNamespace because there is a namespace (two, actually) defined in the XML, and unless you prefix the correct one to the element name you won't get any results.
You might be able to combine the last two steps into one line, but I'm not 100% sure.
The above code was tested with your example, and produces the following value for uploadString:
48A583CA-A532-419A-9CDB-292764CEC541,ED6BA682-2BB2-4ADF-8355-9C605E16E088,D20D7042-FC5B-4CF7-9496-D2D9DB68CF52,F5DB10C5-D517-4CDA-8AAA-4E3F50B5FF3C
However, if you're going to loop through the result and pass each one in singularly to a stored procedure, I'd skip the String.Join and just loop through the List:
foreach (string id in uploads)
{
// Do your stored procedure call for each Guid.
}
Added in Response to Comment
In the situation in your comment, if you have a List that you want to get the values for, you'd do essentially the same, but you'll need to check for nulls and (probably) convert the Guid to a string before passing it into the stored proc:
foreach (Guid? g in uploads)
{
if (g != null)
{
string newGuid = g.ToString();
// do your data access stuff here
}
}
You can't use local names of elements, because you have namespace declared. So, you should use namespace to provide names:
XNamespace ns = "http://schemas.acatar.com/2013/03/Malt.Models";
var guids = from r in xdoc.Root.Elements(ns + "Record")
select Guid.Parse((string)r.Element(ns + "TaskGUID"));
Or query your xml without specifying names of elements:
var guids = xdoc.Root.Elements()
.Select(r => Guid.Parse((string)r.Elements().Single()));
I think this is either what you are after or perhaps might shed some light on the direction to go:
string xml = ""; // XML data here
XDocument doc = XDocument.Parse(xml);
List<Guid> guids = doc.Descendants("TaskGUID")
.Select(g => new Guid(g.Value))
.ToList();

XML How to select Child Elements using XPath

I've got the following XML, shown in the following image:
But I can't for the life of me, get any code to select the house element between <ArrayOfHouse>.
There will be more than one House element once I've managed to get it to select one, here's my code so far:
// Parse the data as an XML document
XDocument xmlHouseResults = XDocument.Parse(houseSearchResult);
// Select the House elements
XPathNavigator houseNavigator = xmlHouseResults.CreateNavigator();
XPathNodeIterator nodeIter = houseNavigator.Select("/ArrayOfHouse/House");
// Loop through the selected nodes
while (nodeIter.MoveNext())
{
// Show the House id, as taken from the XML document
MessageBox.Show(nodeIter.Current.SelectSingleNode("house_id").ToString());
}
I'm getting the stream of XML, because I have managed to show the data in the MessageBox shown above, but I can't get to the individual houses.
You can select the House nodes like this:
var houses = XDocument.Parse(houseSearchResult).Descendants("House");
foreach(var house in houses)
{
var id = house.Element("house_id");
var location = house.Element("location");
}
Or you can use Select to directly get a strongly typed object:
var houses = XDocument.Parse(houseSearchResult)
.Descendants("House")
.Select(x => new House
{
Id = x.Element("house_id"),
Location = x.Element("location")
});
This assumes that there exists a class House with the properties Id and Location.
Also, please be sure to think about the suggestion by Thomas Levesque to use XML serialization.
With XPath you would need to use an XmlNamespaceManager, however as you have an XDocument you could simply use the LINQ to XML axis methods e.g.
XNamespace df = XmlHouseResults.Root.Name.Namespace;
foreach (XElement house in XmlHouseResults.Descendants("df" + "House"))
{
MessageBox.Show((string)house.Element("df" + "house_id"));
}

Categories