Aus HTML select suchen

06/28/2012 20:42 Whoknowsit#1
Hi,

der Titel ist vielleicht etwas unglücklich gewählt, aber mir fiel nichts anderes ein :D Ich stehe vor einem selten dämlichen Problem und komme einfach nicht auf die Lösung.

Ich möchte effektiv die Werte verschiedener Input-Felder aus einem HTML-Dokument auslesen (<input.... value=XXX). Das kriege ich mit Hängen und Würgen über reguläre Ausdrücke hin.

Was aber gar nicht gelingen will ist, den Wert einer Selektion auszulesen d.h. ich habe beispielsweise ein Select:

HTML Code:
<select name="bla">
<option value="xxx">xxx</option>
<option value="yyy" selected="selected">yyy</option>
<option value="zzz">zzz</option>
</select>
Ich möchte nun mittels VB.NET den Wert auslesen, der selektiert ist, also yyy. Irgendjemand irgendeine Idee, wie ich das am effektivsten umsetzen kann?
06/28/2012 21:20 nkkk#2
du kannst z.B.den wert ermitteln indem du den string erst zu einerm Xdocument parst welches du dann per linq abragt, in C# sähe das so aus:

PHP Code:
            string s1 "<select name=\"bla\"> <option value=\"xxx\">xxx</option> <option value=\"yyy\" selected=\"selected\">yyy</option> <option value=\"zzz\">zzz</option> </select>";
            
XDocument doc XDocument.Parse(s1);
            var 
query1 from simpleItem in doc.Descendants("option")
                         
where simpleItem.Attribute("selected") != null && simpleItem.Attribute("selected").Value == "selected"
                         
select simpleItem.Attribute("value");
            
string val1 query1.First().Value;
            
//val 1 ist jetzt "yyy" 
06/28/2012 22:57 Muddy Waters#3
Warum machst du es in dem Fall nicht auch einfach per RegExp?

Code:
<.+selected="selected".*>([^<]*)</.+>
Funktioniert sowas nicht?
06/28/2012 23:01 Whoknowsit#4
Das Problem ist, dass ich zum Einen mehrere Selects auf der Seite habe und meine Regex-Versuche bisher gescheitert sind und zum Anderen, dass ich bei Möglichkeit auf Reguläre Ausdrücke verzichten wollen würde.

Diese XPath-Geschichte gefällt mir eigentlich ganz gut, ich krieg sie nur noch nicht zum Laufen :D Ich glaube nämlich, dass es kaum einfacher und performanter geht.

Code:
Imports System.Xml.Linq

'....'

        Dim s1 As String = "<select name=""bla""> <option value=""xxx"">xxx</option> <option value=""yyy"" selected=""selected"">yyy</option> <option value=""zzz"">zzz</option> </select>"
        Dim doc As XDocument = XDocument.Parse(s1)
        Dim query1 = From simpleItem In doc.Descendants("option") _
                     Where simpleItem.Attribute("name") = "bla" _
                     And simpleItem.Attribute("selected").Value = "selected" _
                     Select simpleItem.Attribute("value")
        Dim val1 As String = query1.First().Value
Das schmeißt leider nur so mit Exceptions um sich:

Quote:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
06/28/2012 23:20 nkkk#5
Quote:
Originally Posted by Whoknowsit View Post
Das Problem ist, dass ich zum Einen mehrere Selects auf der Seite habe und meine Regex-Versuche bisher gescheitert sind und zum Anderen, dass ich bei Möglichkeit auf Reguläre Ausdrücke verzichten wollen würde.

Diese XPath-Geschichte gefällt mir eigentlich ganz gut, ich krieg sie nur noch nicht zum Laufen :D Ich glaube nämlich, dass es kaum einfacher und performanter geht.

Code:
Imports System.Xml.Linq

'....'

        Dim s1 As String = "<select name=""bla""> <option value=""xxx"">xxx</option> <option value=""yyy"" selected=""selected"">yyy</option> <option value=""zzz"">zzz</option> </select>"
        Dim doc As XDocument = XDocument.Parse(s1)
        Dim query1 = From simpleItem In doc.Descendants("option") _
                     Where simpleItem.Attribute("name") = "bla" _
                     And simpleItem.Attribute("selected").Value = "selected" _
                     Select simpleItem.Attribute("value")
        Dim val1 As String = query1.First().Value
