Не удается получить данные в пространстве имен Google из документа XML с помощью Nokogiri

У меня есть этот канал покупок Google:

<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
  <item>
    <title>test</title>
    <g:id>1</g:id>
    <g:color>blue</g:color>
  </item>
  <item>
    <title>test2</title>
    <g:id>2</g:id>
    <g:color>red</g:color>
  </item>
</channel></rss>

Я искал несколько дней, и я не могу найти ответ. Я также работал с документацией Нокогири, но это также ничего не прояснило.

Что я пытаюсь сделать:

doc = Nokogiri::XML(*Google Shopping Feed*)
doc.css('channel > item').each do |item|
  puts item.css('g:id')
end

Но это ничего не возвращает. Я перепробовал много предложений, но ни одно из них не сработало. Я явно что-то упускаю здесь, но не могу понять, что.

Еще одна вещь, которую я не могу понять, это получение списка всех атрибутов в элементе. Поэтому мой вопрос заключается в том, как я могу получить следующий массив из фида Google Shopping:

# attributes => ['title', 'g:id', 'g:color']

2 ответа

Решение

Попробуйте использовать at_xpath вместе с text:

doc.css('channel > item').each do |item|
  puts item.at_xpath('g:id').text
end
#=> 1
#=> 2

Еще одна вещь, которую я не могу понять, это получение списка всех атрибутов в элементе.

Вы можете получить массив каждого item как это:

doc.css('channel > item').map do |item|
  item.element_children.map do |key|
    prefix = "#{key.namespace.prefix}:" if key.namespace
    name   = key.name

    "#{prefix}#{name}"
  end
end
#=> [["title", "g:id", "g:color"], ["title", "g:id", "g:color"]]

Если все элементы будут иметь одинаковые атрибуты, то вы можете просто использовать первый элемент (вместо того, чтобы повторять их все):

doc.css('channel > item').first.element_children.map do |key|
  prefix = "#{key.namespace.prefix}:" if key.namespace
  name   = key.name

  "#{prefix}#{name}"
end
#=> ["title", "g:id", "g:color"]

Если вы хотите сохранить информацию о пространстве имен, самым простым решением, вероятно, будет использование выражения Xpath.

Нечто подобное

doc.xpath('//item').each_with_index do |node, i|
  puts "Element #{i} attributes:"
  node.xpath("*/text()").each do |element| 
    puts "#{element.name}: #{element.text}"
  end
end
Другие вопросы по тегам