Как я могу создать селектор Xpath, нечувствительный к регистру nokogiri?
Я использую nokogiri для выбора атрибута "keywords" следующим образом:
puts page.parser.xpath("//meta[@name='keywords']").to_html
Одна из страниц, с которыми я работаю, имеет метку ключевых слов с капиталом "К", которая побудила меня сделать регистр запроса нечувствительным.
<meta name="keywords"> AND <meta name="Keywords">
Итак, мой вопрос: какой лучший способ сделать случай выбора nokogiri нечувствительным?
EDIT Предложение Tomalak ниже отлично подходит для этой конкретной проблемы. Я также хотел бы использовать этот пример, чтобы лучше понять nokogiri, хотя и иметь пару вопросов, о которых мне интересно, и их не удалось найти. Например, являются ли псевдоязыки регулярных выражений Nokogiri Docs подходящими для такой проблемы?
Мне также интересно узнать о методах матчей?() в nokogiri. Я не смог найти никаких разъяснений по методу. Имеет ли это какое-либо отношение к концепции "совпадений" в XPath 2.0 (и, следовательно, может ли она использоваться для решения этой проблемы)?
Большое спасибо.
Ответы
Ответ 1
Обернуто для удобочитаемости:
puts page.parser.xpath("
//meta[
translate(
@name,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'
) = 'keywords'
]
").to_html
В XPath 1.0 нет функции "нижнего регистра", поэтому для этого нужно использовать translate()
. При необходимости добавьте буквы с акцентом.
Ответ 2
Nokogiri позволяет выполнять пользовательские функции XPath. В nokogiri документы, на которые вы ссылаетесь, показывают определение встроенного класса, когда вы используете его только один раз. Если у вас много пользовательских функций, или если вы используете нечувствительность к регистру, вы можете определить его в классе.
class XpathFunctions
def case_insensitive_equals(node_set, str_to_match)
node_set.find_all {|node| node.to_s.downcase == str_to_match.to_s.downcase }
end
end
Затем вызовите его, как и любую другую функцию XPath, передав экземпляр вашего класса в качестве второго аргумента.
page.parser.xpath("//meta[case_insensitive_equals(@name,'keywords')]",
XpathFunctions.new).to_html
В вашем методе Ruby node_set
будет привязан к Nokogiri::XML::NodeSet
. В случае, когда вы передаете значение атрибута, например @name
, это будет NodeSet с одним Nokogiri::XML::Attr
. Поэтому вызов to_s
на нем дает вам свою ценность. (В качестве альтернативы вы можете использовать node.value
.)
В отличие от XPath translate
, где вы должны указывать каждый символ, это работает со всеми символами и кодировками символов, которые Ruby работает.
Кроме того, если вы заинтересованы в том, чтобы делать другие вещи, кроме нечувствительного к регистру соответствия, которое XPath 1.0 не поддерживает, это просто Ruby на этом этапе. Так что это хорошая отправная точка.