2009-12-01 59 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>