Reputation: 3
Very new to C# and Linq, lots to learn... I would like to be able to parse XML with Linq, and move a portion of the XML data into a List. The XML data is small, Initially (query 1 below) I was able to capture all nodes except the ACCT nodes. My 2nd attempt was to create a 2nd query (ACCT query below) but it only successfully captures the 1st occurrence of ACCT . searched for some time, found several examples but I have not been successful in implementing way to capture all occurrences of ACCT with Linq and c#. Seems like a VERY useful tool, any assistance would be appreciated.
here is XML
<?xml version="1.0" encoding="utf-8"?>
<ORDER>
<EMPNUMBER>LDC</EMPNUMBER>
<ITEMNAME>NEWNAME_GR0045LDS01.JPG</ITEMNAME>
<DATETIMESTAMP>04-19-2015</DATETIMESTAMP>
<DEPT>HMES</DEPT>
<SHIPMENTLIST>
<ACCT>2222222222</ACCT>
<ACCT>1111111111</ACCT>
</SHIPMENTLIST>
</ORDER>
here is current class
public class clsShipACCT
{
public string strShipACCT
{
get;
set;
}
}
here is logic(commented out items show failed attempts list)
//this gets all xml details except account(ACCT)
var query1 = from item in xDoc.Descendants("ORDER") // xDoc.Elements() //xDoc.Descendants("ORDER") // xDoc.Root.Elements("ORDER")
select new
{
EmpNum = item.Element("EMPNUMBER").Value,
ItemName = item.Element("ITEMNAME").Value,
OrderDate = Convert.ToDateTime(item.Element("DATETIMESTAMP").Value),
};
//attempt to get ACCT detail
var Acctlist = from P in xDoc.Root.Descendants("SHIPMENTLIST")
select new { b = P.Element("ACCT").Value };
foreach(var p in ACCTlist)
ACCTgram.WriteLog("Parsed XML Acct: " + p);
//failed attempt to capture ACCT in list:
// List<clShipACCT> testList = ACCTlist.ToList<clShipACCT>();
//////var ACCTlist = (from P in xDoc.Descendants("SHIPMENTLIST")
////// select new clShipACCT { strShipACCT = childitem.Element("ACCT").Value }).ToList();
//////testShipACCTList.AddRange(ACCTlist);
Upvotes: 0
Views: 748
Reputation: 152
//this works in LinqPad...Elements() return multiple instances...
void Main()
{
XDocument doc= XDocument.Load(@"d:\test2.xml");
var orders = doc.Root.Elements("ORDER")
.Select (o => new Order
{
EmpNumber=o.Element("EMPNUMBER").Value,
ItemName=o.Element("ITEMNAME").Value,
TimeStamp=o.Element("DATETIMESTAMP").Value,
Shipments=o.Element("SHIPMENTLIST").Elements("ACCT").Select (e => new Shipment{Account= e.Value}).ToList()
}
);
orders.Dump();
}
class Order
{
public Order ()
{
this.Shipments=new List<Shipment>();
}
public string EmpNumber { get; set; }
public string ItemName { get; set; }
public string TimeStamp { get; set; } //should be date time
public string Department { get; set; }
public List<Shipment> Shipments { get; set; }
}
class Shipment
{
public string Account { get; set; }
}
I assumed the following xml: added ORDERS as the root element since one order in xml is really trivial...
Upvotes: 0
Reputation: 32455
Use .Elements
method - this method return all elements with given name
.Element
method will return only first element
var shipments = xDoc.Root.Descendants("SHIPMENTLIST")
List<String> acctList = new List<String>();
foreach(var accts in shipments)
{
acctList.AddRange(accts.Elements("ACCT").Select(acct => acct.Value));
}
foreach(string acct in acctlist)
ACCTgram.WriteLog("Parsed XML Acct: " + acct);
Upvotes: 1
Reputation: 11955
You are very close, just add your accounts search to your first query and generic object creation.
Change this to be:
var query1 = from item in xDoc.Descendants("ORDER") // xDoc.Elements() //xDoc.Descendants("ORDER") // xDoc.Root.Elements("ORDER")
select new
{
EmpNum = item.Element("EMPNUMBER").Value,
ItemName = item.Element("ITEMNAME").Value,
OrderDate = Convert.ToDateTime(item.Element("DATETIMESTAMP").Value),
Accts = item.Element("SHIPMENTLIST").Elements("ACCT").Select(x => x.Value).ToList()
};
Upvotes: 0
Reputation: 1472
var result = xDoc.Root.Element("SHIPMENTLIST").Elements("ACCT").Select(x => x.Value).ToList();
Using the xml in the post, this should yield a
List<string>
of the values in the ACCT fields.
Upvotes: 0