Теперь, когда вы отредактировали вопрос, это имеет смысл. Давайте рассмотрим этот вход:
<tr><td>x</td><td>User Name</td></tr>
и ваш нерабочий запрос:
//tr[normalize-space(td/text()) = 'User Name']
Теперь td/text()
означает «выбрать все дочерние текстовые узлы всех дочерних td
узлов текущего узла». В этом случае это даст набор узлов, состоящий из двух текстовых узлов: x
и User Name
.
Теперь вы вызываете normalize-space()
на этом наборе узлов. Тип единственного аргумента normalize-space()
- string?
. Поскольку набор узлов не является строкой, переходы включаются в разделе 3.2 рекомендации XPath 1.0:
Аргумент преобразуется в тип string, как если бы он вызывал функцию string ().
Теперь давайте посмотрим на определение string () в разделе 4.2:
Набор узлов преобразуется в строку, возвращая строковое значение узла в наборе узлов, который находится первым в порядке документов . Если набор узлов пуст, возвращается пустая строка.
В нашем примере первый узел «в порядке документа» - это текстовый узел x
, поэтому он будет использоваться; второй узел игнорируется. Таким образом, в итоге вы звоните normalize-space('x')
. Естественно, это не будет равно «Имя пользователя». Чтобы сделать эту работу, используйте:
//tr[td[normalize-space(text()) = 'User Name']]
Это может быть расшифровано как «выберите все tr
узлы, которые имеют дочерние td
узлы, первый дочерний узел text()
которых имеет нормализованное строковое значение User Name
» - что вам нужно Кроме того, вы можете упростить это до:
//tr[td[normalize-space() = 'User Name']]
Поскольку аргумент без аргументов normalize-space()
будет применяться к текущему узлу (который будет td
), и обрабатывать все текстовые узлы внутри.