Search code examples
c#.netc#-4.0html-parsingwatin

C# Watin is returning TD with null data


I am using Watin to retrieve data from a password sync page. I expected values to be returned. Maybe null if the value was &nbsp (in the HTML code).

But I am getting something else more unexpected

{string[4, 4]}
[0, 0] = null
[0, 1] = "MAINFRAME"
[0, 2] = "DOMAIN"
[0, 3] = "WebClient"
[1, 0] = null
[1, 1] = "INTERNALID"
[1, 2] = "FIRSTNAME.LASTNAME"
[1, 3] = "INTERNALID"
[2, 0] = null
[2, 1] = "Yes"
[2, 2] = "Yes"
[2, 3] = "Yes"
[3, 0] = null
[3, 1] = ""
[3, 2] = ""
[3, 3] = ""

The HTML code looks like

<TABLE WIDTH="100%" CELLSPACING=0 CELLPADDING=5 BORDER=0 class="TABLEBORDER">
<TR>

<TH class=HEADTEXT>
Target
</TH>
<TH class=HEADTEXT>
Trigger<br>enabled?
</TH>
<TH class=HEADTEXT>
Account
</TH>
<TH class=HEADTEXT>
Password<br>changed?

</TH>
<TH class=HEADTEXT>
Error message<br>(if any)
</TH>
<!-- S_STATUS_ROW -->

<TR>

<TD valign=top class=CELLTEXT>
MAINFRAME
</TD>
<TD valign=top class=CELLTEXT>
No
</TD>
<TD valign=top class=CELLTEXT>
INTERNALID
</TD>
<TD valign=top class=CELLTEXT>
Yes
</TD>
<TD valign=top class=CELLTEXT>
&nbsp;

</TD>
<!-- S_STATUS_ROW -->

<TR>

<TD valign=top class=CELLTEXT>
DOMAIN
</TD>
<TD valign=top class=CELLTEXT>
No
</TD>
<TD valign=top class=CELLTEXT>
FIRSTNAME.LASTNAME
</TD>
<TD valign=top class=CELLTEXT>
Yes
</TD>
<TD valign=top class=CELLTEXT>
&nbsp;

</TD>
<!-- S_STATUS_ROW -->

<TR>

<TD valign=top class=CELLTEXT>
WebClient
</TD>
<TD valign=top class=CELLTEXT>
No
</TD>
<TD valign=top class=CELLTEXT>
INTERNALID
</TD>
<TD valign=top class=CELLTEXT>
Yes
</TD>
<TD valign=top class=CELLTEXT>
&nbsp;

</TD>
<!-- S_STATUS_CONTENT_BOTTOM -->
</TABLE>

