Выражение xPath: получение элементов, даже если они не существуют - PullRequest
3 голосов
/ 20 декабря 2011

У меня есть это выражение xPath, которое я помещаю в htmlCleaner:

 //table[@class='StandardTable']/tbody/tr[position()>1]/td[2]/a/img

Теперь моя проблема в том, что оно меняется, и иногда элемент / a / img отсутствует.Поэтому я хотел бы получить выражение, которое получает все элементы

//table[@class='StandardTable']/tbody/tr[position()>1]/td[2]/a/img

при наличии / a / img и

//table[@class='StandardTable']/tbody/tr[position()>1]/td[2]

при отсутствии / a / img.

У кого-нибудь есть идеи, как это сделать?В другом вопросе я нашел что-то, что выглядит так, как будто это может помочь мне

descendant-or-self::*[self::body or self::span/parent::body]

, но я не понимаю этого.

Спасибо заранее.

Ответы [ 3 ]

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

Использование:

 (//table[@class='StandardTable']
     /tbody/tr)
         [position()>1]
                   /td[2]
                       [not(a/img)] 

|

 (//table[@class='StandardTable']
     /tbody/tr)
         [position()>1]
                   /td[2]
                      /a/img

Как правило, если мы хотим выбрать один набор узлов ($ns1), когда какое-либо условие $cond выполняется, и выбрать другой набор узлов ($ns2) в противном случае это можно указать с помощью следующего единственного выражения XPath :

$ns1[$cond] | $ns2[not($cond)]

В данном конкретном случае ns1 равно :

 (//table[@class='StandardTable']
     /tbody/tr)
         [position()>1]
                   /td[2]
                      /a/img

и ns2 равно :

 (//table[@class='StandardTable']
     /tbody/tr)
         [position()>1]
                   /td[2]

А $cond равно :

boolean( (//table[@class='StandardTable']
         /tbody/tr)
             [position()>1]
                       /td[2]
                          /a/img
        )
2 голосов
/ 20 декабря 2011

Вы можете выбрать объединение двух взаимоисключающих выражений (обратите внимание на оператор объединения |):

//table[@class='StandardTable']/tbody/tr[position()>1]/td[2]/a/img|
//table[@class='StandardTable']/tbody/tr[position()>1]/td[2][not(a/img)]

Когда первое выражение возвращает узлы, второе не будет (и наоборот)), что означает, что вы всегда получите только необходимые узлы.

Из ваших комментариев к ответу @ Dimitre я вижу, что HTMLCleaner не полностью поддерживает XPath 1.0.Тебе это не нужно.Вам просто нужен HTMLCleaner для разбора ввода, которое не правильно сформировано.Как только он выполнит эту работу, преобразуйте его вывод в стандартный org.w3c.dom.Document и обработайте его как XML.

Вот пример преобразования:

TagNode tagNode = new HtmlCleaner().clean("<html><div><p>test");
Document doc = new DomSerializer(new CleanerProperties()).createDOM(tagNode);

С этого момента, просто используйте JAXP с любой реализацией, которую вы хотите:

XPath xpath = XPathFactory.newInstance().newXPath();
Node node = (Node) xpath.evaluate("/html/body/div/p[not(child::*)]", 
                       doc, XPathConstants.NODE);
System.out.println(node.getTextContent());

Вывод:

test
0 голосов
/ 20 декабря 2011

Это некрасиво и может даже не сработать, но принцип должен:

//table[@class='StandardTable']/tbody/tr[position()>1]/td[2][exists( /a/img )]/a/img | //table[@class='StandardTable']/tbody/tr[position()>1]/td[2][not( exists( /a/img ) )]
...