使用Crystal从XML :: Nodeset中的第一个节点检索值

时间:2015-09-18 12:15:26

标签: xml xpath crystal-lang

我正在使用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方法在classXML::Nodeset[]视为{{1}}时将节点集视为Float64。

我错过了什么?

String是否有{{1}}方法,但Float64没有?

2 个答案:

答案 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也是错误的!