как заставить функцию normalize-space () xpath работать? - PullRequest
8 голосов
/ 02 декабря 2009

Я сейчас пробую следующий xpath

//tr[normalize-space(td/text())='User Name']

чтобы получить все tr, которые содержат td, которые содержат 'User Name' или 'User Name' или ' User Name ', но они не работают, и я не знаю, что не так с запросом: (
данные, которые я хочу найти, имеют следующий формат

<tr><td>User Name</td></tr>
<tr><td>User     Name</td></tr>
<tr><td>  User Name   </td></tr>

Так, каков правильный формат для написания этого запроса xpath?

Edit: кажется, не работает, если данные в следующем формате

<tr><td>x</td><td>User Name</td></tr>
<tr><td>x</td><td>y</td><td>User     Name</td></tr>
<tr><td>x</td><td>y</td><td>z</td><td>  User Name   </td></tr>

Итак, как мне написать запрос xpath?
примечание: "// tr [normalize-space (td / text ()) = 'Имя пользователя']" не будет работать
но "// tr / td [normalize-space (text ()) = 'User Name']" будет работать (но я хочу получить tr, а не элемент td)

Ответы [ 2 ]

26 голосов
/ 02 декабря 2009

Теперь, когда вы отредактировали вопрос, это имеет смысл. Давайте рассмотрим этот вход:

<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), и обрабатывать все текстовые узлы внутри.

1 голос
/ 02 декабря 2009

Это прекрасно работает здесь:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(@"
    <table>
        <tr><td>User Name</td></tr>
        <tr><td> User   Name </td></tr>
        <tr><td>   User Name   </td></tr>
    </table>");

Console.WriteLine(
    xmlDoc.SelectNodes(
        "//tr[td[normalize-space(.) = 'User Name']]").Count); // shows "3"

Не могли бы вы обновить ваш вопрос с помощью действительного образца XML?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...