HTMLCollection not advancing enumerator

Hi,

so I have the following code:

    private void Test()
    {
        string htmlString = "<!DOCTYPE html>\r\n<html>\r\n<body>\r\n\r\n<h2>HTML Forms</h2>\r\n\r\n" +
                "<form action=\"/action_page.php\">\r\n  " +
                "<label for=\"fname\">First name:</label><br>\r\n  " +
                "<input type=\"text\" id=\"fname\" name=\"fname\" value=\"John\"><br>\r\n  " +
                "<label for=\"lname\">Last name:</label><br>\r\n  " +
                "<input type=\"text\" id=\"lname\" name=\"lname\" value=\"Doe\"><br>\r\n  " +
                "<label for=\"cars\">Choose a car:</label>\r\n\r\n" +
                "<select name=\"cars\" id=\"cars\">\r\n  " +
                "<option value=\"volvo\">Volvo</option>\r\n  " +
                "<option value=\"saab\">Saab</option>\r\n  " +
                "<option value=\"mercedes\">Mercedes</option>\r\n  " +
                "<option value=\"audi\">Audi</option>\r\n" +
                "</select><br><br>" +
                "<input type=\"submit\" value=\"Submit\">\r\n</form> \r\n\r\n\r\n" +
                "</body>\r\n</html>";

        using ( var htmlDoc = new HTMLDocument( htmlString, "" ) )
        {
            HTMLCollection inputs = htmlDoc.GetElementsByTagName( "input" );

            foreach ( Element input in inputs )
            {
                Debug.WriteLine( input.Id );
                Element div = htmlDoc.CreateElement( "div" );
                div.InnerHTML = ((HTMLInputElement)input).Value ?? string.Empty;
                Node parent = input.ParentElement;
                parent.InsertBefore( div, input );
                input.Remove(); 
            }
        }
    }

The output is

fname
fname

Then, of course, I get a null reference exception, at “parent.InsertBefore( div, input );”, because parent is null here, because input (the element with ID fname again) has already been removed from the DOM. That in turn is because the foreach loop does not provide the next item in the collection, but keeps delivering the first item.

Am I doing something wrong here? Or ist that a bug?

Thanks for your help in advance.

@jscharr

We are going to check it as it has been logged as task ID HTMLNET-4085 in our issue management system. We will check it and let you know once the ticket is resolved. Please give us little time.

@jscharr

The htmlDoc.GetElementsByTagName(“input”) method returns a live HTMLCollection that responds to changes in the DOM tree. Therefore, enumeration by it with simultaneous change of the DOM tree can lead to indefinite results. In order for the iteration to work correctly, you should convert this collection to an array, as shown in the following code snippet:

using (var htmlDoc = new HTMLDocument(htmlString, ""))
{
    HTMLCollection inputs = htmlDoc.GetElementsByTagName("input");

    foreach (Element input in inputs.ToArray())
    {
        Debug.WriteLine(input.Id);
        Element div = htmlDoc.CreateElement("div");
        div.InnerHTML = ((HTMLInputElement)input).Value ?? string.Empty;
        Node parent = input.ParentElement;
        parent.InsertBefore(div, input);
        input.Remove();
    }
}

Ah, I see, thank you. Maybe that could be mentioned in the reference :wink:.

@jscharr

We will surely update functions description in API references. It is an on going process and we keep improve our documentation. Thanks for your feedback. We will consider it as well.

The issues you have found earlier (filed as HTMLNET-4085) have been fixed in this update. This message was posted using Bugs notification tool by avpavlysh