Подтвердить что ты не робот

Как я могу создать селектор 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 (и, следовательно, может ли она использоваться для решения этой проблемы)?

Большое спасибо.

4b9b3361

Ответ 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 на этом этапе. Так что это хорошая отправная точка.