xpath выражение для соответствия регулярному выражению? - PullRequest
12 голосов
/ 28 февраля 2009

Я хочу найти идентификатор Div в HTML-документ с определенным шаблоном. Я хочу сопоставить этот шаблон в регулярном выражении:

foo_([[:digit:]]{1.8})

с использованием xpath. Каков эквивалент xpath для вышеуказанного шаблона?

Я застрял с //div[@id="foo_ и что дальше? Если бы кто-то мог продолжить юридическое выражение для этого.

EDIT

Извините, я думаю, что мне нужно уточнить больше. На самом деле это не foo_, это post_message_

Кстати, я использую механизированный / нокогири (рубин)

Вот фрагмент:

html_doc = Nokogiri::HTML(open(myfile))
message_div =  html_doc.xpath('//div[substring(@id,13) = "post_message_" and substring-after(@id, "post_message_") => 0 and substring-after(@id, "post_message_") <= 99999999]') 

Все еще не удалось. Сообщение об ошибке:

Не удалось оценить выражение '//div[substring(@id,13) = "post_message_" and substring-after(@id, "post_message_") => 0 and substring-after(@id, "post_message_") <= 99999999]' (Nokogiri :: XML :: XPath :: SyntaxError)

Ответы [ 4 ]

15 голосов
/ 28 февраля 2009

Как насчет (обновлено):

XPath 1.0:

"//div[substring-before(@id, '_') = 'foo' 
       and substring-after(@id, '_') >= 0 
       and substring-after(@id, '_') <= 99999999]"

Редактировать # 2: ОП внес изменения в вопрос. Следующее, еще более сокращенное выражение XPath 1.0 работает для меня:

"//div[substring(@id, 1, 13) = 'post_message_' 
       and substring(@id, 14) >= 0 
       and substring(@id, 14) <= 99999999]"

XPath 2.0 имеет удобную matches() функцию :

"//div[matches(@id, '^foo_\d{1,8}$')]"

Помимо лучшей переносимости, я ожидал бы, что числовое выражение (стиль XPath 1.0) будет работать лучше, чем тест регулярного выражения, хотя это станет заметным только при обработке больших наборов данных.


Оригинальная версия ответа:

"//div[substring-before(@id, '_') = 'foo' 
       and number(substring-after(@id, '_')) = substring-after(@id, '_') 
       and number(substring-after(@id, '_')) &gt;= 0 
       and number(substring-after(@id, '_')) &lt;= 99999999]"

Использование функции number() не является необходимым, поскольку операторы математического сравнения неявно приводят свои аргументы к числам, любые нечисловые значения станут NaN, и тесты больше / меньше, чем пройдут.

Я также убрал кодировку угловых скобок, поскольку это требование XML, а не требование XPath.

5 голосов
/ 28 февраля 2009

Как уже отмечалось, в XPath 2.0 было бы хорошо использовать его стандартные возможности регулярных выражений с такой функцией, как matches() функция.

Одно возможное XPath 1.0 решение :

//div[starts-with(@id, 'post_message_')
    and
      string-length(@id) = 21
    and
      translate(substring-after(@id, 'post_message_'), 
                '0123456789', 
                ''
                )
     =
      ''
      ] 

Обратите внимание на следующее :

  1. Использование стандартной функции XPath starts-with().

  2. Использование стандартной функции XPath string-length().

  3. Использование стандартной функции XPath substring-after().

  4. Использование стандартной функции XPath translate().

2 голосов
/ 28 февраля 2009

Или используйте совпадения функции xpath (строка, шаблон).

  <xsl:if test="matches(name(.),'foo_')">

К сожалению, это не регулярное выражение, но этого может быть достаточно, если у вас нет других ненужных тегов foo_, тогда, я думаю, вы можете добавить еще несколько проверок "если", чтобы исключить их.

0 голосов
/ 02 июня 2013

Nikkou делает это очень простым и читаемым:

doc.search('div').attr_matches('id', /post_message_\d{1,8}/)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...