Запрос необязательного элемента LINQ to XML

Я работаю с существующим документом XML, который имеет структуру (частично) следующим образом:

<Group>
    <Entry>
        <Name> Bob </Name>
        <ID> 1 </ID>
    </Entry>
    <Entry>
        <Name> Larry </Name>
    </Entry>
</Group>

Я использую LINQ to XML для запроса XDocument для извлечения всех этих записей следующим образом:

var items = from g in xDocument.Root.Descendants("Group").Elements("Entry")
    select new
    {
        name = (string)g.element("Name").Value,
        id = g.Elements("ID").Count() > 0 ? (string)g.Element("ID").Value : "none"
    };

Элементы "ID" не всегда существуют, и поэтому я решил, что это был джаз Count(). Но мне интересно, есть ли у кого-то лучший способ сделать это. Мне все еще нравится этот новый материал, и я подозреваю, что может быть лучший способ сделать это, чем то, как я это делаю сейчас.

Есть ли лучший/более предпочтительный способ сделать то, что я хочу?

Ответы

Ответ 1

XElement фактически имеет интересные явные операторы преобразования которые делают в этом случае правильные вещи.

Итак, вам редко приходится обращаться к свойству .Value.

Это все, что вам нужно для вашей проекции:

var items =
    from g in xDocument.Root.Descendants("Group").Elements("Entry")
    select new
    {
        name = (string) g.Element("Name"),
        id = (string) g.Element("ID") ?? "none",
    };

И если вы предпочитаете использовать значение ID как целое число в вашем анонимном типе:

var items =
    from g in xDocument.Root.Descendants("Group").Elements("Entry")
    select new
    {
        name = (string) g.Element("Name"),
        id = (int?) g.Element("ID"),
    };

Ответ 2

В аналогичной ситуации я использовал метод расширения:

    public static string OptionalElement(this XElement actionElement, string elementName)
    {
        var element = actionElement.Element(elementName);
        return (element != null) ? element.Value : null;
    }

использование:

    id = g.OptionalElement("ID") ?? "none"

Ответ 3

Как насчет:

var items = from g in xDocument.Root.Descendants("Group").Elements("Entry")
            let idEl = g.Element("ID")
            select new
            {
                name = (string)g.element("Name").Value,
                id = idEl == null ? "none" : idEl.Value;
            };

если это barfs, тогда FirstOrDefault() и т.д. может быть полезно, иначе просто используйте метод расширения (как уже было предложено).