Выражение xpath для сопоставления, подобного регулярному выражению?

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

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

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

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

РЕДАКТИРОВАТЬ

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

Кстати, я использую Mechanize / nokogiri (рубин)

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

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)

Решение

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

XPath 1.0:

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

Изменить № 2: OP внес изменение в вопрос. У меня работает следующее, еще более сокращенное выражение 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.

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

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

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

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

doc.search('div').attr_matches('id', /post_message_\d{1,8}/)

Как уже указывалось, в 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().