Проблема получения значения атрибута узла XML с помощью nokogiri - PullRequest
1 голос
/ 24 января 2011

Я пытаюсь проанализировать XML-файл из iTunes, используя nokogiri и rails 3.

Вот мой код:

itunes_top_300 = Nokogiri.HTML(open("http://itunes.apple.com/us/rss/toppodcasts/limit=300/xml"))

itunes_top_300.search('//entry').each do |podcast|
  url = podcast.xpath("//[@href]]").text
  return podcast.url
end

Когда я загружаю представление, которое вызывает этот метод, я получаю:

неопределенный метод `url '

Вот XML, который я пытаюсь разобрать:

http://itunes.apple.com/us/rss/toppodcasts/limit=300/xml

Заранее спасибо,

Harris

1 Ответ

4 голосов
/ 24 января 2011

Несмотря на то, что вы заявили, что ваш код снова работает, позвольте мне указать на некоторые недостатки в вашем коде:

  1. Вы просите Nokogiri разобрать канал RSS RSS как HTML.Вместо этого вы должны использовать Nokogiri::XML( ... );Ничего страшного, и не причина этой проблемы.

  2. Вы используете return внутри каждого из них.В показанном вами коде это обычно вызывает LocalJumpError: unexpected return.Очевидно, что вы используете этот код внутри метода (который вы нам не показали).Использование return внутри блока не приводит к выходу из блока, а скорее вызывает возврат метода вложения.Что касается того, что вы, вероятно, хотите вместо этого, читайте дальше:

  3. Вы создаете локальную переменную url, но не используете ее.

  4. Я предполагаю, что вы пытались найти только url из каждого канала.Однако, используя XPath //[@href], вы действительно находили каждый элемент в документе, который имеет атрибут href="...".Вы повторно находите этот полный набор элементов для каждого entry в документе.(За исключением того, что из-за оператора return вы выходили раньше.) А затем, запросив text элемента, вы бы ничего не получили.

  5. Что касается фактической ошибки, которую вы получили, вы пытались получить доступ к podcast.url, но элементы Nokogiri не имеют метода url.

Учитывая схему каналов изURL, который вы указали, вот несколько способов получить массив атрибута href="..." каждого entry/link в документе в порядке возрастания простоты и предпочтения:

Почти прямой перевод

urls = []
itunes_top_300.search('//entry').each do |podcast|
  # Find the first element below the current one that has an href attribute
  # and then get the value of that attribute
  url = podcast.at_xpath(".//[@href]")['href']

  # Add this url to the array
  urls << url
end

# As the last statement in your method, return urls (without word 'return')
urls

Избавление от локальной переменной

urls = []
itunes_top_300.search('//entry').each do |podcast|
  # It's pretty clear what we're doing, so no need to name the value
  # before we add it to the array
  urls << podcast.at_xpath(".//[@href]")['href']
end
urls

Очистка с помощью Map

# Run through the array and convert each element to the return value
# of the block
itunes_top_300.search('//entry').map do |podcast|
  podcast.at_xpath(".//[@href]")['href']
end

# If the above is the last statement of the method, the method will return the
# result of the map as the return value of the method

Запрос только атрибута напрямую

itunes_top_300.search('//entry').map do |podcast|
  # Instead of getting the element, get the attribute itself
  # Use `to_s` or `value` to get the text of the attribute node.
  podcast.at_xpath(".//[@href]/@href").to_s
end

Использование только XPath, чтобы получить то, что мы хотели в первую очередь

# Take an array of attribute nodes and get their values
itunes_top_300.xpath('//entry/link/@href').map{ |attr| attr.to_s }

Использование синтаксиса Ruby 1.9 для сокращения вызова карты

# Map the result of the XPath by calling `to_s` on each
itunes_top_300.xpath('//entry/link/@href').map( &:to_s )
...