none
Hilfe bei LINQ Abfrage von HTML Element RRS feed

  • Frage

  • Hallo,

    ich habe eine LINQ Abfrage für ein bestimmtes HTML Div-Element mit dem class-Attribut smallfont. Das klappt auch ohne Probleme, nur kann es vorkommen das zweimal dieselben Div Elemente hintereinander vorkommen. Hier möchte ich nur das erste Element selektieren.

    var boards = (from tbody in documentNode.Descendants("tbody")
                              where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                              from td in tbody.Descendants("td")
                              where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                              from a in td.Descendants("a")
                              where a.HasChildNodes && a.FirstChild.Name == "strong"
                              from div in td.Descendants("div") // Hier nur den ersten Treffer selektieren                         
                              where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont" // Hier nur den ersten Treffer selektieren
                              select new BoardViewModel() { 
                                  Name = a.FirstChild.InnerText, 
                                  Uri = a.GetAttributeValue("href", string.Empty), 
                                  Description = div.InnerText
                              }).ToArray();

    Der HTML Code:

    <tbody id="collapseobj_forumbit_3" style="">
        <td class="alt1Active" align="left" id="f23">
    	<div>
    	    <a href="#"><strong>Trainingsforum</strong></a>
    	</div>
    	<div class="smallfont">Das hier soll selektiert werden</div>
    	<div class="smallfont" style="margin-top:0px">Das soll nicht selektiert werden</div>
    

    Bitte um Hilfe! :)


    Montag, 28. Mai 2012 16:15

Antworten

  • hab gerade das Windows Phone SDk nicht hier, aber ich würde es erstmal ganz einfach im Select new mit folgendem versuchen:

     Description =(div.InnerText ).First()

    ansonsten den längeren weg.

                var boards = (from tbody in documentNode.Descendants("tbody")
                              where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                              from td in tbody.Descendants("td")
                              where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                              from a in td.Descendants("a")
                              where a.HasChildNodes && a.FirstChild.Name == "strong"
                              select new BoardViewModel()
                              {
                                  Name = a.FirstChild.InnerText,
                                  Uri = a.GetAttributeValue("href", string.Empty),
                                  Description =  (  from div in td.Descendants("div") // Hier nur den ersten Treffer selektieren                         
                                                    where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont" // Hier nur den ersten Treffer selektieren
                                                    select div.InnerText ).First()
                              }).ToArray();

    mfg

    Shmoo


    Beende meine FIAE Ausbiildung mit dem Prüfungsteil A am 20.06.2012. Suche Job im MS Umfeld in Wuppertal und Umgebung!


    Montag, 11. Juni 2012 16:17
  • Vielen Dank für eure Hilfe! 

    Das hier ist die endgültige Lösung:

                var boards = (from tbody in documentNode.Descendants("tbody")
                              where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                              from td in tbody.Descendants("td")
                              where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                              from a in td.Descendants("a")
                              where a.HasChildNodes && a.FirstChild.Name == "strong"
                              select new BoardViewModel()
                              {
                                  Name = a.FirstChild.InnerText,
                                  Uri = a.GetAttributeValue("href", string.Empty),
                                  Description = (from div in td.Descendants("div")
                                                 where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont"
                                                 select div.InnerText).FirstOrDefault()
                              }).ToArray();

    Ich muss bei Description FirstOrDefault() verwenden, da es auch möglich sein kann das welche keine Description haben, also kein Div mit der Klasse "smallfont"!

    Donnerstag, 14. Juni 2012 19:35