Finally here is the offending C# code.

        String path = "http://localhost/cgi.exe?ID=" + userName;
        Int32 startingRow = 1;

        using (var browser = new IE(path)) 
        {
            try
            {
                browser.Image(Find.ByAlt("Use a password")).Click();
                browser.TextField(Find.ByName("_MYPW")).TypeText(privateCurrentPassword);
                browser.Image(Find.ByAlt("Verify password")).Click();
                browser.Link(Find.ByTitle("Change passwords")).Click();
                browser.TextField(Find.ByName("_NEWP1")).TypeText(privateNewPassword);
                browser.TextField(Find.ByName("_NEWP2")).TypeText(privateNewPassword);
                browser.Image(Find.ByName("SUBMIT-CHANGE")).Click();
                Table table = browser.Table(Find.ByClass("TABLEBORDER"));
                Int32 numberOfColumn = table.TableRows[startingRow].TableCells.Count;
                Int32 currentRow = startingRow;
                td1stcolumn = new String[table.OwnTableRows.Count];
                td2ndcolumn = new String[table.OwnTableRows.Count];
                td3rdcolumn = new String[table.OwnTableRows.Count];
                td4thcolumn = new String[table.OwnTableRows.Count];

                for (int i = 1; i < table.OwnTableRows.Count; i++)
                {
                    td1stcolumn[i] = table.OwnTableRows[i].TableCells[0].Text.Trim();
                    td2ndcolumn[i] = table.OwnTableRows[i].TableCells[2].Text.Trim();
                    td3rdcolumn[i] = table.OwnTableRows[i].TableCells[3].Text.Trim();
                    td4thcolumn[i] = table.OwnTableRows[i].TableCells[4].Text.Trim();
                }
                String[,] arrayOfStrings = new String[4,td1stcolumn.Length];

                for(int j = 0; j < td1stcolumn.Length; j++)
                {
                    arrayOfStrings[0,j] = td1stcolumn[j];
                    arrayOfStrings[1,j] = td2ndcolumn[j];
                    arrayOfStrings[2,j] = td3rdcolumn[j];
                    arrayOfStrings[3,j] = td4thcolumn[j];
                }

                string resultDialogString = ResultDialog.ShowBox(arrayOfStrings, "Result Page", passwordTextBox.Text.ToString().Trim());
            }
            catch (ElementNotFoundException enfe)
            {
                String error = enfe.Message.ToString();
                browser.TextField(Find.ByName("_MYPW")).TypeText(privateCurrentPassword);
                browser.Image(Find.ByAlt("Verify password")).Click();
                browser.Link(Find.ByTitle("Change passwords")).Click();
                browser.TextField(Find.ByName("_NEWP1")).TypeText(privateNewPassword);
                browser.TextField(Find.ByName("_NEWP2")).TypeText(privateNewPassword);
                browser.Image(Find.ByName("SUBMIT-CHANGE")).Click();
                Table table = browser.Table(Find.ByClass("TABLEBORDER"));
                Int32 numberOfColumn = table.TableRows[startingRow].TableCells.Count;
                Int32 currentRow = startingRow;
                td1stcolumn = new String[table.OwnTableRows.Count];
                td2ndcolumn = new String[table.OwnTableRows.Count];
                td3rdcolumn = new String[table.OwnTableRows.Count];
                td4thcolumn = new String[table.OwnTableRows.Count];

                for (int i = 1; i < table.OwnTableRows.Count; i++)
                {
                    td1stcolumn[i] = table.OwnTableRows[i].TableCells[0].Text.Trim();
                    td2ndcolumn[i] = table.OwnTableRows[i].TableCells[2].Text.Trim();
                    td3rdcolumn[i] = table.OwnTableRows[i].TableCells[3].Text.Trim();
                    td4thcolumn[i] = table.OwnTableRows[i].TableCells[4].Text.Trim();
                }
                String[,] arrayOfStrings = new String[4, td1stcolumn.Length];

                for (int j = 0; j < td1stcolumn.Length; j++)
                {
                    arrayOfStrings[0, j] = td1stcolumn[j];
                    arrayOfStrings[1, j] = td2ndcolumn[j];
                    arrayOfStrings[2, j] = td3rdcolumn[j];
                    arrayOfStrings[3, j] = td4thcolumn[j];
                }
                string resultDialogString = ResultDialog.ShowBox(arrayOfStrings, "Result Page", passwordTextBox.Text.ToString().Trim());
            }
        }

Solution

  • What is the question here? what do you expect to get? everything you got could be explained very simply, I'll try to address some of the clear issues.

    First of all, the null values you get are because

    tdNstcolumn = new String[table.OwnTableRows.Count];
    

    and the loop

    for (int i = 1; i < table.OwnTableRows.Count; i++)
    

    starts with i = 1, which means the firsth (index 0) of the tdNstcolumn is never filled and hence null (when copying to arrayOfStrings the loop starts with j = 0).

    The "" (empty string) values you get are from

    <TD valign=top class=CELLTEXT>
    &nbsp;
    
    </TD>
    

    nbsp, by definition is a non breakable space - i.e " " which is trimmed by your call for Trim() The Trim function trims a lot more then just " ", it trims every character that is considered whitespace -> new line is also a whitespace (see: http://msdn.microsoft.com/en-us/library/t809ektx.aspx)

    I hope it makes everything clear