我正在使用Crystal,并且正在尝试检索XML文档中节点的ID:
<foo ID="bar"></foo>
我使用以下代码来获取ID
require "xml"
file = File.read("path/to/doc.xml")
xml = XML.parse(file)
xpath_context = XML::XPathContext.new(xml)
nodeset = xpath_context.evaluate("//foo/@ID")
如果我检查节点集,我会得到我期待的内容:
[#<XML::Attribute:0x1287690 name="ID" value="bar">]
nodeset.class
返回XML::NodeSet
node = nodeset[0]
node.value
。所以我相信我应该能够做到这一点来获得价值:
nodeset[0]
然而,当我致电undefined method '[]' for Float64 (compile-time type is (String | Float64 | Bool | XML::NodeSet))
node = nodeset[0]
时,我收到以下错误:
[]
我不明白为什么inspect
方法在class
和XML::Nodeset
将[]
视为{{1}}时将节点集视为Float64。
我错过了什么?
String是否有{{1}}方法,但Float64没有?
答案 0 :(得分:4)
执行evaluate
时,返回类型是所有可能值的并集类型。在这种情况下,XML::NodeSet
是运行时类型(注意编译时类型的差异)。
如果您可以确保返回类型始终是节点集,那么您只需执行以下操作:
nodeset = xpath_context.evaluate("//foo/@ID") as XML::NodeSet
但如果结果有不同的类型,那将引发异常。 另一个选择是有条件地做:
if nodeset.is_a?(XML::NodeSet)
# use nodeset here without casting, the compiler will restrict the type
end
甚至使用case
声明:
case nodeset
when XML::NodeSet
# ...
end
答案 1 :(得分:0)
为了完整起见,这是我最终得到的代码,在@asterite和@waj的帮助下
file = File.read("path/to/doc.xml")
xml = XML.parse(file)
node = xml.xpath_node("//foo/@ID")
node.text
请注意,node.value也是错误的!