LINQ e HTML Agility Pack riempiendo i dati della tabella HTML analizzati in un datatable

datatable html-agility-pack linq vb.net

Domanda

Sto usando la seguente query per analizzare i dati della tabella 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}

Come posso usare per ogni loop come posso riempire questo in un datatable?

Vorrei creare le colonne prima utilizzando i dati dell'intestazione e poi utilizzare un nidificato per ogni ciclo per riempire i dati della cella nella tabella, ma non sono sicuro di come, anche le eventuali modifiche suggerite sulla query LINQ sopra riportata?

Nota : la pagina html contiene sempre una sola tabella.

Risposta accettata

Dato il seguente html

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())

e la tua domanda

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}

puoi utilizzare GroupBy o ToLookup per raggruppare gli oggetti per colonne:

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

e utilizzare questo raggruppamento per creare un DataTable con le DataColumn appropriate:

Dim dt = new DataTable()

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

Ora, per riempire il DataTable , devi "ruotare" il raggruppamento, poiché ogni gruppo contiene i dati per una colonna, ma vogliamo i dati per ogni riga. Usiamo un piccolo metodo di supporto

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

per riempire il DataTable .

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

E ora il DataTable sarà simile a questo:

inserisci la descrizione dell'immagine qui



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché