Reputation: 1314
I'm a bit of a LINQ newbie and I was having some trouble with the following. I'm trying to perform a query using LINQ on an XML file and store the results in a list of DataClass objects that match the XML.
I've got an XML file that is defined like this:
<NewDataSet>
<NewDataTable>
<Field>Accepted ASNs</Field>
<Val>59</Val>
<Order Number="1234" ShipDate="2009/05/21" />
<Order Number="2190" ShipDate="2009/05/22" />
<Order Number="1809" ShipDate="2009/05/22" />
</NewDataTable>
<NewDataTable>
<Field>Rejected ASNs</Field>
<Val>8</Val>
<Order Number="2901" ShipDate="2009/05/21" />
<Order Number="2810" ShipDate="2009/05/24" />
<Order Number="1419" ShipDate="2009/05/25" />
</NewDataTable>
<NewDataTable>
<Field>Missing ASNs</Field>
<Val>7</Val>
<Order Number="2902" ShipDate="2009/05/19" />
<Order Number="2898" ShipDate="2009/05/20" />
<Order Number="1296" ShipDate="2009/05/22" />
</NewDataTable>
</NewDataSet>
I have created a Data class to support this XML format. What I would like to do is create a LINQ Query to grab these 3 records and store them into a List of my DataClass.
In order to support multiple Order elements, I have my class defined with a generic list of "Order" structs... It looks like this:
Public Class ASNData
Private _field As String
Private _value As String
Private _orders As List(Of Order)
Public Property Field() As String
Get
Set
End Property
Public Property Value() As String
Get
Set
End Property
Public Property Orders() As List(Of Order)
Get
Set
End Property
Structure Order
Private _number As String
Private _date As Date
Public Property Number() As String
Get
Set
End Property
Public Property ShippingDate() As Date
Get
Set
End Property
End Structure
End Class
The biggest issue I'm having is figuring out how to grab the 3 order elements and store them into my list of Order structs.
Can anyone point me in the right direction on this?
Thank you.
Upvotes: 2
Views: 4064
Reputation:
XDocument xmlDoc = XDocument.Load(Server.MapPath("Order.xml"));
List<ASNData> lst= (from data in xmlDoc.Root.Elements("NewDataTable")
select new ASNData
{
Field=data.Element("Field").Value,
Value=data.Element("Val").Value,
Orders=(from ord in data.Elements("Order")
select new Order
{
Number=ord.Attribute("Number").Value,
ShippingDate=Convert.ToDateTime(ord.Attribute("ShipDate").Value)
}).ToList<Order>()
}).ToList<ASNData>();
foreach(ASNData a in lst)
{
Response.Write("Field:"+a.Field+"</br>");
Response.Write("Value:"+a.Value+"</br>");
Response.Write("Orders:"+"</br>");
foreach(Order o in a.Orders)
{
Response.Write("OrderNum:"+o.Number+"</br>");
Response.Write("ShipDate:"+o.ShippingDate+"</br>");
}
}
Upvotes: 0
Reputation: 13837
Here is the code for a Console application with the LINQ query you need. I had to fill in the getters and setters of your class and containing structure, but this is tested working code. To get a List(Of ASNData) just call DataTables.ToList
Of course this will work with any number of Order elements.
Using Structure Order works just fine. I would use a Class, but no need to change it for this to work.
The key part of this code is the LINQ query:
Dim DataTables = From NewDataTable In TestData...<NewDataTable> _
Select New ASNData With {.Field = NewDataTable.<Field>.Value, _
.Value = NewDataTable.<Val>.Value, _
.Orders = (From AnOrder In NewDataTable...<Order> _
Select New ASNData.Order With _
{.Number = AnOrder.@Number, _
.ShippingDate = Date.Parse(AnOrder.@ShipDate)}).ToList}
Here is the complete working console app:
Module Module1
Sub Main()
Dim TestData = <NewDataSet>
<NewDataTable>
<Field>Accepted ASNs</Field>
<Val>59</Val>
<Order Number="1234" ShipDate="2009/05/21"/>
<Order Number="2190" ShipDate="2009/05/22"/>
<Order Number="1809" ShipDate="2009/05/22"/>
</NewDataTable>
<NewDataTable>
<Field>Rejected ASNs</Field>
<Val>8</Val>
<Order Number="2901" ShipDate="2009/05/21"/>
<Order Number="2810" ShipDate="2009/05/24"/>
<Order Number="1419" ShipDate="2009/05/25"/>
</NewDataTable>
<NewDataTable>
<Field>Missing ASNs</Field>
<Val>7</Val>
<Order Number="2902" ShipDate="2009/05/19"/>
<Order Number="2898" ShipDate="2009/05/20"/>
<Order Number="1296" ShipDate="2009/05/22"/>
</NewDataTable>
</NewDataSet>
Dim DataTables = From NewDataTable In TestData...<NewDataTable> _
Select New ASNData With {.Field = NewDataTable.<Field>.Value, .Value = NewDataTable.<Val>.Value, _
.Orders = (From AnOrder In NewDataTable...<Order> _
Select New ASNData.Order With {.Number = AnOrder.@Number, .ShippingDate = Date.Parse(AnOrder.@ShipDate)}).ToList}
Console.WriteLine(DataTables.Count)
Console.ReadLine()
End Sub
Public Class ASNData
Private _field As String
Private _value As String
Private _orders As List(Of Order)
Public Property Field()
Get
Return _field
End Get
Set(ByVal value)
_field = value
End Set
End Property
Public Property Value() As String
Get
Return _value
End Get
Set(ByVal value As String)
_value = value
End Set
End Property
Public Property Orders() As List(Of Order)
Get
Return _orders
End Get
Set(ByVal value As List(Of Order))
_orders = value
End Set
End Property
Structure Order
Private _number As String
Private _date As Date
Public Property Number() As String
Get
Return _number
End Get
Set(ByVal value As String)
_number = value
End Set
End Property
Public Property ShippingDate() As Date
Get
Return _date
End Get
Set(ByVal value As Date)
_date = value
End Set
End Property
End Structure
End Class
End Module
Upvotes: 4
Reputation: 1502396
To get order elements (from a NewDataTable
element), you'd use
newDataTableElement.Elements("Order")
which will return an IEnumerable<XElement>
- you can then use Select
to transform each one as normal. To get the attributes, use:
element.Attribute("Number").Value
element.Attribute("ShipDate").Value
That will give the value to use as string - you can get XAttribute
to do the conversions for you though:
CType(element.Attribute("Number"), Integer)
CType(element.Attribute("ShipDate"), DateTime)
I'm not 100% that that will work for your dates, because it may expect a full date and time - worth a try though. Otherwise, just parse the string using DateTime.ParseExact
.
I would strongly recommend that you reconsider Order
being a structure though - particularly a mutable structure. Any reason for making it a structure rather than a class?
Upvotes: 0
Reputation: 7172
var result = from order in YourXMLVar.Descendants("NewDataTable")
.First().Elements("Order") select order;
This should give you an Array of Orders.
Then you should be able to do something like:
foreach(var order in result)
{
int someVal = Convert.ToInt32(order.Attribute("Number").Value);
}
// EDIT: Obviously, you wouldn't use First(), but instead would iterate through your orders or whatever your logic dictates. I used First() because it made for an easy demo.
Upvotes: -1