I want retrieve a list of unique customer Ids from a simple XML file (see below), using Task Parallel Library (TPL).
I use XPathNavigator to iterate through xml and retrieve customer Ids. I’m using an iterator with the Parallel.ForEach(..) for task parallelism.
For some reason I retrieve duplicated customer Ids. It almost seems like the iterator keeping track of previous reads/iteratoes. I’m expecting new iterator each time when I loop through.
I have tried number of ways still no luck. If someone can point me to the right direction it would be greatly appreciated.
(The attempted full code sample is below.)
Some simple XML:
private static string Xml()
{
return "<persons>" +
"<person><id>1</id></person>" +
"<person><id>2</id></person>" +
"<person><id>3</id></person>" +
"<person><id>4</id></person>" +
"<person><id>5</id></person>" +
"</persons>";
}
static void Main(string[] args)
{
var navigator = XmlHelper.CreateNavigator(Xml());
string xpath = "/persons/person";
var exp = navigator.Compile(xpath);
var iterator = navigator.Select(exp);
//Parallel Task scenario returns duplicated customer Ids
Parallel.ForEach(Iterate(iterator), (a) =>
{
string xpathId = "/person/id";
var value = XmlHelper.SelectString(a.Current, xpathId);
Console.WriteLine("person id: " + value);
});
/*
* Sample output can be: (notice the duplicated values!)
* person id: 2
* person id: 2
* person id: 4
* person id: 4
* person id: 3
* person id: 1
*
*/
//Sequential scenario displays unique values:
//while (iterator.MoveNext())
//{
// string xpathId = "/person/id";
// var value = XmlHelper.SelectString(iterator.Current, xpathId);
// Console.WriteLine("person id: " + value);
//}
Console.ReadLine();
}
private static IEnumerable<XPathNodeIterator>
Iterate(XPathNodeIterator iterator)
{
while (iterator.MoveNext())
{
yield return iterator;
}
}
public static class XmlHelper
{
public static string SelectString(XPathNavigator navigator, string xpath)
{
return SelectString(navigator, xpath, null);
}
public static string SelectString
(XPathNavigator navigator, string xpath, string defaultVal)
{
XPathExpression exp = navigator.Compile(xpath);
XPathNodeIterator it = navigator.Select(exp);
it.MoveNext();
return it.Current.Value;
}
public static XPathNavigator CreateNavigator(string input)
{
XPathDocument doc;
using (var reader = new StringReader(input))
{
doc = new XPathDocument(reader);
}
return doc.CreateNavigator();
}
}
Note I have also the approach take by this article still no luck. Any help greatly appreciated.