Das schmeißt leider nur so mit Exceptions um sich:
Quote:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
ich vermute das liegt daran, dass einige tags kein selected sttibut haben und Attribute("selected") dementprechend null zurückgibt.
deswegen hatte ich auch oben in menem code
Code:
where [COLOR="RED"] simpleItem.Attribute("selected") != null && [/COLOR]simpleItem.Attribute("selected").Value == "selected"
stehen
06/28/2012 23:22 Whoknowsit#6
Das hatte ich nachträglich entfernt, ist leider nicht das Problem. So sah es ursprünglich aus:

Code:
        Dim s1 As String = "<select name=""bla""> <option value=""xxx"">xxx</option> <option value=""yyy"" selected=""selected"">yyy</option> <option value=""zzz"">zzz</option> </select>"
        Dim doc As XDocument = XDocument.Parse(s1)
        Dim query1 = From simpleItem In doc.Descendants("option") _
                     Where simpleItem.Attribute("name") = "bla" _
                     And simpleItem.Attribute("selected") IsNot Nothing _
                     And simpleItem.Attribute("selected").Value = "selected" _
                     Select simpleItem.Attribute("value")
        Dim val1 As String = query1.First().Value
EDIT:

Okay... Zumindest habe ich einen Denkfehler gefunden:

Code:
Where simpleItem.Attribute("name") = "bla"
das wird nicht gehen, wenn ich mich auf "option" beziehe. Richtig? Aber auch das ist nicht das Problem.
06/28/2012 23:24 nkkk#7
njaa
doc.Descendants("option")
gibt ja die liste aller <option> taggs zurück, diese haben aber kein attribut "name" deswegen wirst du wohl bei impleItem.Attribute("name") = "bla" den fehler bekommen
06/28/2012 23:32 Whoknowsit#8
Wie gesagt: Das ist leider auch nicht das Problem :D Zumal ich mir noch nicht darüber im Klaren bin, wie ich eben explizit die Optionen des Select-Elements mit dem Namen "bla" entsprechend auswerten könnte. Arbeite das 1. Mal mit XDocument und die Doku hält sich diesbezüglich leider sehr... Uninformativ :D
06/28/2012 23:45 nkkk#9
hmm, habs jetzt mal in visual studio kopiert und den fehler gefunden:
der "And" operator in VB wertet IMMER beide terme aus im gegensatz du dem && Operator aus C# der wenn das erste ergebnis schon falsch ist das zweite garnicht mehr auswertet.

was du bruchtst ist der "AndAlso" operator der sich genauso verhält wie "&&" in C#. Dieser code solte funktionieren:
Code:
        Dim doc As XDocument = XDocument.Parse(s1)
        Dim query1 = From simpleItem In doc.Descendants("option") _
                     Where simpleItem.Attribute("selected") IsNot Nothing _
                     AndAlso simpleItem.Attribute("selected").Value = "selected" _
                     Select simpleItem.Attribute("value")
        Dim val1 As String = query1.First().Value
PS: war das "CODE" tag schon immer mehrfarbig ??
06/29/2012 00:19 Whoknowsit#10
Ich Idiot, ich hatte sogar AndAlso zuerst drin stehen :D Oky, also grundtechnisch ist die Frage gelöst. Bleibt nurnoch die Bitte, dass du mir irgendwie erklären kannst, wie ich die "Suche" auf das Element "bla" beschränken kann. Also dass ich nur die Optionen aus dem Select-Feld mit dem Namen "bla" entsprechend vergleiche.

Ich könnte hier mit meiner selbstgebauten Stringbetween-Funktion arbeiten, aber das ist unschön, wenn man vergleichsweise doch eine wirklich gute Lösung nutzen könnte. Weiß halt nicht, ob das geht, kann mir aber nicht vorstellen, dass es nicht geht :)

Zum Thema Code-Tag: Ich kenn's nur farbig :D Wobei man selbst gepostete Code-Container nur dann farbig sieht, wenn man die Seite nach der Beitragserstellung aktualisiert :p

