2

A snippet of the XML im querying is

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <metadata created="2014-11-03T18:13:02.769Z" xmlns="http://example.com/ns/mmd-2.0#" xmlns:ext="http://example.com/ns/ext#-2.0"> <customer-list count="112" offset="0"> <customer id="5f6ab597-f57a-40da-be9e-adad48708203" type="Person" ext:score="100"> <name>Bobby Smith</name> <gender>male</gender> <country>US</country> <birth-span> <start>1965-02-18</start> <end>false</end> </birth-span> 

The code im writing to get the elements is

 GetCustomer = from c in XDoc.Descendants(ns + "customer") select new Customer { Name = c.Element(ns + "name").ToString(), Gender = Convert.ToString(c.Element(ns + "gender")), BeginDate = c.Elements("birth-span").Any() ? c.Element("start").Value.ToString() : "No data found" 

The problem i have is with birth-span, i never seem to get the value if birth-span exists (there are some records which do not contain the birth-span element). For the records that do contain the birth-span element i have added the namespace variable which doesnt work (throws the error that object is not set to an instance)

 BeginDate = c.Elements(ns + "birth-span").Any() ? c.Element(ns + "start").Value.ToString() : "No data found" 

Ive added different variations but either i get the value No Data found OR an error (Seems to be object not set to an instance). Can anyone see what im doing wrong?

1 Answer 1

4

You're treating start as a direct descendant of c (or customer) by doing this:

BeginDate = c.Elements("birth-span").Any() ? c.Element("start").Value.ToString() : "No data found" 

When you actually want to do treat start as a direct descendant of the birth-span element like so:

BeginDate = c.Elements("birth-span").Any() ? c.Element("birth-span").Element("start").Value.ToString() : "No data found" 

There's room for improvement though. Is there either zero or one birth-span element, or zero or many? As it seems like it's zero or one, you could do this and make it a little clearer:

var customers = from c in doc.Descendants("customer") let birthSpan = c.Element("birth-span") select new { Name = c.Element("name").Value, Gender = c.Element("gender").Value, BeginDate = birthSpan == null ? "No data found" : birthSpan.Element("start").Value }; 

Also, there's no need to call Convert.ToString or .ToString() on any of these. If you want a string, .Value() will do. If you actually want it typed to something else, directly cast it and let the conversion operators do the work:

var customers = from c in doc.Root.Descendants("customer") let birthSpan = c.Element("birth-span") select new { Name = (string)c.Element("name"), Gender = (string)c.Element("gender"), BeginDate = birthSpan == null ? (DateTime?)null : (DateTime?)birthSpan.Element("start") }; 

There's a great article about that here.

Sign up to request clarification or add additional context in comments.

3 Comments

Namespace to be included ...(ns+"customer")
Thanks - very helpful. Before going into the advanced theories i tried getting the basic way to work first by using this code BeginDate = c.Elements("birth-span").Any() ? c.Element("birth-span").Element("start").Value.ToString() : "No data found" but still this returns "No data found"?
Did you re-add the ns+ as @Thirisangu suggests? I removed them to try to simplify, but they will still be necessary in your code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.