How to retrieve multiple let linq to xml c# - c#

I am trying to get all the Hoop attributes but its only getting the first values(In this instance it is adding 24 and 4 to the listbox). Is there a way of adding all my result to a list. I usually use .ToList() but it did not work in this instant. The aim was to get the hoops for Home and away separate then store it into an object.
XML:
<League>
<Round>
<Match>
<Team Side="Home" >
<Hoop qtr="1st" player-name="Joe" time-scored="24" />
<Hoop qtr="1st" player-name="Jack" time-scored="54" />
</Team>
<Team Side="Away">
<Hoop qtr="1st" player-name="James" time-scored="4" />
<Hoop qtr="1st" player-name="Brown" time-scored="34" />
</Team>
</Match>
</Round>
</League>
C#:
XDocument xDoc = XDocument.Load("test.xml");
var query = from q in xDoc.Descendants("Team")
where (string)q.Attribute("Side") == "Home"
let d = q.Element("Hoop")
select new
{
Period = d.Attribute("qtr").Value,
Name = d.Attribute("player-name").Value,
Time = d.Attribute("time-scored").Value
};
foreach (var qq in query)
{
listBox.Items.Add(qq.Time);
}

Change let d = q.Element("Hoop") to from d in q.Elements("Hoop")
var xDoc = XDocument.Load("test.xml");
var query = from q in xDoc.Descendants("Team")
where (string)q.Attribute("Side") == "Home"
from d in q.Elements("Hoop")
select new
{
Period = d.Attribute("qtr").Value,
Name = d.Attribute("player-name").Value,
Time = d.Attribute("time-scored").Value
};
foreach (var qq in query)
{
listBox.Items.Add(qq.Time);
}

Related

Extracting XML data with Linq in C# difficulty

So I'm working with reading an xml file to create a dictionary, but I can't figure out how to access the xml fields I want.
Below is the format of the XML I want to read.
<Days>
<Day Name="Monday">
<Task Order="1">TestTask</Task>
<Task Order="2">Test2</Task>
</Day>
</Days>
Below is my code so far. I've tried a lot of variations for finding task and order, such as for task: (string)e, or e.ToString(), or e.Elements("Task").Value.ToString(); And for order e.Attributes("Order").ToString();
string today = DateTime.Now.ToString("dddd");
var allItems = new Dictionary<string, int>();
XElement root = XElement.Parse(_orderxml);
IEnumerable<XElement> address =
from el in root.Elements("Day")
where el.Attribute("Name").Value == today
select el;
foreach (XElement e in address)
{
string task = ???;
string order = ???;
allItems.Add(task, (int)order);
}
So far, none of these have given me the right results, and I'm really unsure of what the proper way to get this data is, so any help would be appreciated!
Add a second loop to iterate the tasks and extract the values
static void Main()
{
string _orderxml = #"<Days> <Day Name=""Wednesday""> <Task Order=""1"">TestTask</Task> <Task Order=""2"">Test2</Task> </Day></Days>";
string today = DateTime.Now.ToString("dddd");
var allItems = new Dictionary<string, int>();
XElement root = XElement.Parse(_orderxml);
IEnumerable<XElement> address =
from el in root.Elements("Day")
where el.Attribute("Name").Value == today
select el;
foreach (XElement e in address)
{
foreach (XElement t in e.Descendants())
{
string task = t.Value.ToString();
int order = int.Parse(t.Attribute("Order").Value.ToString());
allItems.Add(task, (int)order);
}
}
}
Or you can do it with a Linq query like this
var result=root.Descendants("Day").Where(d=>d.Attribute("Name").Value==today).Descendants("Task").Select(x => new {Task=x.Value,Order=x.Attribute("Order") });
Or create a dictionary from the anonymous objects
var result = root.Descendants("Day").Where(d=>d.Attribute("Name").Value==today).Select(x => new { Task = x.Value.ToString(), Order = x.Attribute("Order") }).ToDictionary(c => c.Task, c => c.Order);
Or create a dictionary directly from the linq query
var result = root.Descendants("Day").Where(d=>d.Attribute("Name").Value==today).ToDictionary(c => c.Value.ToString(), c => int.Parse(c.Attribute("Order").Value.ToString()));

XML to List in C#