Danke dir auf jeden Fall bis hierher.
06/29/2012 01:29 nkkk#11
Quote:
Originally Posted by Whoknowsit View Post
Ich Idiot, ich hatte sogar AndAlso zuerst drin stehen :D Oky, also grundtechnisch ist die Frage gelöst. Bleibt nurnoch die Bitte, dass du mir irgendwie erklären kannst, wie ich die "Suche" auf das Element "bla" beschränken kann. Also dass ich nur die Optionen aus dem Select-Feld mit dem Namen "bla" entsprechend vergleiche.

Ich könnte hier mit meiner selbstgebauten Stringbetween-Funktion arbeiten, aber das ist unschön, wenn man vergleichsweise doch eine wirklich gute Lösung nutzen könnte. Weiß halt nicht, ob das geht, kann mir aber nicht vorstellen, dass es nicht geht :)

Zum Thema Code-Tag: Ich kenn's nur farbig :D Wobei man selbst gepostete Code-Container nur dann farbig sieht, wenn man die Seite nach der Beitragserstellung aktualisiert :p

Danke dir auf jeden Fall bis hierher.
also wenn ich dich richtig verstanden habe wisst du mit der methode eine ganze website auswerten?

das geht nur wenn die website in gültigem XML geschireben ist was auch bei normalen XHTML seiten die man im internet findet eher selten ist.
zum einen liefern mache webseiten sehr fehlerhaftes html(tags werden geöffnet aber nicht geschlossen u.s.w.)
aber auch code wie dieser
HTML Code:
<HTML>
<img src="http://beispiel.com/images/img1.png?a=1&b=5"  />
</HTML>
ist kein gültiges xml wegen dem "&" zeichen.

hast du gültiges xml vorliegen ist da aber relertiv einfach, ist z.B. s1 =
Code:
<?xml version="1.0" encoding="utf-8" ?>
<basee>
  <irgendwas></irgendwas>
  <select name="name1">
    <option value="xxx">xxx</option>
    <option value="yyy" selected="selected">yyy</option>
    <option value="zzz">zzz</option>
  </select>
  <nochwas>
    <select name="name2">
      <option value="xxx">xxx</option>
      <option value="234" selected="selected">234</option>
      <option value="zzz">zzz</option>
      <malewasanderes>36546</malewasanderes>
    </select>
  </nochwas>
</basee>
kann man den selecteteten wert vom selct "name2" auslesen mit :
Code:
            XDocument doc = XDocument.Parse(s1);

            var querySelect = from xelement in doc.Descendants("select")
                              where xelement.Attribute("name") != null && xelement.Attribute("name").Value == "name2"
                              select xelement;
            var gesuchtesSelect = querySelect.First();

            var queryOptions = from simpleItem in gesuchtesSelect.Descendants("option")
                         where simpleItem.Attribute("selected") != null && simpleItem.Attribute("selected").Value == "selected"
                         select simpleItem;
            var selectedOptionValue = queryOptions.First().Value;
selectedOptionValue ist dann hinterher 234
06/29/2012 09:28 boxxiebabee#12
Hab mir jetzt nicht alles durchgelesen, aber ich rate dir von Regex ab, wenn es ums parsen von HTML geht. Benutz lieber [Only registered and activated users can see links. Click Here To Register...] .
06/29/2012 23:25 Whoknowsit#13
Danke euch, hat mir sehr geholfen :) Nun kann ich mein kleines Tool endlich fertig machen :D
06/30/2012 15:19 -PinkiWinki-#14
Quote:
Originally Posted by boxxiebabee View Post
Hab mir jetzt nicht alles durchgelesen, aber ich rate dir von Regex ab, wenn es ums parsen von HTML geht. Benutz lieber [Only registered and activated users can see links. Click Here To Register...] .
!
Die Lib ist zum Html parsen wirklich das beste was man nehmen kann, vor allem in Verbindung mit XPath ;).

Code:
string content = System.IO.File.ReadAllText(@"D:\test.html");

HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(content);

HtmlAgilityPack.HtmlNode node = doc.DocumentNode.SelectSingleNode("//select[@name='bla']//option[@selected='selected']");
Console.WriteLine(node.GetAttributeValue("value", string.Empty));