I am using Crystal, and am trying to retrieve the ID of a node in an XML document:
<foo ID="bar"></foo>
I am using the following code to get to the 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")
If I inspect the nodeset, I get the content I am expecting:
[#<XML::Attribute:0x1287690 name="ID" value="bar">]
And nodeset.class returns XML::NodeSet which has an instance method []. So I believe I should be able to do this to get the value:
node = nodeset[0]
node.value
However, when I call nodeset[0] I get the following error:
undefined method '[]' for Float64 (compile-time type is (String | Float64 | Bool | XML::NodeSet))
node = nodeset[0]
I do not understand why the [] method is seeing nodeset as a Float64 when both inspect and class are seeing it as an XML::Nodeset.
What am I missing?
Is it a coincidence that String has a [] method, but Float64 does not?
When you execute evaluate the return type is a union type of all the possible values. In this case XML::NodeSet is the runtime type (notice the difference with the compile time type).
If you can assure that the return type is always a node set, then you can simply do:
nodeset = xpath_context.evaluate("//foo/@ID") as XML::NodeSet
But that will raise an exception if the result has a different type. Another option is do it conditionally:
if nodeset.is_a?(XML::NodeSet)
# use nodeset here without casting, the compiler will restrict the type
end
Or even with a case statement:
case nodeset
when XML::NodeSet
# ...
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With