Reputation: 41
I am having trouble with C#, trying to filter the contents of an XML file.
I want to remove items from a list of XML entries, based on whether those items match items found in a second list of XML entries, and return that filtered list as a new list of entries that I can iterate through and do things with.
I'm trying to do this with the .Except()
function, because it seems tailor-made for this purpose. The examples given at MSDN seem to indicate that this is precisely what the function was made to do.
However it is not working and I can't find an elegant solution. I know that I could manually iterate through the second list each time I try to act upon one of its items, but that is inelegant and makes the code hard to read.
Here is a simplified example of my code that is not working.
First, an example XML file:
<?xml version="1.0" encoding="utf-8"?>
<MyTest version="1.0">
<Validation>
<Manifest>
<VerifyItems SinceVersion="1.5">
<Item Type="File" Uninstalled="True" Location="%ProgramData%\MyData" >MyFirstFile.dat</Item>
<Item Type="File" Uninstalled="True" Location="%ProgramData%\MyData" >MySecondFile.dat</Item>
<Item Type="Folder" Uninstalled="True" Location="%ProgramData%\MyData" >MyFirstFolder</Item>
<Item Type="Folder" Uninstalled="True" Location="%ProgramData%\MyData" >MySecondFolder</Item>
</VerifyItems>
<VerifyItems SinceVersion="2.1">
<Item Type="File" Uninstalled="True" Location="%ProgramData%\MyData" >aNewerFile.dat</Item>
<Item Type="Folder" Uninstalled="True" Location="%ProgramData%\MyData" >aNewerFolder</Item>
</VerifyItems>
<RemovedItems SinceVersion="2.1">
<Item Type="Folder" Uninstalled="True" Location="%ProgramData%\MyData" >MyFirstFolder</Item>
<Item Type="Folder" Uninstalled="True" Location="%ProgramData%\MyData" >MySecondFolder</Item>
</RemovedItems>
</Manifest>
</Validation>
</MyTest>
Here is an example of the C# code that I want to use but which is not working:
// Among other Using statements, I have these up at the top.
using System.Xml.Linq;
using System.Xml.XPath;
// Load the XML file into memory.
XElement XMLFileContents = XElement.Load("MyXMLFile");
// The following statement retrieves all "Verify" items for all versions,
// since the product version cited in the query is newer than everything
// in the file. Total of 6 items.
IEnumerable<XElement> PresentItemResults = XMLFileContents.XPathSelectElements("//VerifyItems[@SinceVersion<=2.20]/Item");
// The following statement retrieves all "Removed" items for all versions,
// total of 2 items. These items both match items already extant in the
// "Verify" list.
IEnumerable<XElement> RemovedItemResults = XMLFileContents.XPathSelectElements("//RemovedItems[@SinceVersion<=2.20]/Item");
// Attempt to create a third list which, in theory, should be only four
// items long, filtering out the two items in the "Removed" list from
// the six items in the "Verify" list. It looks like the "Except()" function
// should do what I want.
IEnumerable<XElement> FilteredItemResults = PresentItemResults.Except(RemovedItemResults);
// However it does not remove the items. The output from below
// is 6 2 6, not 6 2 4 like I'd hoped.
Console.WriteLine(PresentItemResults.Count().ToString());
Console.WriteLine(RemovedItemResults.Count().ToString());
Console.WriteLine(FilteredItemResults.Count().ToString());
// I want to put code here that works with the contents of FilteredItemResults.
// However I am not getting a filtered list.
I suspect that it's possibly not working because the elements in the second list have different parents and siblings than the elements in the first list, thus, the equality function considers them different because of that little technicality.
But I don't care about the parents and siblings, I just want one list filtered out of the other list based on each item's attributes and values. When I act upon these items, I only care about the attributes and values, not where in the XML tree I got them from.
Can anyone help me figure out how to make this work in a simple and elegant way?
Upvotes: 2
Views: 314
Reputation: 156624
But I don't care about the parents and siblings, I just want one list filtered out of the other list based on each item's attributes and values...
You should be able to call the overload of Except
that takes an IEqualityComparer<>
to tell it this.
Upvotes: 1