Ivan-Mark Debono Ivan-Mark Debono - 27 days ago 5x
C# Question

Foreach not iterating through elements

I have an HTML document and I'm getting elements based on a class. Once I have them, I'm going through each element and get further elements:

var doc = new HtmlAgilityPack.HtmlDocument();

var rows = doc.DocumentNode.SelectNodes("//tr[contains(@class, 'row')]");
foreach (var row in rows)
var name = row.SelectSingleNode("//span[contains(@class, 'name')]").InnerText,
var surname = row.SelectSingleNode("//span[contains(@class, 'surname')]").InnerText,

customers.Add(new Customer(name, surname));

However, the above is iterating through the rows but the always retrieving the text of the first row.

Is the XPath wrong?


This is a FAQ in XPath. Whenever your XPath starts with /, it ignores context element (the element referenced by row variable in this case). It searches for matching elements starting from the root document node regardless of the context. That's why your SelectSingleNode() always return the same element which is the first matched element in the entire document.

You only need to prepend a dot (.) to make it relative to current context element :

foreach (var row in rows)
    var name = row.SelectSingleNode(".//span[contains(@class, 'name')]").InnerText,
    var surname = row.SelectSingleNode(".//span[contains(@class, 'surname')]").InnerText,

    customers.Add(new Customer(name, surname));