LINQ type expected

have the following linq code trying to parse the xml file into a datatable, but I get weird values ​​in the resulting datatable all the cell values ​​are displayed as

System.Xml.Ling.XContainer+<GetElements>d_11 

Here is my LINQ

  XDocument doc1 = XDocument.Load(@"D:\m.xml"); var q = from address in doc1.Root.Elements("Address") let name = address.Elements("Name") let street = address.Elements("Street") let city = address.Elements("city") select new { Name = name, Street = street, City = city }; var xdt = new DataTable(); xdt.Columns.Add("Name", typeof(string)); xdt.Columns.Add("Street", typeof(string)); xdt.Columns.Add("City", typeof(string)); foreach (var address in q) { xdt.Rows.Add(address.Name, address.Street, address.City); } dataGrid1.ItemsSource = xdt.DefaultView; 

here is my xml:

 <PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20"> <Address Type="Shipping"> <Name>Ellen Adams</Name> <Street>123 Maple Street</Street> <City>Mill Valley</City> <State>CA</State> <Zip>10999</Zip> <Country>USA</Country> </Address> <Address Type="Billing"> <Name>Tai Yee</Name> <Street>8 Oak Avenue</Street> <City>Old Town</City> <State>PA</State> <Zip>95819</Zip> <Country>USA</Country> </Address> </PurchaseOrder> 

and here is the result that I get! enter image description here

+4
source share
7 answers

You forgot to restore the inner text of XElements. This way you select the whole element with attributes, etc. Use this piece of code:

 var q = from address in doc1.Root.Elements("Address") let name = address.Element("Name") let street = address.Element("Street") let city = address.Element("city") select new { Name = name.Value, Street = street.Value, City = city.Value }; 
+5
source

address.Elements("Name") is the collection of all elements of the "Name" type. It so happened that in your case this is a collection of size one, but this is still a collection. You want to get the first element from this collection (since you know that it will be the only one), and then get the text value of that element. If you use Element instead of Elements , you will get the first element that matches, not a set of elements.

Now that you have your only element, you also need to get the value of this element, not the element itself (which also contains a lot of other information in the general case, although there really is nothing interesting about this in this particular case.

 var q = from address in doc1.Root.Elements("Address") select new { Name = address.Element("Name").Value, Street = address.Element("Street").Value, City = address.Element("City").Value }; 
+4
source

How does it work for you?

  var q = from address in doc1.Root.Elements("Address") let name = (string)(address.Element("Name")) let street = (string)(address.Element("Street")) let city = (string)(address.Element("city")) //... 

http://msdn.microsoft.com/en-us/library/bb155263.aspx

+1
source

You call Elements , which returns n elements wrapped in a helper class.

You probably want to call Element , which returns the first element as an XElement .

+1
source

Try the following:

 var q = from address in doc1.Root.Elements("Address") let name = address.Element("Name").Value let street = address.Element("Street").Value let city = address.Element("City").Value 
+1
source

Change address.Elements("Name") to address.Elements("Name").FirstOrDefault() , etc.

+1
source

The Elements method returns IEnumerable. Therefore, your let variables point to a sequence of elements, not a single element. You must take the returned single element, which will be an XElement, and then take its Value property to get the concatenated text of its contents. (According to the documentation)

Instead

 select new { Name = name, Street = street, City = city } 

You must write:

 select new { Name = name.Single().Value, Street = street.Single().Value, City = city.Single().Value } 

Either there, or directly in let expressions. You can also find a helper method:

 public static string StringValueOfElementNamed(XElement node, string elementName) { return node.Elements(elementName).Single().Value; } 

Turn this helper method into an extension method if you want to use membership access syntax.

Edit: After reading concurrent answers, the best way to use would be:

 public static string StringValueOfElementNamed(XElement node, string elementName) { return node.Element(elementName).Value; } 

The element returns the first element found. Beware of the returned null pointer when the item is not found.

+1
source

All Articles