#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?