This is the xml:
<Packages>
<Package>
<Id>1</Id>
<Prerequisites>
<Prerequisite>7</Prerequisite>
<Prerequisite>8</Prerequisite>
</Prerequisites>
</Package>
<Package>
<Id>2</Id>
.....
</Package>
....
</Packages>
And the list:
class lista
{
public int id {get; set;}
public List<int> pre{get;set;}
}
How can I add This xml pattern to a list of lista class and this is what i have got so far bot it only put one in the second list.
XDocument xdoc = XDocument.Load("Employee.xml");
var ListPckage =
(from item in xdoc.Descendants("Package")
orderby item.Element("Id").Value
select new
{
Id = item.Element("Id").Value,
Prerequisite = item.Element("Prerequisites").Element("Prerequisite").Value,
}).ToList();
foreach works for shoing them
foreach (var item in ListPckage)
{
Console.WriteLine(item.Id);
foreach (var item1 in ListPckage)
{
Console.WriteLine(item1.Prerequisites);
}
}
As John Sket mentioned in the comment to the question, one way to achieve that is to use Linq To Xml.
//string xcontent = #"xml content here";
//XDocument xdoc = XDocument.Parse(xcontent);
XDocument xdoc = XDocument.Load("FullPathToXml");
List<lista> resultlist = xdoc.Descendants("Package")
.Select(x=> new lista
{
id = Convert.ToInt32(x.Element("Id").Value),
pre = x.Descendants("Prerequisite").Select(y=>Convert.ToInt32(y.Value)).ToList()
})
.ToList();
But, i'd suggest to use XmlSerialization/XmlDeserialization.
First parse the XML to XDocument using XDocument.Parse to get XML in XDocument variable i.e.
var requiredXml = XDocument.Parse("Xml String here")
Then you can use LINQ to Xml (something like) as below:
//may be syntactic error but you can get an idea
var requiredList =
from element in requiredXml.Descandants("Package")
Select new lista { id = element.Element("ID").Value,
pre = element.Elements("Prerequisite").Select(x=> Convert.ToInt32(x.Value)).ToList() }

Xdocument getting element node value from another note in the xml file

I'm trying to get some data from an XML file - see below.
Basically for each session data, I get all the elements in it and store it but I need to get the movie_Name from the elements with reference by the movie.
<Schedule_Data>
<Movies>
<Movie>
<Cinema_ID>3169101</Cinema_ID>
<Movie_ID>1012689</Movie_ID>
<Movie_Name>2D Captain America: Civil War</Movie_Name>
<Rating>PG13</Rating>
<Runtime>160</Runtime>
</Movie>
<Movie>
<Cinema_ID>3169101</Cinema_ID>
<Movie_ID>1012984</Movie_ID>
<Movie_Name>2D Zootopia</Movie_Name>
<Rating>PG</Rating>
<Runtime>115</Runtime>
</Movie>
</Movies>
<Sessions>
<Session>
<Cinema_ID>8888888</Cinema_ID>
<Movie_ID>1012689</Movie_ID>
<Session_ID>1083592422</Session_ID>
<Price_group_code>10007</Price_group_code>
<Auditorium_Number>9</Auditorium_Number>
<Assigned_Seating>True</Assigned_Seating>
<Attribute></Attribute>
<Date_time>20160607141000</Date_time>
<Total_Seats>87</Total_Seats>
<Available_Seats>87</Available_Seats>
</Session>
<Session>
<Cinema_ID>8888888</Cinema_ID>
<Movie_ID>1012984</Movie_ID>
<Session_ID>1083592423</Session_ID>
<Price_group_code>10007</Price_group_code>
<Auditorium_Number>9</Auditorium_Number>
</Session>
</Sessions>
</Schedule_Data>
Currently my code is:
XDocument thisXML = XDocument.Parse(responseText);
//get the dates element (which contains all the date nodes)
XElement datesElement = thisXML.Element("Schedule_Data").Element("Sessions");
//use linq to compile an ienumerable of the date nodes
var dates = from dateNode in datesElement.Elements("Session")
select dateNode;
//get the dates element (which contains all the film nodes)
XElement MoviesElement = thisXML.Element("Schedule_Data").Element("Movies");
foreach (XElement session in dates)
{
//get movie name
var films = from filmnode in MoviesElement.Elements("Movie")
select filmnode;
var movieId = session.Element("Movie_ID").Value;
// This is where i try do the where clause and try get the value but it returns null
var answer = from reply in films
where reply.Element("Movie_ID").Value == movieId
select films.Elements("Movie_Name");
//create a new session import record
ORM.Sessionimportattemptimportedsession newSessionimportattemptimportedsession = new ORM.Sessionimportattemptimportedsession();
//check data and set properties
newSessionimportattemptimportedsession.MovieTitle = answer.ToString();
newSessionimportattemptimportedsession.ScreenNumber = session.Element("Screen_bytNum").Value;
.....
numberOfSessions++;
}
Any suggestions?
You're just performing a join between sessions and movies. Just do this:
var query =
from s in doc.Descendants("Session")
join m in doc.Descendants("Movie")
on (string)s.Element("Movie_ID") equals (string)m.Element("Movie_ID")
select new
{
MovieName = (string)m.Element("Movie_Name"),
Session = s,
Movie = m,
};

