Amicable
Amicable

Reputation: 3091

Foreach Iteration Null

I am using LINQ to filter the XmlNode returned from Sharepoint WSS3's listService.GetListItems() method.

This is the XML it returns: http://pastebin.com/mqHcserY

I observed that the last row is different to the others, it does not contain the following attributes.

ows_ContentType
ows_LinkFilenameNoMenu
ows_LinkFilename
ows_BaseName 
ows__EditMenuTableStart

So bearing this in mind I filter the results with LINQ:

XmlNode items = listService.GetListItems(listName, string.Empty, query, viewFields, string.Empty, queryOptions, g.ToString());

// Namespace for z: prefix
XNamespace xns = "#RowsetSchema";

XElement root;
using (XmlReader xr = new XmlNodeReader(items)) { root = XElement.Load(xr); }

// This query returns XElements that are Folder types
IEnumerable<XElement> result = from child in root.Descendants(xns + "row")
                               where child.Attribute("ows_ContentType").Value != null && child.Attribute("ows_ContentType").Value == "Folder"
                               select child;

foreach (XElement xml in result)
{
    //Exception when attempts to loop final XElement
}

However when I iterate through the results I get a NullReferenceException. In a Foreach loop it will happily iterate through every object until it gets to the last one, then it will throw an exception.

This last object is the one that differs from the other rows (I know this through process of elimination, I saw every other row get looped past) and should have been filtered out of my results as it does not have the "ows_ContentType" attribute.

I changed my LINQ to where child.Attribute("ows_ContentType").Value != null && child.Attribute("ows_ContentType").Value == "Folder" in attempt to filter anything that would contain a null value but I have the same results. I have looked at a few samples and I appear to have the correct syntax.

Could someone please explain what is causing this last XElement to return null? I really don't understand why it would add a null instance to the <IEnumerable<XElement> result collection.

Upvotes: 3

Views: 1608

Answers (4)

Binary Worrier
Binary Worrier

Reputation: 51711

The last node doesn't contain an "ows_ContentType" attribute, but your where clause is looking for the value of that missing attribute.

Possibly you need

where child.Attribute("ows_ContentType") != null 
&& child.Attribute("ows_ContentType").Value == "Folder"

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167571

Note that LINQ2XML simply allows you to use (string)someXElement and (string)someXAttribute which will give null if the XElement or XAttribute is null or the Value of the XElement or XAttribute if it exists. That means you code can be shortened to use

IEnumerable<XElement> result = from child in root.Descendants(xns + "row")
                               where (string)child.Attribute("ows_ContentType") == "Folder"
                               select child;

Upvotes: 1

middelpat
middelpat

Reputation: 2585

Calling the value of a non existing attribute will cause a nullreference because the node simply doesn't exist.

child.Attribute("ows_ContentType").Value

throws an exception by calling the value of the missing element.

use this instead:

child.Attribute("ows_ContentType") != null

implemented:

IEnumerable<XElement> result = from child in root.Descendants(xns + "row")
                           where child.Attribute("ows_ContentType") != null && child.Attribute("ows_ContentType").Value == "Folder"
                           select child;

Upvotes: 3

RobH
RobH

Reputation: 3612

You need to check whether the element is null NOT the value of the element.

child.Attribute("ows_ContentType") != null && child.Attribute("ows_ContentType").Value == "Folder"

Upvotes: 2

Related Questions