使用 Crystal 从 XML::Nodeset 中的第一个节点检索值
Retrieve a value from the first node in an XML::Nodeset using Crystal
我正在使用 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
returnsXML::NodeSet
其中有an instance method []
。所以我相信我应该能够这样做以获得价值:
node = nodeset[0]
node.value
但是,当我调用 nodeset[0]
时出现以下错误:
undefined method '[]' for Float64 (compile-time type is (String | Float64 | Bool | XML::NodeSet))
node = nodeset[0]
我不明白为什么 []
方法将节点集视为 Float64 而 inspect
和 class
都将其视为 XML::Nodeset
。
我错过了什么?
String有[]
方法,而Float64没有,是巧合吗?
当您执行 evaluate
时,return 类型是所有可能值的联合类型。在这种情况下 XML::NodeSet
是运行时类型(注意与编译时类型的区别)。
如果你能保证 return 类型总是一个节点集,那么你可以简单地做:
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
为了完整起见,这是我在@asterite 和@waj 的帮助下最终得到的代码
file = File.read("path/to/doc.xml")
xml = XML.parse(file)
node = xml.xpath_node("//foo/@ID")
node.text
注意 node.value 也错了!
我正在使用 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
returnsXML::NodeSet
其中有an instance method []
。所以我相信我应该能够这样做以获得价值:
node = nodeset[0]
node.value
但是,当我调用 nodeset[0]
时出现以下错误:
undefined method '[]' for Float64 (compile-time type is (String | Float64 | Bool | XML::NodeSet))
node = nodeset[0]
我不明白为什么 []
方法将节点集视为 Float64 而 inspect
和 class
都将其视为 XML::Nodeset
。
我错过了什么?
String有[]
方法,而Float64没有,是巧合吗?
当您执行 evaluate
时,return 类型是所有可能值的联合类型。在这种情况下 XML::NodeSet
是运行时类型(注意与编译时类型的区别)。
如果你能保证 return 类型总是一个节点集,那么你可以简单地做:
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
为了完整起见,这是我在@asterite 和@waj 的帮助下最终得到的代码
file = File.read("path/to/doc.xml")
xml = XML.parse(file)
node = xml.xpath_node("//foo/@ID")
node.text
注意 node.value 也错了!