Как заставить Nokogiri разрешать ссылки XPath при синтаксическом анализе XML?

О Nokogiri написано много с точки зрения чтения XML с помощью XPath. Однако как насчет использования Nokogiri с XML, содержащим ссылки XPath.

В этом примере xml содержит ссылку на XPath:

<elements>
 <element>
  <location>
   <longitude>...
   <latitude>...
  </location>
 </element>
 <element>
  <location reference="../../element/location"/>
 </element>
</elements>

Поскольку оба элемента местоположения равны, подробно описывается только первый элемент. Второй просто ссылается на первый.

Используя Nokogiri, xml.xpath ('// location'), как и ожидалось, возвращает два экземпляра узла. Первый узел содержит все дочерние узлы. Вторая только ссылка как атрибут экземпляра второго узла.

Хорошо, если я хочу запросить все значения долготы, я бы сделал xml.xpath ('// location / longitude'). Это возвращает только один экземпляр узла. Однако, поскольку на самом деле существует два элемента типа «долгота», я ожидал получить два экземпляра узла, ожидая, что Nokogiri разрешит ссылки XPath ...

Как добиться этого с помощью Nokogiri?


person Scholle    schedule 29.01.2011    source источник
comment
В вашем примере я вижу только один элемент долготы. Не могли бы вы подробнее рассказать о вводе и о том, что вы хотите извлечь?   -  person Mark Thomas    schedule 29.01.2011
comment
Вы задавали этот вопрос на нескольких сайтах, включая Nokogiri Talk. Разработчики отслеживают этот список, но редко заходят сюда, поэтому, пожалуйста, обновите свой вопрос любыми ответами, которые они предоставят.   -  person the Tin Man    schedule 30.01.2011


Ответы (2)


Вы можете собрать узлы местоположения, которые имеют фактические значения (не ссылочные узлы), а затем собрать все ссылки отдельно, как показано в следующем фрагменте:

require 'nokogiri'

xml = <<End
<elements>
 <element>
  <location>
   <longitude>45</longitude>
   <latitude>-70</latitude>
  </location>
 </element>
 <element>
  <location reference="../../element/location"/>
 </element>
</element>
End

doc = Nokogiri::XML(xml)

#Collect all the explicit longitudes
longitudes = doc.search('//location[not(@reference)]/longitude').map(&:text)

#Follow references to longitudes
doc.search('//location[@reference]').each do |location|
  reference = location.attribute('reference')
  longitudes << location.xpath("#{reference}/longitude").text
end

puts longitudes #=> ["45", "45"]

Вы можете использовать эту технику для извлечения любой информации, которую захотите.

person Mark Thomas    schedule 29.01.2011
comment
Я обновил пример кода. Ссылка - это не идентификатор, а скорее выражение XPath. - person Scholle; 29.01.2011

Вы не указали, как второй элемент location ссылается на первый.

Даже если бы этот механизм был известен и мы могли бы указать его в выражении XPath для выбора указанного элемента location, два выбранных longitude узла были бы идентичны.

Когда выражение XPath оценивается, оно всегда возвращает набор узлов - то есть, если один и тот же узел выбирается более одного раза, он представлен только один раз в результате выбора. - в наборе нет повторяющихся предметов.

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

Вот пример;

<a>
 <b>
   <c/>
 </b>
</a>

Выражение XPath:

/a/* | //c/..

выбирает только один элемент b, а не два одинаковых элемента b.

person Dimitre Novatchev    schedule 29.01.2011