VB.NET Klasse HTMLReader

Zweck

In vielen Fällen kommt es vor, dass man eine HTML Seite oder HTML Datei auswerten muss. Das kann sehr mühsam werden, wenn man mit Bordmittel arbeitet.

Es gibt verschiedene Methoden (Nicht abschliessend):

  1. Man überlässt dies der von der MSHTML Bibliothek verfügbaren Klasse HTMLDocument, dass ist für die vor .NET-Framework Zeit eine der besten Boardmittel.
  2. Der HTML-Quellcode wird eingelesen und mit Regex (Regulären Ausdrücken) zu analysieren.
  3. Man benutzt das Html Agility Pack.
  4. Man schreibt selber einen Parser.

Stolpersteine

Der Code des HTML ist je nach Herkunft unterschiedlich aufgebaut. Es gibt bei der HTML Codierung zwei Positionen, an der man sich festhalten kann.

  1. Die erste Zeile ist meist der Dokumenttyp bzw. die Kennung welche HTML Version benutzt wurde.
  2. Es gibt ein HTML Grundgerüst mit den Tags-Abschnitten HTML, HEAD, TITLE, BODY und dessen End-Tags.
  3. Die meisten Tags (ausser META, und LINK) haben ein Kleiner-Als () Schlusszeichen.

Man könnte nun mithilfe des Kleiner-Als (<) Zeichen die HTML Tags (Befehle) ermitteln. Doch es gibt folgende Stolpersteine:

In Kommentarabschnitten (), in Scriptabschnitten und Styleabschnitten können ebenfalls Tags vorkommen, die unter Umständen nicht an diese Positionen gehören oder unfertig gebaut sind. Zum Beispiel ruft ein Javascript ein HTMLCode Zeichenkette per Funktion auf. Das kann dazu führen, dass man innerhalb eines HEAD-Abschnittes (Kopfzeile) einen BODY-Abschnitt findet. Manchmal sind solche Fragmente absichtlich eingebaut worden, damit die Seite nicht analysiert werden kann.

Deshalb muss, bevor man eine Analyse oder eine Auftrennung des HTML Inhaltes vornimmt, muss man die Kommentare, Scripts und Styles in dem, für die zu eingelesenden HTML Seite, verfügbaren Variable entfernen.

Danach kann der restliche Inhalt  der HTML Seite nach Tags-Abschnitten aufgetrennt werden.

Ein weitere Stolperstein ist, dass Identifikationsmerkmale, wie Klassenname (class), Identitäten (id) oder Überschriften (….</h*) nicht an der Stelle auftaucht, in der sich die gewünschte Information befindet. Beispielsweise stehen zwischen der Information und einem Klassennamen etliche Tags-Abschnitte dazwischen.

Deshalb ist es nützlich, dass man während dem Auftrennen der Tags-Abschnitte, den Wert der Identifikationsmerkmale sich merkt und weitervererbt.

Nützlich wäre auch, dass man die Tabellen innerhalb des HTML Inhalts bereits als Tabellen strukturiert aufnimmt.

Ein weiter Stolperstein ist das HTML Codes grundsätzlich Verschachtelt daher kommt. Das heisst es  Verschachtelungen der Tags-Abschnitte, aber auch von Tabellen. Beispielsweise kann innerhalb einer Tabellenzelle, eine Untertabelle auftauchen.

Keine Chance bei Verschachtelten HTML Codes hat man, wenn man nirgends eine Identifikationsmerkmal definiert hat.

Um möglichst den HTML Inhalt Datenbank mässig zu analyisieren und gezielt werte auszuwerten habe ich folgenden Quellcode geschrieben.

Aufbau der Klasse HTMLReader

Aufruf

  • DIM objectvariable as new HTMLReader(Internet-Adresse oder Dateipfad)

Datentypen

  • Table (Tabellen)
  • TableRow (Tabellenzeilen)
  • TableCell (Tabellenzellen)
  • Tag (Der Tag Abschnitt und seine Informationen)

Eigenschaften

  • GetValueFromObject (Zugreifen auf Werte von Variabeln, Eigenschaften via Name)
  • Content (Der Inhalt der HTML Seite)
  • Url (Die Adresse oder der Pfad der HTML Seite)
  • Tags (Der Auflistungscontainer für die Tags)
  • Tables (Der Auflistungscontainter für die Tabellen)

Methoden

  • Close (Schliessen des HTML Inhaltes)

Funktionen

  • GetSelectTags (Auswerten nach einem Tag-Name)
  • GetSelectAttributs (Auswerten nach einem Attribut-Schlüsselnamen)
  • GetSelectAttributsByTag (Auswerten nach einem Attribut-Schlüsselnamen innerhalb eines bestimmten Tag-Abschnittes)
  • GetSelect (Auswerten der Tags-Auflistung nach verschieden Kriterien)
  • GetValueFromSelect (Wie GetSelect, nur übermittle mir den Wert des ersten Treffers)

Quellcode

Imports System
Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Linq