Get values of specific xml elements in c# by linq

This is the result of an online xml :
<prices targetNamespace="http://api.saxo.com/v1/prices/">
<price>
<id>28924741-0-0-1-0-1-0</id>
<quantity type="integer">1</quantity>
<normalprice type="decimal">49,95</normalprice>
<price type="decimal">49,95</price>
<vatpercent type="decimal">25,00</vatpercent>
<fixedprice>false</fixedprice>
<discount type="decimal">0,00</discount>
<allowdiscount type="integer">1</allowdiscount>
<productid>28924741</productid>
<entries>
<entry>
<id>1</id>
<type type="PriceEntryType">Standard</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">9,99</vatamount>
<priceunitexvat type="decimal">39,96</priceunitexvat>
<priceunitinclvat type="decimal">49,95</priceunitinclvat>
<pricetotalexvat type="decimal">39,96</pricetotalexvat>
<pricetotalinclvat type="decimal">49,95</pricetotalinclvat>
<discountpercent type="decimal">0,00</discountpercent>
<discountamountexvat type="decimal">0,00</discountamountexvat>
<discountamountinclvat type="decimal">0,00</discountamountinclvat>
</entry>
<entry>
<id>2</id>
<type type="PriceEntryType">Context</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">9,99</vatamount>
<priceunitexvat type="decimal">39,96</priceunitexvat>
<priceunitinclvat type="decimal">49,95</priceunitinclvat>
<pricetotalexvat type="decimal">39,96</pricetotalexvat>
<pricetotalinclvat type="decimal">49,95</pricetotalinclvat>
<discountpercent type="decimal">0,00</discountpercent>
<discountamountexvat type="decimal">0,00</discountamountexvat>
<discountamountinclvat type="decimal">0,00</discountamountinclvat>
</entry>
<entry>
<id>3</id>
<type type="PriceEntryType">Subscription</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">6,99</vatamount>
<priceunitexvat type="decimal">27,96</priceunitexvat>
<priceunitinclvat type="decimal">34,95</priceunitinclvat>
<pricetotalexvat type="decimal">27,96</pricetotalexvat>
<pricetotalinclvat type="decimal">34,95</pricetotalinclvat>
<discountpercent type="decimal">30,03</discountpercent>
<discountamountexvat type="decimal">12,00</discountamountexvat>
<discountamountinclvat type="decimal">15,00</discountamountinclvat>
</entry>
</entries>
</price>
</prices>
I tried many ways to get value of "normalprice" and "pricetotalinclvat" of last entry . but i got null or exception .
Can you guide me that how i can get those two values by using linq ?
Looks like a possible duplication of this
The short version is:
XElement element = XElement.Parse(YourString);
var prices = element.Elements("price")
.Select(item => item.Element("normalprice").Value);
These values can be extracted using Descendant in combination with Last:
var xml = XElement.Parse(xmlStr);
var normalPrice = xml
.Descendants("normalprice")
.Last()
.Value;
var pricetotalinclvat = xml
.Descendants("pricetotalinclvat")
.Last()
.Value;
If approach does not matter, loading the contents into an XDocument and accessing via XPath would seem to make more sense in this situation:
You will want to be using the System.Xml.XPath namespace with this...
System.Xml.Linq.XDocument xdoc = System.Xml.Linq.XDocument.Parse(xmlString);
decimal priceNormal = 0;
decimal.TryParse(xdoc.XPathSelectElement(#"/prices/price/normalprice").Value, out priceNormal);
decimal priceTotalInclvat = 0;
decimal.TryParse(xdoc.XPathSelectElement(#"/prices/price/entry[last()]/pricetotalinclvat").Value, out priceTotalInclvat);
You can try this:
XDocument doc = XDocument.Load(path);
var query = from price in doc.Descendants("price")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = price.Descendants("entry").Last().Element("pricetotalinclvat").Value
};
To avoid a null exception in case you don't have entries you can also do this:
var query = from price in doc.Descendants("price")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = price.Descendants("entry").Any()?price.Descendants("entry").Last().Element("pricetotalinclvat").Value:"0"
};
Or:
var query = from price in doc.Descendants("price")
let entries = price.Descendants("entry")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = entries!=null ? entries.Last().Element("pricetotalinclvat").Value : "0"
};
I tried all of the solutions in this page but i did not get any result . it is so weird .this is what i did , but it is not a good way :
var document = XDocument.Load(url);
var root = document.Root;
if (root == null)
return;
var ns = root.GetDefaultNamespace();
var mainNode = document.Element(ns + "prices");
if (mainNode == null)
return;
var priceNode = mainNode.Elements(ns + "price").FirstOrDefault().Elements();
var lastEntry = mainNode.Elements(ns + "price").FirstOrDefault().Elements().Last().Elements().Last().Elements();
foreach (var element in lastEntry.Where(element => element.Name.LocalName == "pricetotalinclvat"))
{
plusPrice = element.Value;
}
foreach (var element in priceNode.Where(xElement => xElement.Name.LocalName == "price"))
{
price = element.Value;
}
Any Suggestion to make it better ?

Find a child node and get the value of it using a variable. Windows phone

So i am able to select all the results under a certain node, but I have the following XML
<ArrayOfStop>
<Stop>
<StopName>Rajdutt Restaurant</StopName>
<route_stop />
<route_stop_stop />
<route_stop_timetable_stop />
<stopId>6400</stopId>
</Stop>
<Stop>
<StopName>Cysleys Farm (by request only)</StopName>
<route_stop />
<route_stop_stop />
<route_stop_timetable_stop />
<stopId>6401</stopId>
</Stop>
<ArrayOfStop>
If i want to select stopId if the stopname was Cysleys Farm (by request only) how would one go about it?
I have the following code:
XDocument loadedData = XDocument.Load("People.xml");
var data = from query in loadedData.Descendants("ArrayOfStop")
select new Person
{
StopName = (string)query.Element("StopName")
};
listBox.ItemsSource = data;
EDIT:
var data = from query in loadedData.Descendants("ArrayOfStop")
where query.Element("StopName").Value == "Cysleys Farm (by request only)"
select query.Element("StopId").Value;
select new Person
{
FirstName = (string)query.Element("StopName"),
//LastName = (string)query.Element("Long"),
//Age = (int)query.Element("age")
};
listBox.ItemsSource = data;
EDIT 2
Do the items need to be going into a list box? As i need the value in a string format to use on a url.
var doc =
XDocument.Parse(
"<ArrayOfStop><Stop><StopName>Rajdutt Restaurant</StopName><route_stop /><route_stop_stop /><route_stop_timetable_stop /><stopId>6400</stopId></Stop><Stop><StopName>Cysleys Farm (by request only)</StopName><route_stop /><route_stop_stop /><route_stop_timetable_stop /><stopId>6401</stopId></Stop></ArrayOfStop>");
var list = (from item in doc.Descendants("Stop")
where (string) item.Element("StopName") == "Cysleys Farm (by request only)"
select (string)item.Element("stopId")).ToList();
This will get you a single node that has a matching value. If you expect more than one node will have a matching value and only want the first one, then use FirstOrDefault instead of SingleOrDefault.
string search = "Cysleys Farm (by request only)";
var query = doc.Root.Elements()
.SingleOrDefault( x => x.Element( "StopName" ).Value == search );
if (query != null)
{
// if the query is not null, then this will be
// a single node with a root of <Stop>
string id = query.Element( "stopId" ).Value;
}
Another way of doing it is:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("People.xml");
// Select the 'StopId' node whose StopName is 'Cysleys Farm (by request only)'
XmlNode stopIdNode = xmlDoc.SelectSingleNode("/ArrayOfStop/Stop[StopName='Cysleys Farm (by request only)']/stopId");
string stopId = stopIdNode.InnerText;
If there are multiple nodes with the same StopName, then you can store them in a list:
List<string> stopIdList = new List<string>();
foreach (XmlNode stopIdNode
in xmlDoc.SelectNodes
("/ArrayOfStop/Stop[StopName='Cysleys Farm (by request only)']/stopId"))
{
stopIdList.Add(stopIdNode.InnerText);
}

Categories

Resources