Анализ простого XML с помощью Nokogiri
У меня есть следующий XML:
<links>
<item>
<title>Title 1</title>
<url>http://www.example.com/url-1</url>
</item>
<item>
<title>Title 2</title>
<url>http://www.example.com/url-2</url>
</item>
<item>
<title>Title 3</title>
<url>http://www.example.com/url-3</url>
</item>
</links>
И я хотел бы преобразовать его в список HTML:
<ul>
<li><a href="#" onclick="location.href='http://www.example.com/url-1'; return false;">Title 1</a></li>
<li><a href="#" onclick="location.href='http://www.example.com/url-2'; return false;">Title 2</a></li>
<li><a href="#" onclick="location.href='http://www.example.com/url-3'; return false;">Title 3</a></li>
</ul>
В настоящее время у меня есть это:
Контроллер:
require 'nokogiri'
doc = Nokogiri::XML(...)
@links = doc.xpath('//links/item').map do |i|
{'title' => i.xpath('//title'), 'url' => i.xpath('//url')}
end
Шаблон:
<ul>
<% @links.each do |l| %>
<li><a href="<%= l['url'] %>"><%= l['title'] %></a></li>
<% end %>
</ul>
Результат HTML:
<ul>
<li><a href="#" onclick="location.href='http://www.example.com/url-1http://www.example.com/url-2http://www.example.com/url-3'; return false;">Title 1Title 2Title 3</a></li>
<li><a href="#" onclick="location.href='http://www.example.com/url-1http://www.example.com/url-2http://www.example.com/url-3'; return false;">Title 1Title 2Title 3</a></li>
<li><a href="#" onclick="location.href='http://www.example.com/url-1http://www.example.com/url-2http://www.example.com/url-3'; return false;">Title 1Title 2Title 3</a></li>
</ul>
Что я делаю неправильно? Есть ли более оптимальный способ сделать это?
Ответы
Ответ 1
Заменить это:
@links = doc.xpath('//links/item').map do |i|
{'title' => i.xpath('//title'), 'url' => i.xpath('//url')}
с
@links = doc.xpath('//links/item').map do |i|
{'title' => i.xpath('title'), 'url' => i.xpath('url')}
Объяснение
//title
и
//url
являются абсолютными выражениями XPath, и они выбирают все (соответственно) title
и все элементы url
в документе XML.
Контрастируйте это с помощью:
title
и
url
Это относительные выражения XPath и выберите все (соответственно) title
и url
только для детей текущего node.
Ответ 2
Проблема заключается в том, что Xpath //title
выполняет поиск заголовков из корня документа и возвращает все теги title
. Использование поиска Xpath title
в контексте данного node, как вы хотите. Тоже на url
.
@links = doc.xpath('//links/item').map do |i|
{'title' => i.xpath('title'), 'url' => i.xpath('url')}
end