2009-12-01 62 views
11

我正在实现一个需要命名空间的XML数据格式的导出器。我正在使用Nokogiri XML Builder(版本1.4.0)来执行此操作。用Nokogiri构建器创建一个名称空间根元素的XML文档

但是,我不能让Nokogiri创建一个具有名称空间的根节点。

这工作:

Nokogiri::XML::Builder.new { |xml| xml.root('xmlns:foobar' => 'my-ns-url') }.to_xml 

<?xml version="1.0"?> 
<root xmlns:foobar="my-ns-url"/> 

至于做这个的:

Nokogiri::XML::Builder.new do |xml| 
    xml.root('xmlns:foobar' => 'my-ns-url') { xml['foobar'].child } 
end.to_xml 

<?xml version="1.0"?> 
<root xmlns:foobar="my-ns-url"> 
    <foobar:child/> 
</root> 

不过,我需要像<foo:root>这不起作用:

Nokogiri::XML::Builder.new { |xml| xml['foobar'].root('xmlns:foobar' => 'my-ns-url') }.to_xml 

NoMethodError: undefined method `namespace_definitions' for #<Nokogiri::XML::Document:0x11bfef8 name="document"> 

命名空间必须显然,在使用前定义,所以没有办法将一个添加到根节点。

我发现a question about this on the Nokogiri mailing list,但它没有回复。任何人都有解决方案?

回答

13
require 'rubygems' 
require 'nokogiri' 

puts Nokogiri::XML::Builder.new { |xml| 
    xml.root("xmlns:foo"=>"url") { 
    xml.parent.namespace = xml.parent.namespace_definitions.find{|ns|ns.prefix=="foo"} 
    xml['foo'].child 
    } 
}.to_xml 

不能使用xml['foo']定义的命名空间之前,你把它作为参数传递给根节点即之前。因此,上面的代码将命名空间事后添加到根节点。

+0

就像一个魅力。谢谢! – 2009-12-07 16:39:16

+0

你,先生,让我非常沮丧 – yalestar 2010-02-23 23:06:55

+0

不客气,耶鲁之星。 – akuhn 2010-02-25 00:00:35

6

两年后,我找到了一个更简洁的方法,使用Nokogiri::XML::Builder的文档引用来检索根节点并向其中添加命名空间。像以前的解决方案一样,它需要根节点在命名空间添加到它之前存在。

我已经改变了<root>元素<rootElement>所以更清楚:

builder = Nokogiri::XML::Builder.new do |xml| 
    xml.rootElement do 
    # create a namespace and save it for later 
    ns = xml.doc.root.add_namespace_definition('foo', 'my-ns-url') 
    # you can also create multiple name spaces 
    xml.doc.root.add_namespace_definition('bar', 'http://example.com/bar') 

    # assign the saved namespace to rootElement 
    xml.doc.root.namespace = ns 

    xml['foo'].child 
    xml['bar'].child 
    end 
end 

现在,builder.to_xml将返回:

<?xml version="1.0"?> 
<foo:rootElement xmlns:foo="my-ns-url" xmlns:bar="http://example.com/bar"> 
    <foo:child/> 
    <bar:child/> 
</foo:rootElement> 

我喜欢这个更好,因为你不必搜索名称空间,并且更容易添加多个名称空间。

+0

这很好。谢谢。但是,我无法摆脱名称空间继承。我想要实现类似以下的内容。 <?xml version =“1.0”?> value dknight 2012-08-16 14:54:52

0

卢克回答三年后,它变得更简单了。您现在可以在定义的“之前”使用名称空间。此代码:

require 'nokogiri' 

NAMESPACES = { 'xmlns:foo' => 'bar', 'xmlns:baz' => 'bat' } 

builder = Nokogiri::XML::Builder.new { |xml| 
    xml['foo'].RootElement(NAMESPACES) { 
    xml['baz'].FirstChild 
    } 
} 

puts builder.to_xml 

输出这个XML:

<?xml version="1.0"?> 
<foo:RootElement xmlns:foo="bar" xmlns:baz="bat"> 
    <baz:FirstChild/> 
</foo:RootElement>