Rolf B: Telefonbuch Rückwärtssuche

Beitrag lesen

Hallo Norbert,

ja, es gibt im Forum inline-Code, mit Backticks ` eingefasst.

Und Block-Code, mit zwei Zeilen eingefasst, in denen ~~~ steht.

Danke für den Hinweis auf das HtmlAgilityPack und das HtmlDocument Objekt darin. Das hatte ich neulich schon gefragt, aber das ist wohl untergegangen.

Ich würde Dir gerne sagen, dass es bessere Methoden zum Selektieren von Nodes gibt als das Herumturnen auf den ChildNodes Listen. Es wäre schön, wenn HtmlAgilityPack CSS Selektoren anbieten würde. Aber das ist noch "coming soon", bzw. man braucht noch eine Library.

Es gibt aber auch SelectNodes und SelectSingleNode, die XPath verwenden. Das ist eine andere Abfragesyntax, die nicht ganz einfach ist. Unser Wiki hat was dazu, ob man es versteht, weiß ich nicht. XPath-Dokumentationen neigen zu gruseliger Abstraktheit. Von XPath gibt's Versionen, und .net kennt nur XPath 1.0, das macht es nicht einfacher. Aber was wir brauchen, ist relativ easy:

dim entries = doc.SelectNodes("//div[starts-with(@id, 'entry_')]")
if entries IsNot Nothing
   for each eintrag as HtmlNode in entries
      dim nameElement = eintrag.SelectSingleNode(".//h2/a")
      dim addressElement = eintrag.SelectSingleNode(".//address")
      if nameElement IsNot Nothing
         ...
      end if

      if addressElement IsNot Nothing
         ...
      end if
   next
end if

Nehmen wir die XPathes auseinander:

//div[starts-with(@id, 'entry_')]

Das // bedeutet: Beginne am Wurzelknoten des Dokuments, und durchsuche den ganzen Dokumentenbaum nach dem, was hiernach steht. Da steht div, damit spezifiziert man XML (oder HTML) Elemente. Das Dokument wird also komplett nach divs durchsucht.

Hinter dem div steht was in eckigen Klammern. Das bedeutet: Suche die divs, die eine Zusatzbedingung erfüllen. Diese Zusatzbedingung ist eine weitere XPath-Query, die relativ zu dem div ausgeführt wird, für das die Zusatzbedingung geprüft werden muss.

Nun muss man wissen, dass man in XPath in unterschiedliche Richtungen suchen kann. Wenn man sich auf einem Element im Dokument aufhält, gibt's davon mehrere: Nach oben (Elternknoten), nach unten (Kindknoten), zur Seite (Geschwisterknoten), und dann noch die Attribute. Wir müssen das id-Attribut prüfen, also entlang der Attributachse laufen, und dafür dient das @ Kürzel.

@id sucht also an dem div das id Attribut. Und dann gibt's noch ein paar Funktionen. starts-with prüft, ob @id mit 'entry_' beginnt.

Also alles zusammen: //div[starts-with(@id, 'entry_')] findet alle div Elemente, deren id mit 'entry_' beginnt.

Das Ergebnis von SelectNodes ist eine HtmlNodeCollection. Allerdings, das ist ein Blödsinn der .net XML Libraries, wenn es gar keinen Eintrag gab, kommt Nothing zurück, keine leere Collection. Deswegen die Abfrage auf IsNot Nothing, bevor man die Treffer untersucht.

Das geschieht, indem man die entries mit For Each durchläuft.

Innerhalb der Entries wird nun nach Name und Adresse gesucht. Der Name ist ein a Element in einem h2 Element. Das suchen wir mit dem XPath .//h2/a. .// bedeutet: Durchsuche alle Elemente unterhalb des aktuellen Elements, und auch ihre Kinder und Kindeskinder. Das aktuelle Element ist das, auf dem SelectNodes aufgerufen wird. Analog wird das address Element gesucht.

Die Rückgabewerte müssen noch auf Nothing geprüft werden, falls nichts gefunden wird. Wie Du reagieren willst, wenn Name oder Adresse fehlen (Leerstring anzeigen, diesen Treffer überspringen) musst Du für Dich entscheiden.

Auf diese Weise kommst Du mit relativ kompaktem Code an die richtigen Elemente heran, würde ich behaupten.

Rolf

--
sumpsi - posui - obstruxi