LINQ to XML sin conocer los nodos

Tengo esta consulta LINQ:

XNamespace ns = NAMESPACE;

var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
     Title = c.Element(ns + "ItemAttributes").Element(ns + "Title").Value,
     MFR = c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
     Offer = c.Element(ns + "Offers").Element(ns + "TotalOffers").Value,
     Amazon = c.Element(ns + "Offer").Element(ns + "Merchant").Elements(ns + "MerchantId"),
     LowPrice = Convert.ToDouble(c.Element(ns + "FormattedPrice").Value),
     SalesRank = Convert.ToInt32(c.Element(ns +"SalesRank").Value),
     ASIN = c.Element(ns + "ASIN").Value
}).ToList<Item>();

Funciona muy bien cuando no hay un nodo presente. Por ejemplo, no puede tener un MFR o un rango de ventas. ¿Cómo puedo hacer que si no tiene el nodo en cuestión, me da un valor predeterminado o no me hace intentar capturar toda mi consulta para un elemento?

preguntado el 08 de noviembre de 11 a las 19:11

3 Respuestas

Hasta donde yo sé, LINQ to XML no es compatible con esto. Sin embargo, me encontré con el mismo lío en un proyecto en el que estaba trabajando y creé esta extensión para que XElement lo permitiera. Quizás podría funcionar para ti:

public static XElement ElementOrDummy(this XElement parentElement, 
                                      XName name, 
                                      bool ignoreCase)
{
    XElement existingElement = null;

    if (ignoreCase)
    {
        string sName = name.LocalName.ToLower();

        foreach (var child in parentElement.Elements())
        {
            if (child.Name.LocalName.ToLower() == sName)
            {
                existingElement = child;
                break;
            }
        }
    }
    else
        existingElement = parentElement.Element(name);

    if (existingElement == null)
        existingElement = new XElement(name, string.Empty);

    return existingElement;

}

Básicamente, solo verifica si el elemento existe y, si no lo hace, devuelve uno con el mismo nombre y un valor vacío.

respondido 08 nov., 11:23

Lo siento, el fragmento de código original que publiqué estaba incompleto. He editado en la extensión completa. - Mel Green

Me cambio a existingElement = new XElement(name, string.Empty); a existingElement = new XElement(name, "0"); ¡y funciona muy bien para mis necesidades! - Joe Tyman

Puede utilizar la conversión explícita de XElement, por ejemplo:

(int?)c.Element(ns +"SalesRank")

Referencia: http://msdn.microsoft.com/en-us/library/bb340386.aspx

respondido 08 nov., 11:23

si el problema de que el XElement existe, pero el valor está en blanco? es decir

<Item>
 <ItemAttributes>
    <Manufacturer></Manufacturer>
  </ItemAttributes>
</Item>

entonces puedes usar la función string.IsNullOrEmpty

XNamespace ns = NAMESPACE;

var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
     MFR = if (string.IsNullOrEmpty(c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value)) ? "default value here" : c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
    // omitted for brevity
}).ToList<Item>();

respondido 08 nov., 11:23

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.