简体   繁体   中英

How to ignore a specific with a LINQ where clause?

I have a client that sends an xml feed which I parse using the following code. This code works.

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")
                          };

After getting all my "reviews" I cast the IEnumerable as a List and return it out. Originally, I was having a good and easy time parsing their XML which used to look like this:

<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>

They have, however, changed their schema, to which I don't have access, and now their XML is adding in a final <node> tag to the end which does not contain the decedent elements I am looking for, and so, my parsing breaks on this last tag and I throw an exception. Here is an example:

<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>

I need to know if there is a way to ignore this final tag (its always at the end of the document) even though it has the same name as all the other "node" tags I am looking for. I do have a try catch around this block of code but it doesnt return the list of good reviews out if it sees this error.

Thanks guys.

If it's always the last node,

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

Something like this should do the trick:

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")
};

You can additional null checks for the other elements if you wish.

add null checking

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

Always add null checking to everything you do. Just good practice. In this case, it will eliminiate this error, but potentially crop up an error later in your program where you assume these strings are not empty, so make sure and null-check later as well.

You could count the number of nodes and then use this overload of Where, which also passes an index number: (http://msdn.microsoft.com/en-us/library/bb549418.aspx)

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

So, something like this:

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

You could throw a "where" clause in there.

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")
                      };

This sample would just be checking for a child node called "Review", so it would be a better idea to check for all of your required child nodes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM