Как я могу создать нечувствительный к регистру селектор Xpath? - PullRequest
18 голосов
/ 17 февраля 2010

Я использую nokogiri для выбора атрибута «ключевые слова» следующим образом:

puts page.parser.xpath("//meta[@name='keywords']").to_html

На одной из страниц, с которыми я работаю, есть метка ключевых слов с заглавной буквой "K", что побудило меня сделать запрос нечувствительным к регистру.

<meta name="keywords"> AND <meta name="Keywords"> 

Итак, мой вопрос: каков наилучший способ сделать регистр нечувствительным к регистру?

РЕДАКТИРОВАТЬ Предложение Томалака ниже прекрасно подходит для этой конкретной проблемы. Я хотел бы также использовать этот пример, чтобы помочь лучше понять нокогири, и у меня есть пара вопросов, которые меня интересуют и которые не увенчались успехом. Например, подходит ли регулярное выражение «псевдо-классы» Документы Нокогири для такой проблемы?

Мне также любопытно узнать о методе совпадений? () В нокогири. Я не смог найти каких-либо разъяснений по поводу метода. Имеет ли это какое-либо отношение к концепции «совпадений» в XPath 2.0 (и, следовательно, может ли оно использоваться для решения этой проблемы)?

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

Ответы [ 2 ]

21 голосов
/ 11 января 2012

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

9 голосов
/ 17 февраля 2010

Обернуто для удобочитаемости:

puts page.parser.xpath("
  //meta[
    translate(
      @name, 
      'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
      'abcdefghijklmnopqrstuvwxyz'
    ) = 'keywords'
  ]
").to_html

В XPath 1.0 нет функции "в нижнем регистре", поэтому вы должны использовать translate() для подобных вещей.При необходимости добавьте акцентированные буквы.

...