Public Class HTMLReader : Implements IDisposable
    'Klasse:   HTMLReader
    'Ziel:     Datenbankorientiertes Lesen eines HTMLCodes
    'Autor:    Daniel Schück, Hubstrasse 55a, CH-9500 Wil
    'Version:  1.0.0 von 2017

    'History
    '-------
    '1.0.0     07.10.2017  Eröffnung der Klasse

    Private pv_Content As String                'HTML Inhalt
    Private pv_Url As String                    'Url
    Private pv_Tags As List(Of Tag)             'Tags
    Private pv_Tables As List(Of Table)         'Tabellen

    'Schalter für FilterOptionen
    Public Enum FilterOptionEnum
        SingleLine = 0 'Rückgabe erster Wert
        MultiLine = 1  'Rückgabe aller Werte
    End Enum

    'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
    Shared Function pv_GetValueFromObject(ByVal FromObject As Object, ByVal Name As String)
        Dim oFieldInfo As Reflection.FieldInfo          'Eröffne Feldinformationen Objekt
        Dim oPropertyInfo As Reflection.PropertyInfo    'Eröffne Eigenschaftinformationen Objekt
        Dim oFieldValue As Object = Nothing             'Eröffne Wert Objekt
        Dim vName As String = Name                      'Temporäre Variable für Name des Objektes
        Dim vKey As String = ""                         'Schlüsselname
        'Wenn der Name des Objektes einen Punkt hat trenne in auf.
        If vName.IndexOf(".") >= 0 Then
            vKey = vName.Substring(vName.IndexOf(".") + 1).Trim
            vName = vName.Substring(0, vName.IndexOf(".")).Trim
        End If
        oFieldInfo = FromObject.GetType.GetField(vName)         'Suche ein Feld mit dessen Namen
        If Not oFieldInfo Is Nothing Then
            'Der Feldname ist gültig und nun hohle aktuellen Wert
            oFieldValue = oFieldInfo.GetValue(FromObject)
            If Not vKey = "" Then
                If oFieldValue.Contains(vKey) Then
                    oFieldValue = oFieldValue(vKey)
                End If
            End If
        Else
            'Der Feldname ins ungültig
            oPropertyInfo = FromObject.GetType.GetProperty(Name) 'Suche anstelle des Felds in den Eigenschaften
            If Not oPropertyInfo Is Nothing Then
                'Der Eigenschaftsname ist gültige und nun hohle aktuellen Wert
                oFieldValue = oPropertyInfo.GetValue(FromObject, Nothing)
            End If
        End If
        'Gib ermittelten Wert zurück
        Return oFieldValue
    End Function

    'Datentyp Table für Tabellen
    Public Structure Table
        Public Nr As String                     'Nummer der Tabelle
        Public Name As String                   'Name der Tabelle
        Public Rows As List(Of TableRow)        'Zeilen innerhalb der Tabelle
        'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
        Public ReadOnly Property GetValueFromObject(ByVal Name As String)
            Get
                'Gib ermittelten Wert zurück
                Return pv_GetValueFromObject(Me, Name)
            End Get
        End Property
    End Structure

    'Datentyp TableRow für Tabellenzeilen
    Public Structure TableRow
        Public Nr As Long                       'Nummer der Zeile
        Public Name As String                   'Name der Zeile
        Public Cells As List(Of TableCell)      'Zellen innerhalb der Zeilen
        'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
        Public ReadOnly Property GetValueFromObject(ByVal Name As String)
            Get
                'Gib ermittelten Wert zurück
                Return pv_GetValueFromObject(Me, Name)
            End Get
        End Property
    End Structure

    'Datentyp TableCell für Tabellenzellen
    Public Structure TableCell
        Public Nr As Long                       'Nummer der Zelle
        Public Name As String                   'Name der Zelle
        Public Content As String                'HTML Inhalt der Zelle
        Public Text As String                   'Text der Zelle
        'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
        Public ReadOnly Property GetValueFromObject(ByVal Name As String)
            Get
                'Gib ermittelten Wert zurück
                Return pv_GetValueFromObject(Me, Name)
            End Get
        End Property
    End Structure

    'Datentyp Tag für Tag-Abschnitte in einer HTML Struktur
    '* Diese Variabeln befinden sich auch in der Sections Collection
    Public Structure Tag
        Public Nr As Long                       'Fortlaufende Zahl
        Public Name As String                   'Name des Tags
        Public Content As String                'HTML Inhalt
        Public OuterTag As String               'Ausserhalb des Tags (Text)
        Public InnerTag As String               'Innerhalb des Tags
        Public Attributs As Collection          'Attribute innerhalb des Tags
        Public Hierarchy As String              'Hierachie
        Public InnerBody As Boolean             'Tag befindet sich im Body-Abschnitt
        Public Sections As Collection           'Vererbten Identifikationsmerkmale (Tabellenname, Überschriften, Klassennamen, Ids)
        'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
        Public ReadOnly Property GetValueFromObject(ByVal Name As String)
            Get
                'Gib ermittelten Wert zurück
                Return pv_GetValueFromObject(Me, Name)
            End Get
        End Property
    End Structure

    'Eigenschaft GetValueFromObject für Rückgabe des Wertes eines bestimmten Objekt
    Public ReadOnly Property GetValueFromObject(ByVal Name As String)
        Get
            'Gib ermittelten Wert zurück
            Return pv_GetValueFromObject(Me, Name)
        End Get
    End Property

    'Eigenschaft HTML für Rückgabe des HTML Inhaltes (Codes)
    Public ReadOnly Property Content() As String
        Get
            Return pv_Content
        End Get
    End Property

    'Eigenschaft URL für Rückgabe der URL Adresse
    Public ReadOnly Property Url() As String
        Get
            Return pv_Url
        End Get
    End Property

    'Eigenschaft Tags für Auflistung der Tags
    Public ReadOnly Property Tags() As List(Of Tag)
        Get
            Return pv_Tags
        End Get
    End Property

    'Eigenschaft Tables für Auflistung der Tabellen
    Public ReadOnly Property Tables() As List(Of Table)
        Get
            Return pv_Tables
        End Get
    End Property

    'Das Objekt wird eröffnet
    'Eingabeparameter URL: URL-Adresse oder Dateiname
    Public Sub New(ByVal URL As String)
        Dim oWebRequest As HttpWebRequest               'Webanfrage Objekt
        Dim oWebResponse As WebResponse = Nothing       'Webantwort Objekt
        Dim oDataStreamReader As StreamReader           'Lesedatenfolge Objekt

        If URL Like "?:\*" Or URL Like "\\*" Then
            'Die URL ist eine Datei
            oDataStreamReader = New StreamReader(New FileStream(URL, FileMode.Open))
        Else
            'Stelle die Webanfrage an die angebenen URL Adresse
            oWebRequest = WebRequest.Create(URL)
            'Verwendet Standard Authentifizierung
            oWebRequest.Credentials = CredentialCache.DefaultCredentials
            'Hohle die Antwort der Webanfrage
            oWebResponse = oWebRequest.GetResponse()
            'Hohle die Datenfolge der Webanfrage
            oDataStreamReader = New StreamReader(oWebResponse.GetResponseStream)
        End If

        'Lese Dateninhalt der HTML Inhaltsdatenfolge aus Datei oder Web
        pv_Content = oDataStreamReader.ReadToEnd        'Übertrage Dateninhalt auf pv_Content
        pv_Url = URL                                    'Übertrage URL Adresse auf pv_Url
        oDataStreamReader.Close()                       'Schliesse Datenleser Onbjekt
        oDataStreamReader.Dispose()                     'Zerstöre Datenleser Objekt
        oDataStreamReader = Nothing                     'Zerstöre Datenleser Objekt

        If Not oWebResponse Is Nothing Then
            'Schliese die Webanfrage
            oWebResponse.Close()
            oWebResponse = Nothing
            oWebRequest = Nothing
        End If

        'Fülle die Auflistungen von Tags und Tabellen
        pv_Tags = fillTags()
        pv_Tables = fillTables()
    End Sub

    'Schliesse das Objekt und leere Variabeln und Auflistungen
    Public Sub Close()
        pv_Content = ""
        pv_Url = ""
        pv_Tags.Clear()
        pv_Tables.Clear()
    End Sub

    'fillTags füllt die Auflistungsvariable der Tags
    'Rückgabewert Liste vom Datentyp Tag
    Private Function fillTags() As List(Of Tag)
        Dim oTag As New Tag                             'Objekt eines einzelnen Tag-Abschnitt <.....>.....<
        Dim oTags As New List(Of Tag)                   'Objekt der Tag-Abschnitt Auflistung
        Dim AttributKey As String                       'Schlüssel des Attributes ....=xxxxxx
        Dim AttributValue As String                     'Wert des Attributes xxxx=....
        Dim Hierarchy As String = ""                    'Hierarchy innerhalb des HTML Inhaltes
        Dim ChildItr As Long = 0                        'Kinderzähler (Untergeordnete Objekte)
        Dim vContent As String = Content                'Inhalt des HTMLs (Code)
        Dim vTableItr As Long = 0                       'Tabellenzähler
        Dim vTableRowItr As Long = 0                    'Tabellenzeilenzähler
        Dim vTableCellItr As Long = 0                   'Tabellenzellenzähler
        Dim vLastHeading As String = ""                 'Letzter Überschriftentext
        Dim vLastClass As String = ""                   'Letzter Attributwert des Attributs Class
        Dim vLastID As String = ""                      'Letzter Attributwert des Attributs Id
        Dim vLastTableName As String = ""               'Letzter Name der Tabelle

        'Entferne Störende HTML Code Inhalte vor der Tag-Abschnittermittlung
        vContent = vContent.Replace(vbCr, " ").Replace(vbLf, " ")                   'Zeilenumschaltungen
        vContent = Regex.Replace(vContent, "(?=<!--)([\s\S]*?)-->", "")             'Kommentareblöcke
        vContent = Regex.Replace(vContent, "(?=<script)([\s\S]*?)</script>", "")    'Scriptblöcke
        vContent = Regex.Replace(vContent, "(?=<style)([\s\S]*?)</style>", "")      'Styleblöcke
        vContent = vContent.Replace("&nbsp;", "")                                   'Unzulässige Textinhalte

        oTag.InnerBody = False                          'Befindet sich der Tag-Abschnitt im Body-Abschnittblock

        'Teile den HTML Codes auf einzelene Tag-Abschnitte auf <......>......|<
        For Each Tag As String In vContent.Split("<")
            oTag.Content = ("<" & Tag).Trim             'Gesamtinhalt des Tag-Abschnitt
            oTag.Nr = oTag.Nr + 1                       'Tag-Abschnittzähler
            oTag.Name = ""                              'Der Tagname "<.... xxxxxxxx>xxxxxxxx|<
            oTag.OuterTag = ""                          'Ausserhalb des Tags <xxxxxxxx>........|<
            oTag.InnerTag = ""                          'Innerhalb des Tags <......>xxxxxxxxx|<
            'Trenne Innerhalb und Ausserhalb des Tags ab
            If Tag.IndexOf(">") > 0 Then
                oTag.InnerTag = Tag.Substring(0, Tag.IndexOf(">")).Trim
                oTag.OuterTag = Tag.Substring(Tag.IndexOf(">") + 1).Trim
            End If

            'Trenne der Names des Tags von Innerhalb des Tags ab
            If oTag.InnerTag.IndexOf(Chr(32)) > 0 Then
                oTag.Name = oTag.InnerTag.Substring(0, oTag.InnerTag.IndexOf(Chr(32))).Trim
                oTag.InnerTag = oTag.InnerTag.Substring(oTag.InnerTag.IndexOf(Chr(32)) + 1).Trim
            Else
                oTag.Name = oTag.InnerTag
            End If

            'Ermittle die Attribute des Tagabschnitts
            Dim ColAttributs As New Collection          'Temporäre Attribut Collection Objekt
            'Teile diesen Variable nach jedem Leerzeichen (32) auf
            For Each Attributs As String In oTag.InnerTag.Replace(Chr(34), "").Split(Chr(32))
                'Finde ein Gleichzeichen
                If Attributs.IndexOf("=") > 0 Then
                    'Trenne die Zeichenkette in Schlüssel und dessen Wert auf
                    AttributKey = Attributs.Substring(0, Attributs.IndexOf("="))
                    AttributValue = Attributs.Substring(Attributs.IndexOf("=") + 1)
                    'Speichere dies in die Temporären Attributs Collection und Auflistungs Objekte
                    ColAttributs.Add(AttributValue, AttributKey)
                End If
            Next Attributs
            oTag.Attributs = ColAttributs           'Übertrage die Temporäre Attribut Collection in die Tag Auflistung

            'Ermittle die Hierarchie und fülle dies in die Hierarchie Variable ab.
            If Not oTag.Name = "" Then           'Es gibt einen Tagname
                If oTag.Name = "html" Then       'Der Tag HTML ist immer eine Stammhierarchie
                    Hierarchy = "/html"
                ElseIf oTag.Name = "head" Or oTag.Name = "body" Then  'Die Tags HEAD und BODY sind immer dem Tag HTML unterstellt.
                    Hierarchy = "/html/" + oTag.Name
                ElseIf oTag.Name.IndexOf("/") = 0 Or oTag.Name.IndexOf("\/") = 0 Then 'Der Tag ist ein Abschliessender Tag
                    '</Abschschliesender Tag>
                    '<\/Falscher Abschliessender Tag> in codierungen
                    If Hierarchy.LastIndexOf("/") >= 0 Then 'Es ist ein richtiger Abschliessender Tag
                        'Die Variable Hierarchy, wird auf die übergeordenete Tag-Struktur zurückversetzt
                        Hierarchy = Hierarchy.Substring(0, Hierarchy.LastIndexOf("/"))
                    End If
                ElseIf oTag.Name = "meta" Or oTag.Name = "link" Or oTag.Name.IndexOf("!") = 0 Or oTag.Name.IndexOf("\!") = 0 Then
                    'Ist der Tagname META, LINK hat er ein ! oder ein \! ist er nicht Hierarchisch abbildbar, da er sofort wieder geschlossen wird.
                Else
                    'Die Variable Hierarchy erweitert sich um einen Untergeordneten Tag
                    Hierarchy = Hierarchy + "/" + oTag.Name
                End If
                oTag.Hierarchy = Hierarchy          'Übertrage die Variable Hierarchy in die Tag Auflistung
            End If

            'Wenn der Tagname BODY heisst setzte die Variable InnerBody auf Richtig ein.
            If oTag.Name = "body" Then
                oTag.InnerBody = True
            End If

            'Wenn der Tagname ein Abschliessender BODY Tag aufweisst setzte die Variable InnerBody auf Falsch ein.
            If oTag.Name = "/body" Then
                oTag.InnerBody = False
            End If

            'Befülle weitere Variablen des Tag, wenn er sich in einer Body struktur befindet.
            If oTag.InnerBody Then

                'Setzte und behalte denn letzte Überschriffttext, sofern er nicht leer ist
                If oTag.Name Like "h*" And Not oTag.OuterTag = "" Then
                    If IsNumeric(oTag.Name.Substring(1, 1)) Then
                        vLastHeading = oTag.OuterTag
                    End If
                End If

                'Setzte und behalte den letzten Wert eines class Attributs
                If oTag.Attributs.Contains("class") Then
                    vLastClass = oTag.Attributs("class")
                End If

                'Setzte und behalte den letzten Wert eines id Attributs
                If oTag.Attributs.Contains("id") Then
                    vLastID = oTag.Attributs("id")
                End If

                'Setzte und behalte die Tabelleninformation
                If oTag.Name = "table" Then      'Tabellen-Tag ist eröffnet
                    vTableItr = vTableItr + 1       'Tabellenzähler erhöhen um eins
                    'Tabellenname wird erweitert durch einen Untergeordneten Tabellenname
                    '|\Tabellename1|Tabellename2|_______ usw.
                    'Tabellenname = \Letzter Überschrifttext\Letzter ID-Attributwert\Letzter CLASS-Attributwert:Fortlaufende Zahl
                    vLastTableName = vLastTableName & "|"
                    vLastTableName = vLastTableName & "\" & vLastHeading.Replace("\", "").Replace("|", "")
                    vLastTableName = vLastTableName & "\" & vLastID.Replace("\", "").Replace("|", "")
                    vLastTableName = vLastTableName & "\" & vLastClass.Replace("\", "").Replace("|", "")
                    vLastTableName = vLastTableName & ":" & vTableItr.ToString
                End If

                'Wenn die Tabelle geschlossen wurde müssen die Informationen rückgesetzt werden
                If oTag.Name = "/table" Then     'Tabellen-Tag ist geschlossen
                    If vLastTableName.LastIndexOf("|") >= 0 Then 'Die Tabelle ist eine Untertabelle
                        oTags.Add(oTag)     'Sichere HTML-Abschlusstag und die gesammelten Tabelleinformationen
                        'Setzte den Tabellenname auf das Obergeordnete Tabellenname element zurück
                        vLastTableName = vLastTableName.Substring(0, vLastTableName.LastIndexOf("|"))
                        oTag.Name = "tableclosed"    'Führe es als Künstliches Tag "tableclosed" als neuen Tag eintrag.
                    End If
                End If
            End If

            'Übertrage die Parent Variabeln in die Parent Collection
            Dim ColSection As New Collection                    'Temporäre Parent Collection
            ColSection.Add(vLastTableName, "tablename")         'Übertrag der Variable vLastTableName auf die Temporäre Section Collection
            ColSection.Add(vLastHeading, "heading")             'Übertrag der Variable vLastHeading auf die Temporäre Section Collection
            ColSection.Add(vLastClass, "class")                 'Übertrag der Variable vLastClass auf die Temporäre Section Collection
            ColSection.Add(vLastID, "id")                       'Übertrag der Variable vLastID auf die Temporäre Section Collection
            oTag.Sections = ColSection                          'Übertrag der Temporären Section Collection auf den Tag
            oTags.Add(oTag)                                     'Übertrag das Tag Element in die Tags Auflistung
        Next Tag
        'Funktionsübertrag der Tags Auflistung
        Return oTags
    End Function
    'Fülle die Tables Auflistung abhand der Tabelleninformation aus der Tags Auflistung
    'Rückgabewert:  Tables Auflistung
    Public Function fillTables() As List(Of Table)

        Dim oTable As New Table                                     'Tabellen Objekt
        Dim oTables As New List(Of Table)                           'Tabellen Auflistung Objekt
        Dim oTableRow As New TableRow                               'Tabellenzeile Objekt
        Dim oTableRows As New List(Of TableRow)                     'Tabellenzeilen Auflistung Objekt
        Dim oTableCell As New TableCell                             'Tabellenzellen Objekt
        Dim oTableCells As New List(Of TableCell)                   'Tabellenzeilen Auflistung Objekt
        Dim vTableItr As Long = 0                                   'Zähler der Tabelle
        Dim vTableRowItr As Long = 0                                'Zähler der Tabellenzeile
        Dim vTableCellItr As Long = 0                               'Zähler der Tabellenzelle
        Dim vTableContent As String = ""                            'Inhalt (Code) der Tabellenzelle
        Dim vTableText As String = ""                               'Inhalt (Text) der Tabellenzelle
        Dim vTableName As String = ""                               'Name der Tabelle
        Dim vTableRowName As String = ""                            'Name der Tabellenzeile
        Dim vTableCellName As String = ""                           'Name der Tabellenzelle

        'Filtere Auflistung aufgrund des Tabellennamen und Sortiere es nach Tabellenname und der Reihenfolge der Tags
        For Each TableTag In From TableTags In Tags Where Not TableTags.Sections("tablename") = "" Order By TableTags.Sections("tablename"), TableTags.Nr

            Select Case TableTag.Name

                Case "table"                                        'Der Tag ist eine Tabelle
                    vTableItr = vTableItr + 1                       'Erhöhen des Tabellenzählers um eins
                    vTableRowItr = 0                                'Der Zähler der Tabellenzeile wird auf null zurückgesetzt
                    vTableCellItr = 0                               'Der Zähler der Tabellenzelle wird auf null zurückgesetzt
                    vTableContent = ""                              'Der Inhaltsammler wird geleert
                    vTableText = ""                                 'Der Textsammler wird geleert

                Case "tr"                                           'Der Tag ist eine Tabellenzeile
                    vTableRowItr = vTableRowItr + 1                 'Der Zähler Tabellenzeile wird um eins erhöht
                    vTableCellItr = 0                               'DDer Zähler der Tabellenzelle wird auf null zurückgesetzt
                    vTableContent = ""                              'Der Inhaltsammler wird geleert
                    vTableText = ""                                 'Der Textsammler wird geleert
                    'Der Tabellenzeilenname (Name) wird gebildet
                    'Name = \Letzter ID Attribut Wert\Letzer CLASS Attribut Wert\Aktueller ITEMPROP Attribut Wert (falls Vorhanden)
                    vTableRowName = "\" & TableTag.Sections("id").Replace("\", "")
                    vTableRowName = vTableRowName & "\" & TableTag.Sections("class").Replace("\", "")
                    'Falls Vorhanden füge den Wert des ITEMPROP Attributs dem Namen der Tabellenzeile dazu
                    If TableTag.Attributs.Contains("itemprop") Then
                        vTableRowName = vTableRowName & "\" & TableTag.Attributs("itemprop").Replace("\", "")
                    End If

                Case "td"                                           'Der Tag ist eine Tabellenzelle
                    vTableCellItr = vTableCellItr + 1               'Der Zähler der Tabellenzelle wird um eins erhöht
                    vTableContent = ""                              'Der Inhaltsammler wird geleert
                    vTableText = ""                                 'Der Textsammler wird geleert
                    'Der Tabellenzellenname (Name) wird gebildet
                    'Name = \Letzter ID Attribut Wert\Letzer CLASS Attribut Wert\Aktueller ITEMPROP Attribut Wert (falls Vorhanden)
                    vTableCellName = "\" & TableTag.Sections("id").Replace("\", "")
                    vTableCellName = vTableCellName & "\" & TableTag.Sections("class").Replace("\", "")
                    'Falls Vorhanden füge den Wert des ITEMPROP Attributs dem Namen der Tabellenzelle dazu
                    If TableTag.Attributs.Contains("itemprop") Then
                        vTableCellName = vTableCellName & "\" & TableTag.Attributs("itemprop").Replace("\", "")
                    End If

                Case "/td"                                          'Der Tag ist eine Abschliessende Tabellenzelle
                    oTableCell.Nr = vTableCellItr                   'Übertrag des Tabellenzellennummer in das Tabellenzellen Objekt
                    oTableCell.Name = vTableCellName                'Übertrag des Tabellenzellennamen in das Tabellenzellen Objekt
                    oTableCell.Content = vTableContent              'Übertrag des Inhaltsammlers in das Tabellenzellen Objekt
                    oTableCell.Text = vTableText.Trim               'Übertrag des Textsammlers in das Tabellenzellen Objekt
                    oTableCells.Add(oTableCell)                     'Die Information der Tabellezelle wird in die Tabellenzellen Auflistung übernommen

                Case "/tr"                                          'Der Tag ist eine Abschliessende Tabellezeile
                    oTableRow.Nr = vTableRowItr                     'Übertrag des Tabellenzeilennummer in das Tabellenzeile Objekt
                    oTableRow.Name = vTableCellName                 'Übertrag des Tabellenzeilennamen in das Tabellenzeilen Objekt
                    oTableRow.Cells = oTableCells                   'Übertrag der Tabellenzellen Auflistung in das Tabellenzeile Objekt
                    oTableRows.Add(oTableRow)                       'Übertrag des Tabellenzeile Objektes in die Tabellenzeile Auflistung
                    oTableCells = New List(Of TableCell)            'Die Tabellenzelle Auflistung wird neu eröffnet

                Case "/table"                                       'Der Tag ist eine Abschliessende Tabelle
                    oTable.Name = TableTag.Sections("tablename")       'Übertrag des Tabellenname in das Tabelle Objekt
                    oTable.Nr = vTableItr                           'Übertrag der Tabellennummer in das Tabelle Objekt
                    oTable.Rows = oTableRows                        'Übertrag der Tabellenzeilen Auflistung in das Tabelle Objekt
                    oTables.Add(oTable)                             'Übertrag des Tabelle Objekts in die Tabellen Auflistung
                    oTableRows = New List(Of TableRow)              'Die Tabellenzeile Auflistung wird neu eröffnet

            End Select

            vTableContent = vTableContent + TableTag.Content        'Der Inhaltsammler nimmt neue Information auf
            vTableText = vTableText + TableTag.OuterTag             'Der Textsammler nimmt neue Information auf

        Next TableTag
        'Funktionsübergabe der Tabellen Auflistung
        Return oTables
    End Function

    'Hohle für einen bestimmten Tag eine Auflistung
    'Eingangsparameter: TagName = Name des gewünschten Tags
    'Rückgabe:          Auflistung der gewünschten Tags und seinen Werten
    'Beispiel:          divs = GetSelectTags("div")
    '                   Stelle alle DIV-Tags als Auflistung bereit
    Public Function GetSelectTags(ByVal TagName As String) As Object
        Return From SelectTags In Tags Where SelectTags.Name = TagName
    End Function

    'Hohle zu einem bestimmten Attributschlüssel eine Auflistung
    'Eingangsparameter: AttributName = Name des gewünschten Schlüssel des Attributes
    'Rückgabe:          Auflistung des gewünschten Attributsschlüssel und seinen Werten
    'Beispiel:          classes = GetSelectAttributs("class")
    '                   Stelle alle CLASS-Attribute als Auflistung bereit
    Public Function GetSelectAttributs(ByVal AttributName As String) As Object
        Return From SelectTags In Tags Where SelectTags.Attributs.Contains(AttributName)
    End Function

    'Hohle zu einem bestimmten Tag und seinem bestimmten Attirbut eine Auflistung
    'Eingabeparameter:  TagName = Name des gewünschten Tags
    '                   AttributName = Name des gewünschten Schlüssel des Attributes
    'Rückgabe:          Auflistung des gewünschten Attibutschlüssel innerhalb des Tags und seinen Werten
    'Beispiel:          GetSelectAttributsByTag("a","href")
    '                   Stelle alle HREF-Attribute eines A-Tags als Auflistung bereit
    Public Function GetSelectAttributsByTag(ByVal TagName As String, ByVal AttributName As String) As Object
        Return From SelectTags In Tags Where SelectTags.Name = TagName And SelectTags.Attributs.Contains(AttributName)
    End Function

    'Hohle eine Auflistung von Text der von einem Bestimmten Tag und von einem bestimmten gemerkter Identität eines Abschnittes und/oder von einem Attribut erfolgt
    'Eingabeparameter:  TagName = Gewünschter Name des Tags
    '                   FieldName = Der Name des Feldes (Variable/Eigenschaft), dass zurückgeholt werden wird
    '                   SectionFilter = Kriterium des gemerkten Identität eines Abschnittes (Optional)
    '                   AttributFilter = Filterkriterum des Attributs (Optional)
    '                   FilterOption = Möchten wir nur den ersten gefunden Eintrag oder alle Einträge? (Optinal: Standard alle Einträge)
    'Rückgabe:          Auflistung des Abfrageergebniss
    'Beispiel:          getTextByFilter("a", "OuterTag", "caption=*Sound Mix:*", "href=*sound_mixes=*")
    '                   Hohlt eine Auflistung der A-Tags die nach einer Überschrift "Sound Mix:" und einem HREF-Attributwert "sound_mixes=" zurück
    Public Function GetSelect(ByVal TagName As String, ByVal FieldName As String, Optional ByVal SectionFilter As String = "", Optional ByVal AttributFilter As String = "", Optional ByVal FilterOption As FilterOptionEnum = FilterOptionEnum.MultiLine)
        Dim r_GetSelect As New List(Of String)              'Rückgabeobjekt der Auflistung
        Dim AttributFilterName As String = ""               'Name des zu filterndes Attributs
        Dim AttributFilterValue As String = ""              'Wert des zu filterndes Attributs
        Dim SectionFilterName As String = ""                'Name der zu filternden zu einem gemerkten Inhaltes in einem Abschnitt
        Dim SectionFilterValue As String = ""               'Wert der zu filternden zu einem gemerkten Inhaltes in einem Abschnitt
        Dim CollectionKey As String = ""                     'Schlüssel der gewübschten Sammlung
        Dim LinqSelection As Object                         'Objekt der LINQ Auswertung
        'Der AttributFilter ist mit einem Gleichzeichen (=) vorhanden
        If AttributFilter.IndexOf("=") >= 0 Then
            'Trennen von Attribut Name und Wert durch das Gleichzeichen
            AttributFilterName = AttributFilter.Substring(0, AttributFilter.IndexOf("="))
            AttributFilterValue = AttributFilter.Substring(AttributFilter.IndexOf("=") + 1)
        End If
        'Der SectionFilter ist mit einem Gleichzeichen (=) vorhanden
        If SectionFilter.IndexOf("=") >= 0 Then
            'Trennen von Parent Name und Wert durch das Gleichzeichen
            SectionFilterName = SectionFilter.Substring(0, SectionFilter.IndexOf("="))
            SectionFilterValue = SectionFilter.Substring(SectionFilter.IndexOf("=") + 1)
        End If
        'Der Filterzustand wird überprüft und die Abfrage Kriterien festgelegt
        If AttributFilterName = "" And SectionFilterName = "" Then
            'Namen der AttributFilter und SectionFilter fehlen
            'Es wird nur nach dem Namen des Tag gesucht
            LinqSelection = From SelectTags In Tags Where SelectTags.Name = TagName
        ElseIf Not AttributFilterName = "" And SectionFilterName = "" Then
            'Name des AttributFilter vorhanden, aber Name des SectionFilter fehlt
            'Es wird nur nach dem Namen des Tag und des Vorhandenseins des Attributname gesucht
            LinqSelection = From SelectTags In Tags Where SelectTags.Name = TagName And SelectTags.Attributs.Contains(AttributFilterName)
        ElseIf AttributFilterName = "" And Not SectionFilterName = "" Then
            'Name des AttribuFilter fehlt, aber Name des SectionFilter ist vorhanden
            'Es wird nur nach dem Namen des Tag und des Vorhandenseins des Abschnittsname gesucht
            LinqSelection = From SelectTags In Tags Where SelectTags.Name = TagName And SelectTags.Sections.Contains(SectionFilterName)
        Else
            'Alle Filternamen sind vorhanden
            'Es wird nur nach dem Namen des Tag und des Vorhandenseins sowohl des Abschnittsname wie auch des Attributsnamen gesucht
            LinqSelection = From SelectTags In Tags Where SelectTags.Name = TagName And SelectTags.Attributs.Contains(AttributFilterName) And SelectTags.Sections.Contains(SectionFilterName)
        End If
        'Die Abfrage wird gestartet
        For Each oList In LinqSelection
            'Werte analyse
            If AttributFilterName = "" And SectionFilterName = "" Then
                'Wenn der AttributFilterName und der SectionFilterName fehlt dann führe nur den Text eines Tags zurück
                r_GetSelect.Add(Trim(oList.getValueFromObject(FieldName)))
            ElseIf Not AttributFilterName = "" And SectionFilterName = "" Then
                'Wenn der AttributFilterName vorhanden ist, aber der SectionFilterName nicht vorhanden ist, überprüfe ob das Attribut den bestimmten Wert hat
                If oList.Attributs(AttributFilterName) Like AttributFilterValue Then
                    'Aufnahme in die Auflistung des Textes, wenn im Tagname und AttributFilter die Werte übereinstimmen
                    r_GetSelect.Add(Trim(oList.getValueFromObject(FieldName)))
                End If
            ElseIf AttributFilterName = "" And Not SectionFilterName = "" Then
                'Wenn der AttributFilterName fehlt, aber der SectionFilterName vorhanden ist, überprüfe ob die Sectionsammlung den bestimmten Wert hat
                If oList.Sections(SectionFilterName) Like SectionFilterValue Then
                    'Aufnahme in die Auflistung des Textes, wenn im Tagname und SectionFilter die Werte übereinstimmen
                    r_GetSelect.Add(Trim(oList.getValueFromObject(FieldName)))
                End If
            Else
                'Alle Filternamen sind vorhanden. Überprüfe ob das Attribut den Attributwert und ob die Sectionsammlung einen bestimmten Wert enthält
                If oList.Sections(SectionFilterName) Like SectionFilterValue And oList.Attributs(AttributFilterName) Like AttributFilterValue Then
                    'Aufnahme in die Auflistung des Textes, wenn im Tagname und SectionFilter und AttibutFilter die Werte übereinstimmen
                    r_GetSelect.Add(Trim(oList.getValueFromObject(FieldName)))
                End If
            End If
            If FilterOption = FilterOptionEnum.SingleLine Then
                If r_GetSelect.Count > 0 Then
                    'Wird nur der erste Treffer gewünscht, unterbreche die weiteren Auswertungen.
                    Exit For
                End If
            End If
        Next oList
        'Rückgabe der Auflistung an die Funktion
        Return r_GetSelect
    End Function
    'Hohle den ersten Treffer einer getTextByFilters Auswertung in eine Zeichenkette zurück
    'Gleiche Anwendung wie bei getTextByFilters
    Public Function GetValueFromSelect(ByVal TagName As String, ByVal FieldName As String, Optional ByVal ParentFilter As String = "", Optional ByVal AttributFilter As String = "") As String
        Dim r_GetValueFromSelect As String = ""
        For Each oListItem As String In GetSelect(TagName, FieldName, ParentFilter, AttributFilter)
            r_GetValueFromSelect = oListItem
            Exit For
        Next oListItem
        Return r_GetValueFromSelect
    End Function

    'Hohle eine Auflistung von Tabellen zurück, die einen bestimmten Tabellennamen beinhaltet
    'Eingabeparameter:  Name der Tabelle
    'Rückgabe:          Auflistung der Tabellen
    'Beispiel:          getTable("|\Also Known As (AKA)\akas\subpage_data:*")
    '                   Bringt eine Auflistung der Tabellen zurück, die mit dem Tabellennamen "|\Also Known As (AKA)\akas\subpage_data:" anfangen.
    Public Function GetTable(ByVal Name As String) As Table
        Dim r_GetTable As Table = Nothing       'Rückgabe Objekt der Auswertung
        'Starte die Abfrage
        For Each Table As Table In Tables
            If Table.Name Like Name Then
                'Hat er die bestimmte Tabelle gefunden, übertrage das Tabellenobjekt in die Rückantwort
                r_GetTable = Table
                Exit For
            End If
        Next
        'Rückgabe der gefilterten Auswertung an die Funktion
        Return r_GetTable
    End Function

    'Hohle den ersten Text zwischen zwei Wörtern oder Fragmenten
    'Eingabeparameter:  InputString = Text in der gesucht wird
    '                   AfterPhrase = Suchbegriff vor dem gewünschten Text
    '                   NextPhrase = Suchbegriff nach dem gewünschten Text
    'Rückgabe:          Der Text zwischen den zwei Wörtern als Zeichenkette
    'Beispiel:          getBetweenWord("Peter liest gerne Krimis und Western im Bett.","und","im") = Western
    'Beispiel:          getBetweenWord("c:\Schweiz\Thurgau\Orte","\","\") = Schweiz
    'Beispiel:          getBetweenWord("c:\Schweiz\Thurgau\Orte","Schweiz\","\") = Thurgau
    Public Function getBetweenWords(ByVal InputString As String, ByVal AfterPhrase As String, ByVal NextPhrase As String) As String
        Dim r_getBetweenWords As String = ""
        Dim i_InputString As String = InputString
        If i_InputString.IndexOf(AfterPhrase) >= 0 Then
            i_InputString = i_InputString.Substring(i_InputString.IndexOf(AfterPhrase) + AfterPhrase.Length)
            If i_InputString.IndexOf(NextPhrase) >= 0 Then
                r_getBetweenWords = i_InputString.Substring(0, i_InputString.IndexOf(NextPhrase))
            End If
        End If
        Return r_getBetweenWords
    End Function

    'Zerstören der Objekte
    Private disposedValue As Boolean = False        ' So ermitteln Sie überflüssige Aufrufe

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: Anderen Zustand freigeben (verwaltete Objekte).
            End If

            pv_Tables = Nothing
            pv_Tags = Nothing

            ' TODO: Eigenen Zustand freigeben (nicht verwaltete Objekte).
            ' TODO: Große Felder auf NULL festlegen.
        End If
        Me.disposedValue = True
    End Sub
    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub

#Region " IDisposable Support "
    ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
#End Region

End Class

			
			
		

Hinterlasse einen Kommentar