# How to set namespace in XML::Node xpath\_node?

**URL:** <https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089>\
**Category:** Help & Support\
**Created:** [May 11, 2020, 1:12pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089 "2020-05-11T13:12:18Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 1:12pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/1 "2020-05-11T13:12:18Z")

</div>

Hi

> puts x.first\_element\_child.not\_nil!.namespace

returns

> #\<XML::Namespace:0x7f50d27ad000 prefix=“soap” href=“[http://www.w3.org/2003/05/soap-envelope](http://www.w3.org/2003/05/soap-envelope)”\>

but

> puts x.xpath\_node(“/Envelope/Body”).not\_nil!.name

returns

> Unhandled exception: Nil assertion failed (NilAssertionError)

and

> 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

and

> x.xpath\_node(“/Envelope/Body”,{“prefix”=\>“soap”})  
> x.xpath\_node(“/Envelope/Body”,{“soap”=\>“[http://www.w3.org/2003/05/soap-envelope](http://www.w3.org/2003/05/soap-envelope)”})

are also nill.

and

> x.xpath\_node(“/Envelope/Body”,x.first\_element\_child.not\_nil!.namespace).not\_nil!.name

return compile time error

> In /usr/share/crystal/src/xml/xpath\_context.cr:39:16
> 
> 39 | namespaces.each do |prefix, uri|  
> ^—  
> Error: undefined method ‘each’ for XML::Namespace

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 11, 2020, 3:28pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/2 "2020-05-11T15:28:22Z")

</div>

Do you have the code to reproduce this? Like a full example. Can use [https://play.crystal-lang.org/#/cr](https://play.crystal-lang.org/#/cr).

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 6:10pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/3 "2020-05-11T18:10:22Z")

</div>

@Blacksmoke16  
I rewrote the code here :  
[https://play.crystal-lang.org/#/r/91qo](https://play.crystal-lang.org/#/r/91qo)

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 11, 2020, 6:29pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/4 "2020-05-11T18:29:24Z")

</div>

👍 thanks. Yea this seems to be a bug. [https://github.com/crystal-lang/crystal/blob/9b12792c4d532feb2a8875983e72ad19d0a249b9/src/xml/node.cr#L486](https://github.com/crystal-lang/crystal/blob/9b12792c4d532feb2a8875983e72ad19d0a249b9/src/xml/node.cr#L486) calls into a method that wants to iterate over the namespaces [https://github.com/crystal-lang/crystal/blob/master/src/xml/xpath\_context.cr#L39](https://github.com/crystal-lang/crystal/blob/master/src/xml/xpath_context.cr#L39).

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.

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 6:42pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/5 "2020-05-11T18:42:03Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 11, 2020, 6:53pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/6 "2020-05-11T18:53:46Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 11, 2020, 6:55pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/7 "2020-05-11T18:55:56Z")

</div>

This works:

```crystal
require "xml"
str_xml = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <NumberToWordsResponse xmlns="http://www.dataaccess.com/webservicesserver/">
      <NumberToWordsResult>string</NumberToWordsResult>
    </NumberToWordsResponse>
  </soap:Body>
</soap:Envelope>
XML
x = XML.parse str_xml
puts x.first_element_child.not_nil!.namespace
p x.xpath_node("/soap:Envelope/soap:Body", {"soap" => "http://www.w3.org/2003/05/soap-envelope"})

```

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

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [May 11, 2020, 7:09pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/8 "2020-05-11T19:09:21Z")

</div>

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`.

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 7:15pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/9 "2020-05-11T19:15:10Z")

</div>

@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 🙂 )
2. second parameter in x.path\_node function does not accept XML::Namespace is it ok?

And thank you for this beautiful programming language.

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 7:19pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/10 "2020-05-11T19:19:17Z")

</div>

🙂 my bad

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 11, 2020, 7:20pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/11 "2020-05-11T19:20:41Z")

</div>

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

> <https://stackoverflow.com/questions/4690737/nokogiri-xpath-namespace-query/4691008#4691008>

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:

> <https://github.com/crystal-lang/crystal/blob/35c1f41f05144d9645c7bba83cd1b1deaea68fb0/spec/std/xml/xpath_spec.cr#L78>

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

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 11, 2020, 7:28pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/12 "2020-05-11T19:28:49Z")

</div>

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:

```crystal
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?

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 11, 2020, 7:33pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/13 "2020-05-11T19:33:31Z")

</div>

Thanks, I’ll report a bug.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 14, 2020, 12:06pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/14 "2020-05-14T12:06:56Z")

</div>

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

```crystal
x.xpath_node("/soap:Envelope/soap:Body")

```

and it will work out of the box.

---

<div class="post-metadata">

**Author:** ![Geo-7](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/geo-7/32/816_2.png) [@Geo-7](https://forum.crystal-lang.org/u/Geo-7)\
**Post date:** [May 14, 2020, 1:33pm UTC](https://forum.crystal-lang.org/t/how-to-set-namespace-in-xml-node-xpath-node/2089/15 "2020-05-14T13:33:13Z")

</div>

Thank U, It makes life easier 🙂
