«HTML Agility Pack» XPath-запрос с логическим И

c# html-agility-pack xpath

Вопрос

Я пытаюсь найти таблицу в документе HTML с первыми двумя строками, содержащими 3 столбца с текстом.

Я экспериментировал с попыткой использовать следующий запрос, который я хочу вернуть узлу, который имеет первые 2 строки таблицы, содержит текст в первом столбце:

string xpath = @"//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]";
HtmlNode temp = doc.DocumentNode.SelectSingleNode(xpath);

Это не работает должным образом, mon.

Вот пример HTML, который является таблицей, которую я пытаюсь сопоставить:

    <table width="100%" cellpadding="0" border="0">
       <tbody>
       <tr>
          <td width="27%" valign="center"><b><font size="1" face="Helvetica">SOME TEXT<br></font></b></td>
          <td width="1%"></td>
          <td width="9%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="1%"></td>
          <td width="25%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="37%"></td>
       </tr>
       <tr>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">1<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
       </tr>
       </tbody>
</table>

Вы заметили, что столбцы 1,3,5 имеют текст в первых двух строках. Это то, что я пытаюсь сопоставить.

Принятый ответ

//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]

Есть много проблем с этим выражением XPath :

  1. //table//table выбирает любую table которая является потомком table . Однако в предоставленном XML-документе нет вложенных таблиц.

  2. table[//tr[1]//td[1]//*[contains(text(), *)] . //tr внутри предиката является абсолютным выражением Xpath - он выбирает все tr элементы во всем документе - не только в поддереве, укорененном этим элементом table . Скорее всего, вы хотите .//tr вместо //tr .

  3. //td[1] выбирает любой td элемент, который является первым td потомком его родителя, но, скорее всего, вам нужен только первый элемент td потомка. Если это так, вам нужно использовать это выражение XPath: (//td)[1]

  4. //*[contains(text(), *)] выбирает любой элемент, чей первый дочерний элемент текстового узла содержит строковое значение первого дочернего элемента элемента, но вы просто хотите проверить, что td имеет дочерний дочерний дочерний узел - это можно правильно выбрать с помощью: td[.//text()]

Сочетание исправлений всех этих проблем, что вы, вероятно, хотите, это что-то вроде :

  //table
     [(.//tr)[1]/td[1][.//text()]
    and
      (.//tr)[2]/td[1][.//text()]
     ]

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

//table
  [descendant::tr[1]/td[1][descendant::text()]
 and
   descendant::tr[1]/td[1][descendant::text()]
  ]


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow