Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Using XDocument.Descendants with a coalesce operator ?? and nullable types

Compiler: Visual Studio 2019
Framework: .Net 2.1

Given a XML file like this:

<root>
  <data>
        <AdditionalOrderInfo>
            <AdditionalInfoItem key="{4567B566-A0A2-4214-B7E7-814FE179CDFC}" value="ScanItDental"/>
            <AdditionalInfoItem key="GlobalOrderID" value="EDC531BE6A0D4DC5BFEA0C6081D9F26B"/>
            <AdditionalInfoItem key="CreatedIn" value="2.20.1.2"/>
        </AdditionalOrderInfo>  
    </data>
</root>

I need to get AdditionalInfoItem only for certain key values.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

To avoid null errors I’m trying to use nullable types and coalesce operator ??

var additionalOrderInfo = document.Descendants(ns + "AdditionalOrderInfo").First();
var value = additionalOrderInfo.Descendants(ns + "AdditionalInfoItem")?.Where(el => el.Attribute("key").Value == "SomeKey")?.First()?.Attribute("value")?.Value ?? "";

But if key doesn’t exists it returns:

Sequence contains no elements.

I’ve ended using a foreach loop in this way:

var additionalOrderInfo = document.Descendants(ns + "AdditionalOrderInfo").First();
foreach (var item in additionalOrderInfo.Descendants(ns + "AdditionalInfoItem"))
{
    switch (item.Attribute("key").Value)
    {
        case "SomeKey1":
            Order.SomeKey1 = item.Attribute("value").Value;
            break;
        case "SomeKey2":
            Order.SomeKey2 = item.Attribute("value").Value;
            break;
    }
}

Is there a way to avoid the foreach loop and read the value using a single line of code?

>Solution :

Try use FirstOrDefault instead of First only after Where selector:

var value = additionalOrderInfo.Descendants(ns + "AdditionalInfoItem")?
                               .Where(el => el.Attribute("key").Value == "SomeKey")?
                               .FirstOrDefault()? // <--- Here
                               .Attribute("value")?.Value ?? "";

If Where(el => el?.Attribute("key")?.Value == "SomeKey") return 0 elements, you getting Sequence contains no elements exception, so you can’t get First element of it. FirstOrDefault returns null instead, so next nullcheck ? goes forward.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading