2011-01-06 15 views
12

Mam następujący kod HTMLPrzetwarzanie HTML z HTML Agility Pack i Linq

(..) 
<tbody> 
<tr> 
    <td class="name"> Test1 </td> 
    <td class="data"> Data </td> 
    <td class="data2"> Data 2 </td> 
</tr> 
<tr> 
    <td class="name"> Test2 </td> 
    <td class="data"> Data2 </td> 
    <td class="data2"> Data 2 </td> 
</tr> 
</tbody> 
(..) 

Informacja mam to nazwa => tak "Test1" & "Test2". Chcę wiedzieć, w jaki sposób mogę uzyskać dane, które są w "danych" i "danych2" w oparciu o nazwę mam.

Obecnie używam:

var data = 
    from 
     tr in doc.DocumentNode.Descendants("tr") 
    from 
     td in tr.ChildNodes.Where(x => x.Attributes["class"].Value == "name") 
    where 
     td.InnerText == "Test1" 
    select tr; 

Ale pojawia {"Object reference not set to an instance of an object."} kiedy próbuję spojrzeć w data

+0

Dokładnie, co próbujesz zrobić? A jaki jest kod, którego nie chcesz? –

+0

Hehe, przepraszam, zapomniałem go dodać, dodałem go teraz. –

+0

Czy możesz nam powiedzieć, jaki jest twój błąd? A może spodziewasz się, że tak się nie stanie? –

Odpowiedz

13

chodzi o swojej próbie, masz dwa problemy z kodem:

  1. ChildNodes jest dziwne - to również zwraca whitespace węzły tekstowe, które nie mają class atrybuty (nie mogą mieć atrybuty, z kierunek).
  2. Jak skomentował James Walford, spacje wokół tekstu są znaczące, prawdopodobnie chcesz je przyciąć.

Z tych dwóch korekt, następujące prace:

var data = 
     from tr in doc.DocumentNode.Descendants("tr") 
     from td in tr.Descendants("td").Where(x => x.Attributes["class"].Value == "name") 
    where td.InnerText.Trim() == "Test1" 
    select tr; 
1

Oto jedno podejście - najpierw przeanalizować wszystkie dane w strukturze danych, a następnie ją przeczytać. To jest trochę brudny i na pewno potrzebuje więcej walidacji, ale tu idzie:

HtmlWeb hw = new HtmlWeb(); 
HtmlDocument doc = hw.Load("http://jsbin.com/ezuge4"); 
HtmlNodeCollection nodes = doc.DocumentNode 
           .SelectNodes("//table[@id='MyTable']//tr"); 
var data = nodes.Select(
    node => node.Descendants("td") 
     .ToDictionary(descendant => descendant.Attributes["class"].Value, 
         descendant => descendant.InnerText.Trim()) 
     ).ToDictionary(dict => dict["name"]); 
string test1Data = data["Test1"]["data"]; 

Tu zwracam każdy <tr> do słownika, gdzie klasa <td> jest kluczem, a tekst jest wartością. Następnie włączam listę słowników do słownika słówek (tip - abstract that away), gdzie klucz name każdego .

0

zamiast

td.InnerText == "Test1" 

spróbować

td.InnerText == " Test1 " 

lub

d.InnerText.Trim() == "Test1" 
4

Oto sposób XPATH - hmmm ... wszyscy zdają się zapominać o XPath energii i skoncentrować się wyłącznie na C# XLinq, w tych dniach :-)

Funkcja ta pobiera wszystkie wartości danych związanych z nazwą:

public static IEnumerable<string> GetData(HtmlDocument document, string name) 
{ 
    return from HtmlNode node in 
     document.DocumentNode.SelectNodes("//td[@class='name' and contains(text(), '" + name + "')]/following-sibling::td") 
     select node.InnerText.Trim(); 
} 

na przykład ten kod będzie zrzucić wszystko '' test2 dane:

HtmlDocument doc = new HtmlDocument(); 
    doc.Load(yourHtml); 

    foreach (string data in GetData(doc, "Test2")) 
    { 
     Console.WriteLine(data); 
    } 
+0

Pomyślałem o jednej ścieżce z 'zawiera', ale ma to poważny problem: poszukiwanie' Test1' również znajdzie 'Test10',' NotTest1' i tak dalej. Naprawdę nie wiem wystarczająco dużo xpath, aby rozwiązać ten problem ... – Kobi

+0

@Kobi - Jeśli nie chcesz używać zawiera, możesz użyć =. Jeśli białe spacje są problemem, można je usunąć za pomocą normalizowanej przestrzeni, lub ten link zawiera więcej informacji: http://stackoverflow.com/questions/1852571/xpath-function-to-remove-white-space –

+2

Powód I preferujemy odpowiedź Linq na XPath, ponieważ ta ostatnia jest trudna do odczytania i zrozumienia. Ten pierwszy dokładnie wie, co jest zamierzone, i jeśli to konieczne, możesz podzielić zapytanie na podkwerendy, aby je zdebugować. XPath jest rozwlekły i niemożliwy do debugowania. Trudno jest zweryfikować, czy robi to dobrze, bez wielu danych testowych. Po prostu szukanie autorytatywnej strony na składni XPath jest nienawistnym obowiązkiem. Nadal kocham HAP, ale za każdym razem, gdy widzę stwierdzenie XPath, wzdrygam się. –

Powiązane problemy