Как мне удалить HTTP-ссылки с помощью ActiveSupport «starts_with», используя Nokogiri?

#ruby-on-rails #ruby #nokogiri

#ruby-on-rails #ruby #nokogiri

Вопрос:

Когда я пытаюсь это:

 item.css("a").each do |a|
  if !a.starts_with? 'http://'
     a.replace a.content
  end
end
  

Я получаю:

 NoMethodError: undefined method 'starts_with?' for #<Nokogiri::XML::Element:0x1b48a60> 
  

Редактировать:

Уверен, что есть более чистый способ, но это, кажется, работает.

 item.css("a").each do |a|
  unless a["href"].blank?
    if !a["href"].starts_with? 'http://' 
      a.replace a.content
    end
  end
end
  

Ответ №1:

Проблема в том, что вы пытаетесь использовать starts_with метод для объекта, который его не реализует.

 item.css("a").each do |a|
  

вернет XML-узлы в a . Они принадлежат Nokogiri. Что вы хотите сделать, это преобразовать узел в текст, но только ту часть, которую вы хотите проверить, которая, поскольку это параметр узла, может быть доступна следующим образом:

 a['href']
  

Итак, вы хотите использовать что-то вроде этого:

 item.css("a").each do |a|
  if !(a.starts_with?['href']('http://'))
     a.replace(a.content)
  end
end
  

Недостатком этого является то, что вам приходится проходить по каждому <a> тегу в документе, что может быть медленным на большой странице с большим количеством ссылок.

Альтернативный способ сделать это — использовать starts-with функцию XPath:

 require 'nokogiri'

item = Nokogiri::HTML('<a href="doesnt_start_with">foo</a><a href="http://bar">bar</a>')
puts item.to_html
  

какие результаты:

 >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
>> <html><body>
>> <a href="doesnt_start_with">foo</a><a href="http://bar">bar</a>
>> </body></html>
  

Вот как это сделать с помощью XPath:

 item.search('//a[not(starts-with(@href, "http://"))]').each do |a|
  a.replace(a.content)
end
puts item.to_html
  

Какие результаты:

 >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
>> <html><body>foo<a href="http://bar">bar</a>
>> </body></html>
  

Преимущество использования XPath для поиска узлов заключается в том, что все это выполняется на скомпилированном C, а не позволяет Ruby делать это.

Комментарии:

1. ОЧЕНЬ подробный ответ. Спасибо.

Ответ №2:

Разве этот метод не должен быть start_with?

Комментарии:

1. попробовал это на всякий случай, но та же ошибка. используя rails 1.9.2. Отредактированный вопрос, имел в виду !a.starts_with?