2009-12-01 17 views
11

名前空間を必要とするXMLデータ形式のエクスポータを実装しています。私はこれを行うためにNokogiri XML Builder(バージョン1.4.0)を使用しています。Nokogiri Builderで名前空間のルート要素を持つ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

作品。ありがとう! –

+0

あなた、私は多くの欲求不満を惜しみませんでした – yalestar

+0

あなたは大歓迎です、yalestar。 – akuhn

6

2年後、Nokogiri::XML::Builderのドキュメント参照を使用してルートノードを取得し、名前空間を追加することで、これを行うよりクリーンな方法が見つかりました。以前のソリューションと同様に、ネームスペースを追加する前にルートノードが存在する必要があります。

私はこれがより明確である<rootElement><root>要素を変更しました:

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"?> dknight

0

ルークの答えの3年後、それはまだ簡単です。定義済みの "前"の名前空間を使用できるようになりました。このコード:

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> 
関連する問題