Разбор пространства имен XML с использованием libxml-ruby

Я пытаюсь проанализировать XML в следующем формате (из фида данных Европейского центрального банка), используя libxml-ruby:

<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" 
                 xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
  <gesmes:subject>Reference rates</gesmes:subject>
  <gesmes:Sender>
    <gesmes:name>European Central Bank</gesmes:name>
  </gesmes:Sender>
  <Cube>
    <Cube time="2009-11-03">
      <Cube currency="USD" rate="1.4658"/>
      <Cube currency="JPY" rate="132.25"/>
      <Cube currency="BGN" rate="1.9558"/>
    </Cube>
  </Cube>
</gesmes:Envelope>

Я загружаю документ следующим образом:

require 'rubygems'
require 'xml/libxml'
doc = XML::Document.file('eurofxref-hist.xml')

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

Я могу извлечь все Cube узлы, использующие следующий код:

doc.find("//*[local-name()='Cube']")

Но учитывая, что родительский узел и дочерние узлы называются Cube это действительно не помогает мне перебирать только родительские узлы. Возможно, я мог бы изменить этот XPATH, чтобы найти только те узлы с time параметр?

Моя цель состоит в том, чтобы иметь возможность извлечь все Cube узлы, которые имеют time атрибут (т.е. <Cube time="2009-11-03">) так что я могу затем извлечь дату и перебрать курсы обмена у ребенка Cube узлы.

Кто-нибудь может помочь?

2 ответа

Решение

Любой из них будет работать:

/gesmes:Envelope/Cube/Cube - direct path from root
//Cube[@time] - all cube nodes (at any level) with a time attribute

Хорошо, это проверено и работает

arrNS = ["xmlns:http://www.ecb.int/vocabulary/2002-08-01/eurofxref", "gesmes:http://www.gesmes.org/xml/2002-08-01"]
doc.find("//xmlns:Cube[@time]", arrNS)

Так что я понял это. Корневой узел определяет два пространства имен, одно с префиксом, другое без:

xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01
xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref"

Когда префикс определен, вы можете довольно легко ссылаться на имена пространства имен префикса. Используя XML из исходного вопроса, этот XPATH:

/gesmes:Envelope/gesmes:subject

Вернет "Справочные тарифы".

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

doc = XML::Document.file('eurofxref-hist-test.xml')
context = XML::XPath::Context.new(doc)
context.register_namespace('euro', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref')

Как только это определено, поиск узлов Cube с атрибутами времени тривиален:

context.find("//euro:Cube[@time]").each {|node| .... }
Другие вопросы по тегам