Выражение xpath для регулярного сравнения?
Я хочу найти div id в html-документе с определенным шаблоном.
Я хочу сопоставить этот шаблон в регулярном выражении:
foo_([[:digit:]]{1.8})
используя xpath. Каков эквивалент xpath для вышеуказанного шаблона?
Я застрял с //div[@id="foo_
, и что тогда? Если кто-то может продолжить юридическое выражение для него.
ИЗМЕНИТЬ
Извините, я думаю, что мне нужно уточнить больше. На самом деле это не foo_
, it post_message_
Btw, я использую mechanize/nokogiri (ruby)
Здесь фрагмент:
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)
Ответы
Ответ 1
Как насчет этого (обновленного):
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, '_')) >= 0
and number(substring-after(@id, '_')) <= 99999999]"
Использование функции number()
не требуется, потому что операторы математического сопоставления неявно принуждают свои аргументы к номерам, любые не-номера станут NaN
, и тесты, превышающие/меньше, будут терпеть неудачу.
Я также удалил кодировку угловых скобок, поскольку это требование XML, а не требование XPath.
Ответ 2
Как уже указывалось, в 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',
''
)
=
''
]
Обратите внимание на следующее:
Ответ 3
Или используйте соответствия функции xpath (строка, шаблон).
<xsl:if test="matches(name(.),'foo_')">
К сожалению, это не регулярное выражение, но этого может быть достаточно, если у вас нет других тэгов foo_, которые вам не нужны, тогда я думаю, вы можете добавить еще несколько "если", чтобы отбросить их.
Ответ 4
Nikkou делает это очень простым и понятным:
doc.search('div').attr_matches('id', /post_message_\d{1,8}/)