2016-11-28 12 views
2

htmlファイルのテーブルをデータセットに解析しようとしています。私はvb.netを使用してWindowsアプリケーションを作成し、私は次の関数を使用しています:私はそれが最初の行はcolspan=2を持つ列が含まだとHTMLテーブルを解析する時までhtmlテーブルをデータセットに解析中にエラーが発生しました

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 

すべてが正常に動作している(最初の行は、ヘッダーと考えられています<th>を含まない場合でも)。だから、この例外がスローされます。

型「System.ArgumentExceptionの」の未処理の例外がのSystem.Data.dll で発生しました追加情報:入力配列が長く、このテーブルの列数を超えています。

は、このテーブルの例を考えてみます。

<table> 
<tr><td colspan=2>Links</td></tr> 
<tr><td>1</td><td>www.stackoverflow.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> 

は、2列に最初の行を分割するが方法である:

  • 最初の自動生成を含むLinks
  • 秒を含みます値(すなわち:Col1

答えて

1

列スパン、行スパン、欠落したセル、余分なセル、セル内の一貫性のない値などを解決する方法について、いくつかの規則が必要です。一般的に、データテーブルの構造を知らなくても、htmlテーブルをDataTableに解析するのは難しいです。

この回答では、ヘッダーの列スパンに焦点を当てます。

問題が何ですか。

最初<tr><th>数に依存すると見られる<th>に基づいて、データテーブルに列を追加しています。あなたはこのようなテーブル持っているのであれば:

<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つの要素を持っているので、行を追加するとき、あなたは例外を受け取るとします。

この問題を解決するにはどうすればよいですか?

は、ここで私は名前C1C2、...、Cn<th colspan="n">C</th> 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() 

データテーブルに列を追加:

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 
+0

オフトピック:私はそれは良いアイデアだかいないかどうかわからないんだけど、あなたが持っている冗長なコードを取り除くことができます'薄いヘッダー=行(0).Elements(" th ")。連合(行(0).Elements(" td "))。を選択すると、' th'または 'td'に基づいてヘッダーを取得する。あなたのコードの 'else'部分を削除することができます。 –

関連する問題