2013-02-19 16 views
5

Mam tabeli jak topętla Html Agility Paczka poprzez wiersze tabeli i kolumn

<table border="0" cellpadding="0" cellspacing="0" id="table2"> 
    <tr> 
     <th>Name 
     </th> 
     <th>Age 
     </th> 
    </tr> 
     <tr> 
     <td>Mario 
     </td> 
     <th>Age: 78 
     </td> 
    </tr> 
      <tr> 
     <td>Jane 
     </td> 
     <td>Age: 67 
     </td> 
    </tr> 
      <tr> 
     <td>James 
     </td> 
     <th>Age: 92 
     </td> 
    </tr> 
</table> 

i chcesz używać HTML Agility Pack je analizować. Próbowałem tego kodu bezskutecznie:

foreach (HtmlNode row in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr")) 
{ 
    foreach (HtmlNode col in row.SelectNodes("//td")) 
    { 
     Response.Write(col.InnerText); 
    } 
} 

Co robię źle?

+2

Czy możesz opisać, co nie działa? – GolfWolf

+0

Dostaję nieokreśloną pętlę – mpora

+1

To działa dla mnie (no, nie do końca, otrzymuję nazwy Mario/Jane/James powtarzające się 4 razy). Zauważ, że '// td' _nie wybiera z bieżącego węzła only_ (jak można się spodziewać) _ ale z DocumentNode_. Jakiej wersji HtmlAgilityPack używasz? – agentnega

Odpowiedz

1

musiałem podać pełną XPath. Mam pełną XPath za pomocą Firebug z sugestią przez @Coda (https://stackoverflow.com/a/3104048/1238850) i skończyło się z tym kodem:

foreach (HtmlNode row in doc.DocumentNode.SelectNodes("/html/body/table/tbody/tr/td/table[@id='table2']/tbody/tr")) 
{ 
    HtmlNodeCollection cells = row.SelectNodes("td"); 
    for (int i = 0; i < cells.Count; ++i) 
    { 
     if (i == 0) 
     { Response.Write("Person Name : " + cells[i].InnerText + "<br>"); } 
     else { 
      Response.Write("Other attributes are: " + cells[i].InnerText + "<br>"); 
     } 
    } 
} 

Jestem pewien, może być napisany lepiej niż to, ale pracuje dla mnie teraz .

2

Dlaczego po prostu nie wybierzesz td s bezpośrednio?

foreach (HtmlNode col in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr//td")) 
    Response.Write(col.InnerText); 

Alternatywnie, jeśli naprawdę potrzebne tr s oddzielnie dla innej obróbki, upuść // i zrobić:

foreach (HtmlNode row in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr")) 
    foreach (HtmlNode col in row.SelectNodes("td")) 
     Response.Write(col.InnerText); 

Oczywiście, że będzie działać tylko wtedy, gdy td s są bezpośrednimi dzieci z tr s ale powinny być, prawda?


EDIT:

var cols = doc.DocumentNode.SelectNodes("//table[@id='table2']//tr//td"); 
for (int ii = 0; ii < cols.Count; ii=ii+2) 
{ 
    string name = cols[ii].InnerText.Trim(); 
    int age = int.Parse(cols[ii+1].InnerText.Split(' ')[1]); 
} 

Nie ma chyba bardziej efektowny sposób to zrobić z LINQ.

+0

Tak chcę użyć każdej kolumny do przetwarzania, jak widać druga kolumna jest mieszaniną liczb i tekstu, chciałbym wyodrębnić numer. Strona po prostu okrąża i nie ma wyniku po wypróbowaniu tego kodu. – mpora

3

Zabrakło mi kod i wyświetla tylko Nazwy, co jest poprawne, ponieważ Ages są definiowane przy użyciu nieprawidłowy HTML: <th></td> (prawdopodobnie literówka).

Nawiasem mówiąc, kod może zostać uproszczony do tylko jednej pętli:

foreach (var cell in doc.DocumentNode.SelectNodes("//table[@id='table2']/tr/td")) 
{ 
    Response.Write(cell.InnerText); 
} 

Oto kod użyłem do testu: http://pastebin.com/euzhUAAh

Powiązane problemy