Как выбрать таблицу, которая содержит определенное ключевое слово - c # - xpath - htmlagilitypack - PullRequest
3 голосов
/ 26 декабря 2011

Мне нужно собрать информацию со страницы продукта, у которой нет ни класса, ни идентификатора.Я использую htmlagilitypack и c # 4.0.

На этой странице продукта есть много таблиц с исходным кодом.Таблица цен содержит строку "KDV".Поэтому я хотел бы получить эту строку "KDV", содержащую таблицу.Как я могу это сделать?

Приведенный ниже xpath выберет все таблицы, например

string srxPathOfCategory = "//table";
var selectedNodes = myDoc.DocumentNode.SelectNodes(srxPathOfCategory);

Приведенный ниже код выбирает таблицу, но начинается с самой внешней таблицы.Мне нужно выбрать большую внутреннюю таблицу, которая содержит данную строку

//table[contains(., ' KDV')]

c #, xpath, htmlagilitypack

Ответы [ 2 ]

4 голосов
/ 26 декабря 2011

Приведенный ниже код выбирает таблицу, но начинается с самой внешней таблицы. я нужно выбрать большую внутреннюю таблицу, которая содержит данную строку

Используйте

//table
    [not(descendant::table) 
   and 
     .//text()[contains(., ' KDV')]
    ]

Это выбирает любой table в документе XML, который не имеет потомка table, и который имеет потомок текстового узла, который содержит строку " KDV".

Как правило, вышеприведенное выражение может выбирать много таких table элементов.

Если вы хотите, чтобы был выбран только один из них (скажем, первый), используйте это выражение XPath - обратите внимание на квадратные скобки :

   (//table
        [not(descendant::table) 
       and 
         .//text()[contains(., ' KDV')]
        ]
    )[1]

Помните : Если вы хотите выбрать первый элемент someName в документе, использовать это (как в принятом в настоящее время ответе) неправильно:

//someName[1]

Это второй наиболее часто задаваемый вопрос в XPath (после того, как выбирать элементы с нефиксированными именами в документе XML с пространством имен по умолчанию).

Вышеприведенное выражение фактически выбирает любой элемент someName в документе, то есть первый дочерний элемент его родителя - попробуйте его.

Причина такого неинтуитивного поведения заключается в том, что оператор XPath [] имеет более высокий приоритет (приоритет), чем псевдо-оператор //.

Правильное выражение, которое действительно выбирает только первый элемент someName (в любом документе XML), если таковой существует:

(//someName)[1]

Здесь скобки используются для явного переопределения приоритета оператора XPath по умолчанию.

1 голос
/ 26 декабря 2011

Там может быть более эффективный способ сделать это.Во всяком случае, это весь код, который я использовал для вашего случая, и он работает для меня:

        HtmlDocument doc = new HtmlDocument();
        string url = "http://www.pratikev.com/fractalv33/pratikEv/pages/viewProduct.jsp?pInstanceId=3138821";
        using (var response = (WebRequest.Create(url).GetResponse()))
        {
            doc.LoadHtml(new StreamReader(response.GetResponseStream()).ReadToEnd());
        }
        /*There is an bug in the xpath used here. Should have been 
          (//table/tr/td/font[contains(.,'KDV')])[1]/ancestor::table[2] 
          See Dimitre's answer for an explanation and an alternative / 
          more generic / (needless to say) better approach */
        string xpath = "//table/tr/td/font[contains(.,'KDV')][1]/ancestor::table[2]"; 
        HtmlNode table = doc.DocumentNode.SelectSingleNode(xpath);
...