I have an XML document with a default namespace and another prefix defined on the root:
<r xmlns="a://foo" xmlns:b="a://bar" x="y"><!-- content not using b:* --></r>
Using Nokogiri I have already gone through the document and removed elements and attributes using the b
namespace. Now I want to modify the document so that when output it does not have the b
namespace, i.e.
<r xmlns="a://foo" x="y"><!-- content not using b:* --></r>
What does not work
If I use remove_namespaces!
I lose even the default namespace, which I do not want:
<r x="y"><!-- content not using b:* --></r>
I can select the namespace using XPath, but Nokogiri::XML::Namespace
does not inherit from Node
and has no remove
method:
doc.at('//namespace::*[name()="b"]')
#=> #<Nokogiri::XML::Namespace:0x8104118c prefix="b" href="a://bar">
doc.at('//namespace::*[name()="b"]').remove
#=> NoMethodError: undefined method `remove' for #<Nokogiri::XML::Namespace:0x81025acc prefix="b" href="a://bar">
doc.xpath('//namespace::*[name()="b"]').remove; puts doc
#=> <r xmlns="a://foo" xmlns:b="a://bar" x="y"><!-- content not using b:* --></r>
The root element does not include the namespace declaration as an attribute that could be removed:
doc.root.attributes
#=> {"x"=>#<Nokogiri::XML::Attr:0x8103dba4 name="x" value="y">}
What sort of works
As the document is small, I will accept any solution that creates a new copy of the document without the namespace instead of mutating the existing one.
The best solution I've got so far is
doc.remove_namespaces!
doc.root.add_namespace(nil,'foo')
…but this nuclear option will also remove any namespaces on descendants of the root, which is undesirable.