从文档中删除特定命名空间

时间:2014-06-28 14:03:39

标签: ruby xml nokogiri

我有一个带有默认命名空间的XML文档和在根目录上定义的另一个前缀:

<r xmlns="a://foo" xmlns:b="a://bar" x="y"><!-- content not using b:* --></r>

使用Nokogiri我已经浏览了文档,并使用b命名空间删除了元素和属性。现在我想修改文档,以便在输出时它没有b命名空间,即

<r xmlns="a://foo" x="y"><!-- content not using b:* --></r>

什么不起作用

如果我使用remove_namespaces!,我甚至会丢失我不想要的默认命名空间:

<r x="y"><!-- content not using b:* --></r>

我可以使用XPath选择命名空间,但Nokogiri::XML::Namespace不会从Node继承并且没有remove方法:

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>

根元素不包含名称空间声明作为可以删除的属性:

doc.root.attributes
#=> {"x"=>#<Nokogiri::XML::Attr:0x8103dba4 name="x" value="y">} 

什么样的作品

由于文档很小,我会接受任何创建文档新副本但没有命名空间而不是改变现有文档的解决方案。

我到目前为止所获得的最佳解决方案是

doc.remove_namespaces!
doc.root.add_namespace(nil,'foo')

...但是这个核选项也将删除根的后代上的任何名称空间,这是不可取的。

2 个答案:

答案 0 :(得分:0)

在Nokogiri你可以canonicalize the document,只跳过命名空间声明,如下所示:

result = doc.canonicalize(nil,nil,1) do |o,_|
  !o.is_a?(Nokogiri::XML::Namespace) || o.href!="a://bar"
end

这将返回一个字符串(不是新文档)。如果您想要新文档,可以doc2 = Nokogiri.XML(result)

请注意,虽然Nokogiri::XML::Node也有canonicalize方法,但它不接受该块来决定是否保留项目。您必须在文档本身上调用它。

第三个参数需要在规范化中包含注释。我do not know前两个选项的作用,但运行时将segfault if you pass a 1 for the second parameter

但是,这个答案也会从文档中删除空格。我不会接受这个。

答案 1 :(得分:-1)

您可以选择根元素并删除它的属性,如下所示:

doc.css('r')[0].attributes['xmlns:b'].remove

Quoting你自己的答案之一:)

将文档用作HTML,

irb(main):001:0> require 'nokogiri'
=> true
irb(main):002:0> doc = '<r xmlns="foo" xmlns:b="bar" x="y"><!-- content not using b:* --></r>'
=> "<r xmlns=\"foo\" xmlns:b=\"bar\" x=\"y\"><!-- content not using b:* --></r>"
irb(main):004:0> xml = Nokogiri::HTML(doc)
=> #<Nokogiri::HTML::Document:0x3fe4544e6268 name="document" children=[#<Nokogiri::XML::DTD:0x3fe4544e3158 name="html">, #<Nokogiri::XML::Element:0x3fe4544e2834 name="html" children=[#<Nokogiri::XML::Element:0x3fe4544e2410 name="body" children=[#<Nokogiri::XML::Element:0x3fe4544e2050 name="r" attributes=[#<Nokogiri::XML::Attr:0x3fe4544df01c name="xmlns" value="foo">, #<Nokogiri::XML::Attr:0x3fe4544dfcec name="xmlns:b" value="bar">, #<Nokogiri::XML::Attr:0x3fe4544dfd00 name="x" value="y">] children=[#<Nokogiri::XML::Comment:0x3fe4544df418 " content not using b:* ">]>]>]>]>
irb(main):005:0> xml.to_s
=> "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body><r xmlns=\"foo\" xmlns:b=\"bar\" x=\"y\"><!-- content not using b:* --></r></body></html>\n"
irb(main):006:0> xml.css('r')[0].attributes['xmlns:b'].remove
=> #<Nokogiri::XML::Attr:0x3fe4544dfcec name="xmlns:b" value="bar">
irb(main):007:0> xml.to_s
=> "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body><r xmlns=\"foo\" x=\"y\"><!-- content not using b:* --></r></body></html>\n"
irb(main):008:0>