将 html table 解析为数据集时出错

Error while parsing html table into dataset

我正在尝试将 html 个文件中的 table 个解析为数据集。我使用 vb.net 创建了一个 windows 应用程序,我正在使用以下函数:

Public Function GetDataSet(ByVal strWebFilePath As String) As DataSet

    Dim html As String = System.IO.File.ReadAllText(strWebFilePath)

    html = WebUtility.HtmlDecode(html)

    Dim dsHtml As New DataSet
    Dim htmldoc As New HtmlAgilityPack.HtmlDocument
    htmldoc.LoadHtml(html)

    Dim tables = htmldoc.DocumentNode.SelectNodes("//table//tr") _
                    .GroupBy(Function(x) x.Ancestors("table").First())

    For i As Integer = 0 To tables.Count - 1
        Dim rows = tables(i).ToList()
        dsHtml.Tables.Add(String.Format("Table {0}", i))

        Dim headers = rows(0).Elements("th").Select(Function(x) x.InnerText.Trim).ToList()

        If headers.Count > 0 Then

            For Each Hr In headers
                dsHtml.Tables(i).Columns.Add(Hr)
            Next

            For j As Integer = 1 To rows.Count - 1
                Dim row = rows(j)
                Dim dr = row.Elements("td").Select(Function(x) x.InnerText.Trim).ToArray()
                dsHtml.Tables(i).Rows.Add(dr)
            Next

        Else

            headers = rows(0).Elements("td").Select(Function(x) x.InnerText.Trim).ToList()

            For ColumnIndex As Integer = 0 To headers.Count - 1
                dsHtml.Tables(i).Columns.Add("F" & ColumnIndex.ToString)
            Next

            For j As Integer = 0 To rows.Count - 1
                Dim row = rows(j)
                Dim dr = row.Elements("td").Select(Function(x) x.InnerText.Trim).ToArray()
                dsHtml.Tables(i).Rows.Add(dr)
            Next


        End If

    Next

    Return dsHtml
End Function

一切正常,直到我解析 html table 它的第一行包含具有 colspan=2 的列(第一行被认为是 header 即使它不包含 <th> )。所以它抛出这个异常:

An unhandled exception of type 'System.ArgumentException' occurred in System.Data.dll Additional information: Input array is longer than the number of columns in this table.

考虑这个 table 示例:

<table>
<tr><td colspan=2>Links</td></tr>
<tr><td>1</td><td>www.whosebug.com</td></tr>
<tr><td>2</td><td>www.sqlservercentral.com</td></tr>
<tr><td>3</td><td>www.dba.stackexchange.com/</td></tr>
</table>

有没有办法将第一行分成两列:

您需要一些关于如何解决列跨度、行跨度、缺失单元格、额外单元格、单元格中的值不一致等问题的约定。一般来说,在不知道数据结构 table 的情况下,很难将 html table 解析为 DataTable

在这个回答中,我将重点关注 header 上的列跨度。

有什么问题吗?

您首先依赖 <th> 计数 <tr> 并根据找到的 <th> 向数据 table 添加列。因此,如果您有这样的 table:

<table>
    <tr>
        <th colspan="2">A</th>
        <th>B</th>
    </tr>
    <tr>
        <td>1</td>
        <td>11</td>
        <td>111</td>
    </tr>
</table>

那么您假设您有 2 列,并且在添加行时,由于每行中有 3 个元素,您会收到异常。

如何解决问题?

这里我决定将 <th colspan="n">C</th> 转换为名称为 C1C2、...、Cn.

的 n 列
Dim headers = rows(0).Elements("th").Select(Function(x) _
    New With
    {
        .Name = x.InnerText.Trim,
        .Count = If(x.Attributes("colspan") Is Nothing, _
            1, Integer.Parse(x.Attributes("colspan").Value))
    }).ToList()

然后在向数据添加列时table:

For Each Hr In headers
    For index = 1 To Hr.Count
        Dim postFix = If(Hr.Count > 1, index.ToString(), "")
        dsHtml.Tables(i).Columns.Add(Hr.Name & postFix)
    Next
Next