I have an object like this:
public class ClientCredentials
{
public string UserName { get; set; }
public string Password { get; set; }
public string Rights { get; set; }
}
and an xml looking like this:
<?xml version="1.0" encoding="utf-8" ?>
<users>
<user>
<username>playerone</username>
<password>654321</password>
<rights>true</rights>
</user>
<user>
<username>amoreroma</username>
<password>123456789</password>
<rights>false</rights>
</user>
</users>
I just want to generate a List of ClientCredentials objects after LINQ to the given XML
I tried like this:
XDocument document = XDocument.Load(@"path\to\file\file.xml");
var query = document.Descendants("users").Select(s => new ClientCredentials
{
UserName = s.Element("username").Value,
Password = s.Element("password").Value,
Rights = s.Element("rights").Value
}).ToList();
but I get the error Reference not set to an instance of an object.
You need Descendants("user")
instead of Descendants("users")
. Your username
,password
and rights
elements are child element of your user
elements. not Users
element.That's why you are getting NullReferenceException.
Also you can use the explicit cast to avoid NullReferenceException
.If any element can't be found your code will still throw exception because you are accessing Value
property directly.
var query = document.Descendants("user").Select(s => new ClientCredentials
{
UserName = (string)s.Element("username"),
Password = (string)s.Element("password"),
Rights = (string)s.Element("rights")
}).ToList();
Here is a LINQ query that is expressed using query syntax. And rather than making use of the Descendants()
method, the query incorporates a direct path to the elements of interest via Root.Elements("user")
:
var query =
from el in document.Root.Elements("user")
select new ClientCredentials
{
UserName = (string)el.Element("username"),
Password = (string)el.Element("password"),
Rights = (string)el.Element("rights")
};
To demonstrate this query, I created a program with the sample XML data that you supplied. Also, you asked whether a missing element would generate an exception. As @Selman22 indicated, you can avoid an exception from a missing element by dropping the .Value
property and using the (string)
cast. Doing so will result in a empty string being returned for a missing element. To show this, I added a third <user>
element and omitted its <rights>
child element.
Please see below for the formatted output from my demonstration program followed by the program itself.
Demonstration Program Output
UserName:[playerone]
Password:[654321]
Rights:[true]
--
UserName:[amoreroma]
Password:[123456789]
Rights:[false]
--
UserName:[norights]
Password:[20140215]
Rights:[]
--
Demonstration Program
Note that I dropped ToList()
at the end of the query expression since it isn't needed here. (This means that query
is simply IEnumerable
.)
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
class ClientCredentialsDemo
{
static public void Main(string[] args)
{
XDocument document = XDocument.Parse(GetXml());
var query =
from el in document.Root.Elements("user")
select new ClientCredentials
{
UserName = (string)el.Element("username"),
Password = (string)el.Element("password"),
Rights = (string)el.Element("rights")
};
foreach (var cc in query)
{
Console.WriteLine
("UserName:[{0}]\nPassword:[{1}]\nRights:[{2}]\n--",
cc.UserName,
cc.Password,
cc.Rights);
}
}
static string GetXml()
{
return
@"<?xml version='1.0' encoding='utf-8' ?>
<users>
<user>
<username>playerone</username>
<password>654321</password>
<rights>true</rights>
</user>
<user>
<username>amoreroma</username>
<password>123456789</password>
<rights>false</rights>
</user>
<user>
<username>norights</username>
<password>20140215</password>
</user>
</users>";
}
}
public class ClientCredentials
{
public string UserName { get; set; }
public string Password { get; set; }
public string Rights { get; set; }
}