LINQ to XML consulta elemento opcional
-
07-07-2019 - |
Pergunta
Eu estou trabalhando com um documento XML existente, que tem uma estrutura (em parte) assim:
<Group>
<Entry>
<Name> Bob </Name>
<ID> 1 </ID>
</Entry>
<Entry>
<Name> Larry </Name>
</Entry>
</Group>
Eu estou usando LINQ to XML para consultar o XDocument para recuperar todas essas entradas da seguinte maneira:
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"
};
Os elementos "ID" não são sempre lá e por isso a minha solução para este foi o Count () jazz acima. Mas eu estou querendo saber se alguém tem uma maneira melhor de fazer isso. Ainda estou ficando confortável com este material novo e eu suspeito que pode haver uma maneira melhor de fazer isso do que como atualmente estou fazendo isso.
Existe uma maneira melhor / mais preferido para fazer o que eu quero?
Solução
XElement tem realmente operadores de conversão explícita interessantes que fazer a coisa certa no neste caso.
Assim, você raramente realmente precisa de acesso a propriedade .Value
.
Este é tudo que você precisa para a sua projeção:
var items =
from g in xDocument.Root.Descendants("Group").Elements("Entry")
select new
{
name = (string) g.Element("Name"),
id = (string) g.Element("ID") ?? "none",
};
E se você preferir usar o valor de ID
como um inteiro em seu tipo anônimo:
var items =
from g in xDocument.Root.Descendants("Group").Elements("Entry")
select new
{
name = (string) g.Element("Name"),
id = (int?) g.Element("ID"),
};
Outras dicas
Em uma situação semelhante que eu usei um método de extensão:
public static string OptionalElement(this XElement actionElement, string elementName)
{
var element = actionElement.Element(elementName);
return (element != null) ? element.Value : null;
}
uso:
id = g.OptionalElement("ID") ?? "none"
Como sobre: ??
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;
};
Se este Barfs, então FirstOrDefault()
etc pode ser útil, caso contrário basta usar um método de extensão (como já foi sugerido).