使用libxml-ruby解析名称空间的XML

使用libxml-ruby解析名称空间的XML,xml,ruby,xpath,libxml-ruby,Xml,Ruby,Xpath,Libxml Ruby,我正在尝试使用libxml ruby以以下格式解析XML(来自欧洲央行数据源): <?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"> <gesme

我正在尝试使用libxml ruby以以下格式解析XML(来自欧洲央行数据源):

<?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>
但我正在努力找到正确的名称空间配置,以允许对数据进行XPATH查询

我可以使用以下代码提取所有
Cube
节点:

doc.find("//*[local-name()='Cube']")
但是,鉴于父节点和子节点都被称为
Cube
,这实际上并不能帮助我仅迭代父节点。也许我可以修改这个XPATH,只找到带有
time
参数的节点

我的目标是能够提取所有具有
时间
属性(即
)的
多维数据集
节点,这样我就可以提取日期并迭代子
多维数据集
节点中的汇率


有人能帮忙吗?

这两种方法都可以:

/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')
定义后,查找具有时间属性的多维数据集节点非常简单:

context.find("//euro:Cube[@time]").each {|node| .... }

这两种方法实际上都不起作用,它们不返回任何节点。最初我自己试了第一个,但没有用。有趣的是,如果我删除所有名称空间并使用根标记“test”,那么“/test/Cube/Cube”确实可以按预期工作。有什么想法吗?有关工作代码,请参见上面的编辑。经过了相当多的尝试和错误的getAha!谢谢你。实际上,我已经想出了一个解决方案,我刚刚发布了这个解决方案,但您的解决方案为我节省了一个代码链接:)
context.find("//euro:Cube[@time]").each {|node| .... }