Выражение 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)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, '_')) >= 0
and number(substring-after(@id, '_')) <= 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',
''
)
=
''
]
Обратите внимание на следующее :
Использование стандартной функции XPath
starts-with()
.Использование стандартной функции XPath
string-length()
.Использование стандартной функции XPath
substring-after()
.Использование стандартной функции XPath
translate()
.