Alle Antworten

  • Dienstag, 29. Mai 2012 12:26
  • Hallo websocialist,

    Konkret, welches Ergebnis erwartest Du? Folgendes (wurde mit .ToArray[0] erzeugt)?

    [Code]

            private void button2_Click(object sender, RoutedEventArgs e)
            {
                HtmlWeb.LoadAsync("http://www.muskelschmiede.de/forum/", HtmlWeb_Loaded2);
            }
    
            private void HtmlWeb_Loaded2(object sender, HtmlDocumentLoadCompleted e)
            {
                if (e.Error == null)
                {
                    HtmlDocument doc = e.Document;
                    var node = (from tbody in doc.DocumentNode.Descendants("tbody")
                                where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                                from td in tbody.Descendants("td")
                                where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                                from a in td.Descendants("a")
                                where a.HasChildNodes && a.FirstChild.Name == "strong"
                                from div in td.Descendants("div") // Hier nur den ersten Treffer selektieren                         
                                where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont" // Hier nur den ersten Treffer selektieren
                                select new BoardViewModel()
                                {
                                    Name = a.FirstChild.InnerText,
                                    Uri = a.GetAttributeValue("href", string.Empty),
                                    Description = div.InnerText
                                }).ToArray()[0];
                                //select tbody).First();
                }
    
            }
    
            public class BoardViewModel
            {
                public string Name { get; set; }
                public string Uri { get; set; }
                public string Description { get; set; }
    
            }

    Grüße,

    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Dienstag, 29. Mai 2012 13:37
  • Mein erwartetes Ergebnis sieht man am besten an folgenden HTML.

    <tbody id="collapseobj_forumbit_3" style="">
        <td class="alt1Active" align="left" id="f23">
    	<div>
    	    <a href="#"><strong>Trainingsforum</strong></a>
    	</div>
    	<div class="smallfont">Alles rund ums Muskelaufbau-Training, alle Trainingsmethoden, Trainingspläne und Übungen.</div> <!-- Nur diese Node selektieren -->
    	<div class="smallfont" style="margin-top:0px">Unterforen:  Anfänger,  Training@home</div>
    
        <td class="alt1Active" align="left" id="f45">
    	<div>
    	    <a href="#"><strong>Trainingspläne</strong></a>	
    	</div>
    	<div class="smallfont">Präsentation und Fragen zu Trainigsplänen und Programmen.</div>
        </td>

    Es sind zwei td-Knoten mit dem class-Attribut "alt1Active vorhanden. Beide Knoten enthalten ein div-Element mit dem class-Attribut "smallfont", der erste Knoten hat dieses Element aber zweimal. Hier möchte ich nur den Inhalt des ersten div-Elements selektieren.

    Folgendes Ergebnis erwarte ich:

    BoardViewModel[0]:
    Name: Traininsforum
    Description: Alles rund ums Muskelaufbau-Training, alle Trainingsmethoden, Trainingspläne und Übungen.
    Url: #

    BoardViewModel[1]:
    Name: Trainingspläne
    Description: Präsentation und Fragen zu Trainigsplänen und Programmen.
    Url: #

    Mit meinem bisherigen Code erhalte ich aber zum ersten Treffer noch einen zweiten, mit einer anderen Description:

    BoardViewModel[0]:
    Name: Traininsforum
    Description: Alles rund ums Muskelaufbau-Training, alle Trainingsmethoden, Trainingspläne und Übungen.
    Url: #

    BoardViewModel[1]:
    Name: Trainingsforum
    Description: Unterforen: Anfänger, Training@home
    Url: #

    BoardViewModel[2]:
    Name: Trainingspläne
    Description: Präsentation und Fragen zu Trainigsplänen und Programmen.
    Url: #
    Dienstag, 29. Mai 2012 17:54
  • Mit meinem bisherigen Code erhalte ich aber zum ersten Treffer noch einen zweiten, mit einer anderen Description:

    BoardViewModel[0]:
    Name: Trainingsforum
    Description: Alles rund ums Muskelaufbau-Training, alle Trainingsmethoden, Trainingspläne und Übungen.
    Url: #

    BoardViewModel[1]:
    Name: Trainingsforum
    Description: Unterforen: Anfänger, Training@home
    Url: #

    BoardViewModel[2]:
    Name: Trainingspläne
    Description: Präsentation und Fragen zu Trainigsplänen und Programmen.
    Url: #

    Hallo websocialist,

    Ich bekomme dasselbe wie im Zitat aber mit folgendem Code (also nicht wie in Deinem Originalpost …siehe bei mir die && (td.Id == "f23" || td.Id == "f45")):

            private void HtmlWeb_Loaded2(object sender, HtmlDocumentLoadCompleted e)
            {
                if (e.Error == null)
                {
                    HtmlDocument doc = e.Document;
                    var node = (from tbody in doc.DocumentNode.Descendants("tbody")
                                where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                                from td in tbody.Descendants("td")
                                where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active" && (td.Id == "f23" || td.Id == "f45")
                                from a in td.Descendants("a")
                                where a.HasChildNodes && a.FirstChild.Name == "strong"
                                from div in td.Descendants("div") // Hier nur den ersten Treffer selektieren                         
                                where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont"// Hier nur den ersten Treffer selektieren
                                select new BoardViewModel()
                                {
                                    Name = a.FirstChild.InnerText,
                                    Uri = a.GetAttributeValue("href", string.Empty),
                                    Description = div.InnerText
                                }).ToArray();
    
                  
    
                }
    
            }
    
            public class BoardViewModel
            {
                public string Name { get; set; }
                public string Uri { get; set; }
                public string Description { get; set; }
    
            }

    Zeig mal Deinen Code mit dem Du das was im Zitat steht, bekommst.

    Danke und Grüße,

    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Mittwoch, 30. Mai 2012 08:55
  • Das was im Zitat Fett markiert ist möchte ich nicht im Ergebnis haben! Ich möchte nur das Ergebnis [0] und [2].  Mein Code ist noch derselbe wie bisher.
    Montag, 4. Juni 2012 19:16
  • hab gerade das Windows Phone SDk nicht hier, aber ich würde es erstmal ganz einfach im Select new mit folgendem versuchen:

     Description =(div.InnerText ).First()

    ansonsten den längeren weg.

                var boards = (from tbody in documentNode.Descendants("tbody")
                              where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                              from td in tbody.Descendants("td")
                              where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                              from a in td.Descendants("a")
                              where a.HasChildNodes && a.FirstChild.Name == "strong"
                              select new BoardViewModel()
                              {
                                  Name = a.FirstChild.InnerText,
                                  Uri = a.GetAttributeValue("href", string.Empty),
                                  Description =  (  from div in td.Descendants("div") // Hier nur den ersten Treffer selektieren                         
                                                    where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont" // Hier nur den ersten Treffer selektieren
                                                    select div.InnerText ).First()
                              }).ToArray();

    mfg

    Shmoo


    Beende meine FIAE Ausbiildung mit dem Prüfungsteil A am 20.06.2012. Suche Job im MS Umfeld in Wuppertal und Umgebung!


    Montag, 11. Juni 2012 16:17
  • Hallo Der_Shmoo,

    Dein Code ist ist die Lösung aber ich brauche noch immer die Erweiterung && (td.Id == "f23" || td.Id == "f45") in der Zeile where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active" && (td.Id == "f23" || td.Id == "f45") damit ich in boards folgendes bekomme:

    Wenn ich && (td.Id == "f23" || td.Id == "f45") rauslasse dann komme ich an den Breakpoint nicht an.

    Grüße,

    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Montag, 11. Juni 2012 16:38
  • Hatte mich nur an den Code // Hier nur denErsten gehalten, da ich auch kein VS hier habe konnte ich das eh nicht nachprüfen. gehe aber davon aus das du recht hast. solange es nun fluppt ist ja alles bestens.

    Hast du dies zufällig ausprobiert ob die ganz kurze Version funktioniert (Description =(div.InnerText).First()) ?

    würd mich mal interessieren..... aber ohne vs ist man so nackig^^

    mfg

    Shmoo


    Beende meine FIAE Ausbiildung mit dem Prüfungsteil A am 20.06.2012. Suche Job im MS Umfeld in Wuppertal und Umgebung!

    Montag, 11. Juni 2012 16:44
  • Hast du dies zufällig ausprobiert ob die ganz kurze Version funktioniert (Description =(div.InnerText).First()) ?

    würd mich mal interessieren...

    Hallo Der_Shmoo,

    Mit der folgenden Zeile bekomme ich bei der Description dasselbe wie bei Name:

    Description=(from div in td.Descendants("div") select div.InnerText).First()

    [C#]

                 var boards = (from tbody in doc.DocumentNode.Descendants("tbody")
                                  where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                                  from td in tbody.Descendants("td")
                                  where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active" && (td.Id == "f23" || td.Id == "f45")
                                  from a in td.Descendants("a")
                                  where a.HasChildNodes && a.FirstChild.Name == "strong"
                                  select new BoardViewModel()
                                  {
                                      Name = a.FirstChild.InnerText,
                                      Uri = a.GetAttributeValue("href", string.Empty),
                                      Description=(from div in td.Descendants("div") select div.InnerText).First()
                                  }).ToArray();

    [BILD]

    Nur wo smallfont auftaucht hat man die Description:

    Einfach Description =(div.InnerText ).First() funktioniert nicht, da er nicht weiß wer div ist.

    <tbody id="collapseobj_forumbit_3" style="">
        <td class="alt1Active" align="left" id="f23">
    	<div>
    	    <a href="#"><strong>Trainingsforum</strong></a>
    	</div>
    	<div class="smallfont">Alles rund ums Muskelaufbau-Training, alle Trainingsmethoden, Trainingspläne und Übungen.</div> <!-- Nur diese Node selektieren -->
    	<div class="smallfont" style="margin->Unterforen:  Anfänger,  Training@home</div>
    
        <td class="alt1Active" align="left" id="f45">
    	<div>
    	    <a href="#"><strong>Trainingspläne</strong></a>	
    	</div>
    	<div class="smallfont">Präsentation und Fragen zu Trainigsplänen und Programmen.</div>
        </td>

    Grüße,

    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Dienstag, 12. Juni 2012 06:44
  • Hallo websocialist,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Dienstag, 12. Juni 2012 06:46
  • Einfach Description =(div.InnerText ).First() funktioniert nicht, da er nicht weiß wer div ist.

     Stimmt.... da hätte man auch ohne VS drauf kommen können^^.

    danke für die antwort und das ausprobieren.

    MfG

    Shmoo


    Beende meine FIAE Ausbiildung mit dem Prüfungsteil A am 20.06.2012. Suche Job im MS Umfeld in Wuppertal und Umgebung!

    Donnerstag, 14. Juni 2012 16:13
  • Vielen Dank für eure Hilfe! 

    Das hier ist die endgültige Lösung:

                var boards = (from tbody in documentNode.Descendants("tbody")
                              where tbody.Attributes.Contains("id") && tbody.Attributes["id"].Value.StartsWith("collapseobj_forumbit_")
                              from td in tbody.Descendants("td")
                              where td.Attributes.Contains("class") && td.Attributes["class"].Value == "alt1Active"
                              from a in td.Descendants("a")
                              where a.HasChildNodes && a.FirstChild.Name == "strong"
                              select new BoardViewModel()
                              {
                                  Name = a.FirstChild.InnerText,
                                  Uri = a.GetAttributeValue("href", string.Empty),
                                  Description = (from div in td.Descendants("div")
                                                 where div.Attributes.Contains("class") && div.Attributes["class"].Value == "smallfont"
                                                 select div.InnerText).FirstOrDefault()
                              }).ToArray();

    Ich muss bei Description FirstOrDefault() verwenden, da es auch möglich sein kann das welche keine Description haben, also kein Div mit der Klasse "smallfont"!

    Donnerstag, 14. Juni 2012 19:35