2012-02-06 14 views
5

Tengo un cliente que envía un feed xml que analizo utilizando el siguiente código. Este código funciona¿Cómo ignorar un específico con una cláusula LINQ where?

reviews = from item in xmlDoc.Descendants("node") 
          select new ForewordReview() 
          { 
           PubDate = (string)item.Element("created"), 
           Isbn = (string)item.Element("isbn"), 
           Summary = (string)item.Element("review") 
          }; 

Después de obtener todas mis "reseñas", echo el IEnumerable como una lista y lo devuelvo. Originalmente, estaba teniendo un momento bueno y fácil de analizar su XML que solía tener este aspecto:

<reviews> 
    <node> 
     <created>01-01-1900</created> 
     <ISBN>12345657890123</ISBN> 
     <Review>This is a nice and silly book</Review> 
    </node> 
    <node> 
     <created>01-01-2011</created> 
     <ISBN>1236245234554</ISBN> 
     <Review>This is a stupid book</Review> 
    </node> 
    <node> 
     <created>12-06-1942</created> 
     <ISBN>1234543234577</ISBN> 
     <Review>This is a old, naughty book</Review> 
    </node> 
</reviews> 

Han, sin embargo, cambió su esquema, a la que no tengo acceso, y ahora su XML es agregando una etiqueta final <node> al final que no contiene los elementos de fallecido que estoy buscando, y entonces, mi análisis se rompe en esta última etiqueta y arrojo una excepción. Aquí está un ejemplo:

<reviews> 
    <node> 
     <created>01-01-1900</created> 
     <ISBN>12345657890123</ISBN> 
     <Review>This is a nice and silly book</Review> 
    </node> 
    <node> 
     <created>01-01-2011</created> 
     <ISBN>1236245234554</ISBN> 
     <Review>This is a stupid book</Review> 
    </node> 
    <node> 
     <created>12-06-1942</created> 
     <ISBN>1234543234577</ISBN> 
     <Review>This is a old, naughty book</Review> 
    </node> 
    <node> 
     <count>4656</count> 
    </node> 
</reviews> 

Necesito saber si hay una manera de hacer caso omiso de esta etiqueta final (su siempre al final del documento) a pesar de que tiene el mismo nombre que los demás "nodo" etiquetas que estoy buscando. Tengo una captura de prueba alrededor de este bloque de código pero no devuelve la lista de buenas críticas si ve este error.

Gracias chicos.

+1

quizás agregue un 'where item.Element (" count ") == null' _ (o de otra manera round" created "!? = Null) _ – ordag

+0

@ordag De hecho, incorporé el suyo en mi solución junto con algunas comprobaciones nulas de la sugerencia delltrees. Gracias. –

Respuesta

1

añadir nula comprobación

PubDate = (string)(item.Element("created") ?? ""), 
Isbn = (string)(item.Element("isbn") ?? ""), 
Summary = (string)(item.Element("review") ?? "") 

añadir siempre vigilando nula a todo lo que haces. Solo una buena práctica. En este caso, eliminará este error, pero posiblemente surja un error más adelante en su programa en el que suponga que estas cadenas no están vacías, por lo tanto, asegúrese de que la verificación sea nula también más adelante.

+0

Entonces, si encuentra el nodo extraño, ¿cargará el pubdate, isbn y summary en un objeto y le dará a cada uno una cadena vacía? Definitivamente podría manejar eso aguas abajo, si ese es el caso. –

+0

exactamente. string.Empty puede ser una mejor opción, pero esto fue solo una grabación rápida – deltree

+0

@deltree: Creo que "" es más legible que string.Empty. –

4

Si es siempre el último nodo,

var nodes = xmlDoc.Descendants("node"); 
reviews = nodes.Take(nodes.Count() - 1).Select(...); 
+0

Siempre es el último "nodo" pero no el último elemento. El elemento "reviews" es el elemento raíz. ¿Eso importa? –

+0

@fullNelson: Esto tomaría todos los elementos llamados "nodo" excepto el último. ¿Leíste el código? –

+0

Lo leí. Nunca uso este estilo de sintaxis (ya que soy nuevo en linq) por lo que no sé cómo funciona esto. –

1

Se podría contar el número de nodos y luego utilizar esta sobrecarga de dónde, que también pasa un número de índice: (http://msdn.microsoft.com/en-us/library/bb549418.aspx)

public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, 
Func<TSource, int, bool> predicate) 

Por lo tanto, algo como esto:

var count = xmlDoc.Descendants("node").Count(); 
xmlDoc.Descendants("node").Where((node,index) => index < count-1).Select(..) 
+0

Para eso es 'Take '. –

+0

Estoy seguro de que sé lo que está sucediendo aquí, pero la diferencia en la sintaxis de mi código me desilusiona. Creo que lo que Matti y tú están usando es una notación de 'punto'. Para mí, no sé cómo agregar este filtro antes de la cláusula en una instrucción where. –

+0

@fullnelson Las mismas declaraciones se escriben/leen más fácilmente usando la sintaxis de linq y algunas se escriben/leen más fácilmente usando los métodos de extensión (como se indicó anteriormente). Es bueno saber que las sentencias linq se pueden traducir directamente a métodos de extensión. – MichaelvR

2

algo como esto debe hacer el truco:

var reviews = from item in xmlDoc.Descendants("node").Where(x => x.Element("created") != null) 
select new 
{ 
    PubDate = (string)item.Element("created"), 
    Isbn = (string)item.Element("isbn"), 
    Summary = (string)item.Element("review") 
}; 

Usted puede null adicionales para los otros elementos si lo desea.

0

Podría arrojar una cláusula "donde" allí.

reviews = from item in xmlDoc.Descendants("node") where item.Descendants().Any(n => n.Name == "Review") 
         select new ForewordReview() 
         { 
          PubDate = (string)item.Element("created"), 
          Isbn = (string)item.Element("isbn"), 
          Summary = (string)item.Element("review") 
         }; 

Esta muestra simplemente sería el registro de un nodo secundario llamado "opinión", por lo que sería una mejor idea para comprobar si todos los nodos secundarios necesarios.