использование nokogiri для анализа google picasa api xml - проблема с пространством имен? - PullRequest
1 голос
/ 30 марта 2011

Я пытаюсь получить некоторые данные из некоторого google picasa xml, и у меня возникли некоторые проблемы.

Вот фактический xml (содержащий только одну запись): http://pastie.org/1736008

По сути, я хотел бы собрать несколько атрибутов gphoto, поэтому в идеале я хотел бы сделать следующее:

doc.xpath('//entry').map do |entry|
  {:id => entry.children['gphoto:id'],
   :thumb => entry.children['gphoto:thumbnail'],
   :name => entry.children['gphoto:name'],
   :count => entry.children['gphoto:numphotos']}
end

Однако это не работает ... На самом деле, когда я проверяюдети вступления, я даже не вижу никаких атрибутов 'gphoto: xxx' вообще ... Так что я совершенно не понимаю, как их найти.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 30 марта 2011

Вот некоторый рабочий код, который использует nokogiri для извлечения элементов gphoto из вашего примера xml.

#!/usr/bin/env ruby
require 'rubygems'
require 'nokogiri'
content = File.read('input.xml')
doc = Nokogiri::XML(content) {|config| 
          config.options = Nokogiri::XML::ParseOptions::STRICT
      }

hashes = doc.xpath('//xmlns:entry').map do |entry|
  {
    :id => entry.xpath('gphoto:id').inner_text,
    :thumb => entry.parent.xpath('gphoto:thumbnail').inner_text,
    :name => entry.xpath('gphoto:name').inner_text,
    :count => entry.xpath('gphoto:numphotos').inner_text
  }
end

puts hashes.inspect

# yields: 
#
# [{:count=>"37", :name=>"Melody19Months", :thumb=>"http://lh3.ggpht.com/_Viv8WkAChHU/AAAAAAAAAAA/AAAAAAAAAAA/pNuu5PgnP1Y/s64-c/soopingsaw.jpg", :id=>"5582695833628950881"}]

Примечания:

  1. Образцу xml в вашей сущности необходимо закрыть "кормить "тег.Исправлено здесь .
  2. В выражении xpath для поиска элементов записи мы должны использовать префикс пространства имен, поэтому «xmlns: entry», а не просто «entry».Последний (используется в вашем исходном коде) найдет нет элементов.Он ищет элементы в пустом пространстве имен, но в вашем примере все они наследуют пространство имен по умолчанию, указанное в элементе канала.Аарон Паттерсон написал (Nokogiri-centric) введение в проблему, здесь , и есть еще здесь .
  3. Элемент gphoto: thumbnail является потомком feed element, а not каждой записи.Я сделал небольшую (хакерскую) корректировку для этого, сохранив в дизайне вашего исходного примера, но было бы намного лучше искать значение этого элемента только один раз за канал (возможно, позже заполнитьвходные хэши, если им действительно нужно хранить копии).
  4. Настройка строгости Nokogiri на самом деле не нужна, но приятно получить небольшую помощь в раннем обнаружении проблем.
0 голосов
/ 31 марта 2011

Вы можете искать узлы entry, а затем заглядывать внутрь каждого из них, чтобы извлечь узлы с пространством имен gphoto:

require 'nokogiri'

doc = Nokogiri::XML(open('./test.xml'))
hashes = doc.search('//xmlns:entry').map do |entry|
  h = {}
  entry.search("*[namespace-uri()='http://schemas.google.com/photos/2007']").each do |gphoto|
    h[gphoto.name] = gphoto.text
  end
  h
end

require 'ap'
ap hashes
# >> [
# >>     [0] {
# >>                        "id" => "5582695833628950881",
# >>                      "name" => "Melody19Months",
# >>                  "location" => "",
# >>                    "access" => "public",
# >>                 "timestamp" => "1299649559000",
# >>                 "numphotos" => "37",
# >>                      "user" => "soopingsaw",
# >>                  "nickname" => "sooping",
# >>         "commentingEnabled" => "true",
# >>              "commentCount" => "0"
# >>     }
# >> ]

Возвращает все //entry/gphoto:* заметки. Если вы хотите только определенные, вы можете отфильтровать то, что вы хотите:

require 'nokogiri'

doc = Nokogiri::XML(open('./test.xml'))
hashes = doc.search('//xmlns:entry').map do |entry|
  h = {}
  entry.search("*[namespace-uri()='http://schemas.google.com/photos/2007']").each do |gphoto|
    h[gphoto.name] = gphoto.text if (%w[id thumbnail name numphotos].include?(gphoto.name))
  end
  h
end

require 'ap'
ap hashes

# >> [
# >>     [0] {
# >>                "id" => "5582695833628950881",
# >>              "name" => "Melody19Months",
# >>         "numphotos" => "37"
# >>     }
# >> ]

Обратите внимание, что в исходном вопросе происходит попытка доступа к gphoto:thumbnail, однако для //element/gphoto:thumbnails нет соответствующего узла, поэтому он не может быть найден.

Другой способ написать поиск с использованием пространства имен:

require 'nokogiri'

doc = Nokogiri::XML(open('./test.xml'))
hashes = doc.search('//xmlns:entry').map do |entry|
  h = {}
  entry.search("*").each do |gphoto|
    h[gphoto.name] = gphoto.text if (
      (gphoto.namespace.prefix=='gphoto') && 
      (%w[id thumbnail name numphotos].include?(gphoto.name))
    )
  end
  h
end

require 'ap'
ap hashes

# >> [
# >>     [0] {
# >>                "id" => "5582695833628950881",
# >>              "name" => "Melody19Months",
# >>         "numphotos" => "37"
# >>     }
# >> ]

Вместо того, чтобы использовать XPath, он просит Нокогири посмотреть атрибуты пространства имен каждого узла.

...