2009-12-01 33 views
11

Tôi đang triển khai một nhà xuất khẩu cho một định dạng dữ liệu XML yêu cầu không gian tên. Tôi đang sử dụng Nokogiri XML Builder (phiên bản 1.4.0) để làm điều này.Tạo một tài liệu XML có phần tử gốc không gian tên với trình tạo Nokogiri

Tuy nhiên, tôi không thể khiến Nokogiri tạo nút gốc bằng không gian tên.

này hoạt động:

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

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

Như thực hiện điều này:

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> 

Tuy nhiên, tôi cần một cái gì đó giống như <foo:root> và điều này không làm việc:

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

Namespaces phải được xác định trước khi sử dụng, rõ ràng, vì vậy không có cách nào để thêm một vào nút gốc.

Tôi tìm thấy a question about this on the Nokogiri mailing list, nhưng không có trả lời. Bất cứ ai có một giải pháp?

Trả lời

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 

Bạn không thể sử dụng xml['foo'] trước khi không gian tên được xác định, tức là trước khi bạn chuyển nó làm đối số cho nút gốc. Do đó, đoạn mã trên thêm không gian tên sau khi thực tế vào nút gốc.

+0

trình như một say mê. Cảm ơn! –

+0

Bạn, thưa bạn, đã tha cho tôi nhiều sự thất vọng – yalestar

+0

Bạn được chào đón, yalestar. – akuhn

6

Hai năm sau, tôi tìm thấy một cách rõ ràng hơn để làm điều này bằng cách sử dụng tài liệu tham khảo tài liệu Nokogiri::XML::Builder để truy xuất nút gốc và thêm (các) vùng tên đó vào đó. Giống như giải pháp trước, nó yêu cầu nút gốc tồn tại trước khi các không gian tên có thể được thêm vào nó.

Tôi đã thay đổi các yếu tố <root>-<rootElement> vì vậy đây là rõ ràng hơn:

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 

Bây giờ, builder.to_xml sẽ trở lại:

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

Tôi thích video này tốt hơn vì bạn không cần phải tìm kiếm không gian tên và dễ dàng thêm nhiều không gian tên.

+0

Điều này làm việc tuyệt vời. Cảm ơn. Tuy nhiên, tôi không thể thoát khỏi sự thừa kế không gian tên. Tôi muốn đạt được điều gì đó như sau. giá trị dknight

0

Ba năm sau câu trả lời của Luke, câu trả lời đơn giản hơn rất nhiều. Bây giờ bạn có thể sử dụng không gian tên "trước khi" nó được định nghĩa. Mã này:

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 

đầu ra XML này:

<?xml version="1.0"?> 
<foo:RootElement xmlns:foo="bar" xmlns:baz="bat"> 
    <baz:FirstChild/> 
</foo:RootElement> 
Các vấn đề liên quan