I’ve been writing a slurry of code to return list item XML so that it can be parsed and consumed by AJAX components on the client side. Since Lists.asmx does not work in anonymous access scenarios, I’ve been creating many proxy .ashx Http Handlers installed in the LAYOUTS directory, to query via the object model and return the XML of the list items, using the .Xml property of a SPListItemCollection.
I had one particular scenario where I couldn’t pre-filter the items in the collection with an SPQuery object (too complicated a query for CAML), so I needed a way to filter the SPListItemCollection afterwards using C#, before returning the XML.
The SPListItemCollection offers the .Delete() and .DeleteItemById() methods, however they will commit the deletion back to SharePoint. I wanted to simply remove some items from the in-memory collection, not delete the items from the server. There was no way that I could see to remove items from an SPListItemCollection in memory only.
I looked into sub-classing or extending the SPListItemCollection class, but there is no public constructor in the base class, and no way to get at the logic behind the .Xml property without nasty reflection.
I ultimately ended up resorting to using Linq to XML to delete the rows directly from the returned XML, and then adjusted the ItemCount accordingly.
Here’s the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Get the list items from a list SPListItemCollection items = myList.GetItems(mySPQuery); // Get the xml of the list items itemXml = surveyItems.Xml; XNamespace z = "#RowsetSchema"; XDocument xdoc = XDocument.Parse(itemXml); IEnumerable<XElement> rows = xdoc.Root.Descendants(z + "row"); List<XElement> rowsToDelete = new List<XElement>(); foreach (XElement row in rows) { // Here is where you can test for a condition, and decide to remove a row if (row.Attribute("ows_Title").Value.Contains("Some string to filter on")) { rowsToDelete.Add(row); } } while (rowsToDelete.Count > 0) { // Update the parent row count int rowCount = Convert.ToInt32(rowsToDelete[0].Parent.Attribute("ItemCount").Value); rowsToDelete[0].Parent.Attribute("ItemCount").Value = (rowCount - 1).ToString(); rowsToDelete[0].Remove(); rowsToDelete.RemoveAt(0); } // Get the newly filtered xml itemXml = xdoc.ToString() |