1

I am writing a linq query to return an IEnumerable of XElements that match the search criteria.

The program throws an exception when an element matching the search criteria isn't found and including the statement inside a try/catch block doesn't catch the exception.

Thoughts on the correct way to catch the exception?

try
{
    IEnumerable<XElement> oFootnotes = oRoot.DescendantNodes().OfType<XElement>().Where(x => x.Name == "p" && x.Attribute("class").Value == "endnote" && x.Attribute("id").Value == idFootnote);
}
catch(Exception ex)
{
}
dbc
  • 104,963
  • 20
  • 228
  • 340
  • You could probably use `.FirstOrNull` instead of `.Where` to avoid the exception altogether – Pawel Dec 28 '22 at 17:57
  • What exactly is the exception? Is it a null reference exception? If so, the problem may be that the attributes aren't found. If so, use the [null conditional operator `?.`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) to access the value, e.g. `x.Attribute("class")?.Value == "endnote"`. If that doesn't solve the problem, might you please include a [mcve] with an XML sample + complete code that demonstrates the problem? – dbc Dec 28 '22 at 18:24
  • Correct, the XML source is missing some footnotes, which is why the query fails when it can't find an element with a matching footnote ID. – Martin R. Smith Dec 28 '22 at 18:28
  • Using the ?? operator to return null when a match isn't found solved the problem. I wasn't aware of that syntax. Thanks. – Martin R. Smith Dec 28 '22 at 18:30

1 Answers1

0

Enumerable.Where() will not throw an exception when an element matching the search criteria isn't found. It will simply return an empty enumerable.

You have two possible problems:

  1. You have some elements that are missing the attributes "id" or "class".

    To resolve this, use null conditional operator ?. to access their value:

    .Where(x => x.Name == "p" && x.Attribute("class")?.Value == "endnote" && x.Attribute("id")?.Value == idFootnote);
    
  2. Somewhere outside the code shown, you are getting the first element of the enumerable by using Enumerable.First().

    To fix this, use Enumerable.FirstOrDefault() instead, and check for a null return.

Thus your fixed query might look like:

var oFootnotes = oRoot.Descendants().Where(x => x.Name == "p" && x.Attribute("class")?.Value == "endnote" && x.Attribute("id")?.Value == idFootnote);

string firstFootnoteText = oFootnotes.FirstOrDefault()?.Value ?? ""; // If you want you can return the empty string in preference to the null string using the null-coalescing operator ??

Using Descendants() to find all descendant elements of an XElement is equivalent to, but more concise than, DescendantNodes().OfType<XElement>().

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340