How to set namespace in XML::Node xpath_node?


puts x.first_element_child.not_nil!.namespace


#<XML::Namespace:0x7f50d27ad000 prefix=“soap” href=“”>


puts x.xpath_node("/Envelope/Body").not_nil!.name


Unhandled exception: Nil assertion failed (NilAssertionError)


puts x.xpath_node("/Envelope/Body",“soap”).not_nil!.name

return compile time error

namespaces.each do |prefix, uri|
Error: undefined method ‘each’ for String



are also nill.



return compile time error

In /usr/share/crystal/src/xml/

39 | namespaces.each do |prefix, uri|
Error: undefined method ‘each’ for XML::Namespace

Do you have the code to reproduce this? Like a full example. Can use

I rewrote the code here :

:+1: thanks. Yea this seems to be a bug. calls into a method that wants to iterate over the namespaces

However there isn’t a .each defined on XML::Namespace. I’d make an issue with that playground link. Guess we didn’t have any specs on this code and this is the first time that someone tried using xpath with namespaces since Ary implemented it 5 years ago ha.

Thanks, Can you share a link of that issue here?

Sorry, I was suggesting you make an issue about it. I don’t think there is one already.

This works:

require "xml"
str_xml = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="">
    <NumberToWordsResponse xmlns="">
x = XML.parse str_xml
puts x.first_element_child.not_nil!.namespace
p x.xpath_node("/soap:Envelope/soap:Body", {"soap" => ""})

I think that’s the way to use it? Maybe we need more API examples in the docs.

Given #namespace has the name/url within it, probably could also add #each to it. So the user wouldn’t have to construct a hash like {namespace.prefix => namespace.href}.

EDIT: Or at least some overloads to accept either a XML::Namespace, or Hash | NamedTuple.

@asterite Thank you that is working, but I have two other questions for you.

  1. If it is the way that we should use it what is the point of defining namespace?
    (I don not know how it is defined in other programing languages but I think namespace is for avoiding name conflicts and this is the first time that I make and parse WSDL without library :slight_smile: )
  2. second parameter in x.path_node function does not accept XML::Namespace is it ok?

And thank you for this beautiful programming language.

:slight_smile: my bad

@Geo-7 I don’t know much about XML and namespaces, I just copied the behavior from Nokogiri:

Another alternative is to remove all namespaces as suggested by that answer, but I don’t think there’s such thing in Crystal.

I think that if a doc has namespaces, you’ll have to use them. Otherwise there’s no way to tell where “foo” belongs.

Also, if docs are missing, it’s always a good idea to check the specs:

If Nokogiri accepts an XML::Namespace as an argument, we probably should too.

I just checked, nokogiri just accepts a hash.

There’s an XML::Node#namespaces method, you can just call that and pass it to the xpath_node as a second argument. Something like:

x = XML.parse str_xml
p x.xpath_node("/soap:Envelope/soap:Body", x.root.not_nil!.namespaces)

Unfortunately that doesn’t work but probably should. Care to report a bug?

Thanks, I’ll report a bug.

In the next version you’ll be able to do:


and it will work out of the box.

Thank U, It makes life easier :slight_smile: