LINQ et HTML Agility Pack intégrant les données du tableau HTML analysé dans un fichier datatable

datatable html-agility-pack linq vb.net

Question

J'utilise la requête suivante pour analyser les données de table html.

Dim q = From table In htmldoc.DocumentNode.SelectNodes("//table[@class='Seller']").Cast(Of HtmlNode)()
                    From row In table.SelectNodes("tr").Cast(Of HtmlNode)()
                    From header In row.SelectNodes("th").Cast(Of HtmlNode)()
                    From cell In row.SelectNodes("td").Cast(Of HtmlNode)()
               Select New With {Key .Table = table.Id, Key .CellText = cell.InnerText, Key .headerText = header.InnerText}

Comment puis-je utiliser pour chaque boucle, comment peut-on l'intégrer dans un datatable?

Je voudrais d'abord créer des colonnes en utilisant les données d'en-tête, puis utiliser un imbriqué pour chaque boucle afin de remplir les données de cellules dans la table, mais je ne sais pas comment procéder, également des modifications suggérées pour la requête LINQ ci-dessus?

Remarque : La page html contient toujours une seule table.

Réponse acceptée

Étant donné le html suivant

Dim t = <table class='Seller' id='MyTable'>
            <tr>
                <th>FooColumn</th>
                <td>Foo</td>
                <td>Another Foo</td>
            </tr>
            <tr>
                <th>BarColumn</th>
                <td>Bar</td>
                <td>Another Bar</td>
            </tr>
            <tr>
                <th>ThirdColumn</th>
                <td>Third</td>
                <td>Another Third</td>
            </tr>
        </table>

Dim htmldoc = New HtmlAgilityPack.HtmlDocument()
htmldoc.LoadHtml(t.ToString())

et votre requête

Dim q = From table In htmldoc.DocumentNode.SelectNodes("//table[@class='Seller']")
            From row In table.SelectNodes("tr")
                From header In row.SelectNodes("th")
                From cell In row.SelectNodes("td")
        Select New With {.Table = table.Id, .CellText = cell.InnerText, .headerText = header.InnerText}

vous pouvez utiliser GroupBy ou ToLookup pour regrouper les objets par colonnes:

Dim grouped = q.ToLookup(Function(a) a.headerText)

et utilisez ce groupe pour créer un DataTable avec les DataColumn appropriés:

Dim dt = new DataTable()

For Each h in grouped.Select(Function(g) g.Key)
    dt.Columns.Add(h)
Next

Maintenant, pour remplir le DataTable , vous devez "faire pivoter" le groupe, car chaque groupe contient les données d'une colonne, mais nous voulons les données de chaque ligne. Utilisons une petite méthode d'assistance

Function Rotate(Of T, TR)(source As IEnumerable(Of IEnumerable(Of T)), 
                          selector As Func(Of IEnumerable(Of T), IEnumerable(Of TR))) As IEnumerable(Of IEnumerable(Of TR))

    Dim result = new List(Of IEnumerable(Of TR))
    Dim enums = source.Select(Function(e) e.GetEnumerator()).ToArray()
    While enums.All(Function(e) e.MoveNext())
        result.Add(selector(enums.Select(Function(e) e.Current)).ToArray())
    End While

    Return result
End Function

pour remplir le DataTable .

For Each rrow in Rotate(grouped, Function(row) row.Select(Function(e) e.CellText))
    dt.Rows.Add(rrow.ToArray())
Next 

Et maintenant, le DataTable ressemblera à ceci:

entrez la description de l'image ici




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi