这可能是由于本文档中的命名空间:
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
要检验这个假设,请应用以下 XPath 表达式:
/*[local-name() = 'Envelope']/*[local-name() = 'Cube']/*[local-name() = 'Cube'][@time="2014-11-19"]/*[local-name() = 'Cube'][@currency="USD"]/@rate
告诉我你得到了什么。如果您以其他方式正确使用 XPath,您应该得到:
rate="1.2535"
如果没有,您没有正确使用 Nokogiri 的 XPath 工具,那么您真的需要展示所有 Ruby 代码以获得帮助。
编辑
回复评论:
我期待看到一些示例添加到您的答案中,以便我可以了解有关 xml 命名空间的新知识。 – 7 螺栓
7stud 已经给出了正确答案,我只会添加我认为此答案中缺少的信息。
显式命名空间
首先,如果命名空间 URI 显式存在于元素上,则正确的语法使用大括号,用于前缀命名空间和默认命名空间:
<{http://www.gesmes.org/xml/2002-08-01}subject>
在内部,这就是命名空间在元素上的表示方式(尽管有些应用程序有其他方式将元素与命名空间相关联)。前缀和默认命名空间是为了简化这个过程。
Nokogiri 中的命名空间
前缀 (gesmes:) 没有任何内在含义。它们可以与任意命名空间 URI 相关联,并且每个文档都可以使用 gesmes: 来表示不同的含义。命名空间声明不适用于 XPath 引擎本身 - 通常,如果您想在 XPath 表达式中使用前缀,您需要再次声明这个命名空间XPath 处理器。
然而,Nokogiri 试图通过重新声明在输入文档的根元素上找到的命名空间声明来为您简化命名空间处理。这很重要,因为它允许您重用在输入的根元素上声明的前缀,而无需实际声明命名空间。对于在根元素上声明的没有前缀的默认命名空间,Nokogiri 定义了一个特殊的语法:
xmlns:Cube
存在于文档中但在根元素以外的元素上声明的命名空间:
<root>
<child xmlns:gesmes="http://other.com"/>
</root>
必须在 Nokogiri 中明确声明:
@doc.xpath('//other:Cube', 'other' => 'http://other.com/')
您的原始代码有什么问题?
您的代码:
/gesmes:Envelope/def:Cube/def:Cube[@time="2014-11-19"]/def:Cube[@currency="USD"]/@rate
不起作用,因为您使用的是未知前缀 def:。这个前缀没有在输入的根元素上声明,你也没有用 Nokogiri 声明它。 Cube 元素位于默认命名空间中,正如我们所见,处理它们的正确方法是
/gesmes:Envelope/xmlns:Cube
等等,7stud给了你正确答案。