I have an xml file from which I go get ID
s from certain nodes. The nodes have the following structure:
<Bistot ID="1223"/>
<Compressed_Bistot ID="28388"/>
<Compressed_Monoclinic_Bistot ID="28389"/>
...
They are also at different levels in my xml file (it is too big to list it all here).
In order to do this, I use a function that executes a LINQ query:
public String GetItemName(uint id)
{
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => x.Attributes().Any(a => a.Name.LocalName == "ID") && uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value) == id)
.Select(t => t.Name.LocalName);
return names.ElementAt(0);
}
In this form, it works well if the id
I provide exists and the names
variable actually has an entry. If it doesn't though, it raises an exception at return names.ElementAt(0);
because there is no elements at index 0
. At this point, in debug mode, if I go check the variable names
, I do see it mentioned that Input string was not in a correct format
, but no error is raised and the function returns the good name
associated to id
.
I have also tried the following form in order to remove the exception that occurs if the LINQ request doesn't find any associated names in the xml file:
public String GetItemName(uint id)
{
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => x.Attributes().Any(a => a.Name.LocalName == "ID") && uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value) == id)
.Select(t => t.Name.LocalName);
if (names.Count() != 0) // Error raised here
{
return names.ElementAt(0);
}
else
{
return "";
}
}
This is where my problem occurs, since in this case, when I call names.Count()
, the Input string was not in a correct format
(of type FormatException
) error is raised and my application then does not continue/complete.
I have also tried to call .ToList()
at the end of my LINQ query as I had a warning telling me to do so. But in this case, the Input string was not in a correct format
error is raised inside my LINQ query directly, and not at the names.Count()
call.
I do understand the nature of this error, something is not getting parsed right when I call uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value)
inside my LINQ query, but I don't understand why for two reasons:
I have manually checked and each values in the ID
attribute in my xml file are real uint
(just numbers, no spaces, etc).
When not using names.Count()
or .ToList()
, while it does mention the error in debug mode when I look at the variable, the name associated to the id
is still found and the function returns it properly.
Why is my uint.Parse(...)
giving me troubles here?
The issue is that when you use ElementAt(0)
, it only needs to find the first element - so if there's an ID
element later with an invalid value (which I'm sure there is), you're not going to hit it. When you call Count()
or ToList()
, it iterates over the whole of the query, causing the problem.
As it is, your code is very inefficient though, evaluating multiple times - it would be much better written as:
public String GetItemName(uint id)
{
IEnumerable<String> names = ...; // Query as before
return names.FirstOrDefault() ?? "";
}
I'd also recommend using the explicit conversions provided by LINQ to XML instead of manually calling uint.Parse
, too:
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => (uint?) x.Attributes()
.Where(a => a.Name.LocalName == "ID")
.FirstOrDefault() == id)
.Select(t => t.Name.LocalName);
Here we're finding the first ID
attribute, converting it to uint?
(giving null
if there's no such attribute) and then comparing that with id
.
See more on this question at Stackoverflow