2015-02-03 11 views
6

Làm cách nào để thêm Nokogiri::XML::Element vào tài liệu XML đang được tạo với Nokogiri::XML::Buider?Thêm phần tử XML vào tài liệu Nokogiri :: XML :: Builder

Giải pháp hiện tại của tôi là sắp xếp lại phần tử và sử dụng phương thức << để Builder xây dựng lại nó.

orig_doc = Nokogiri::XML('<root xmlns="foobar"><a>test</a></root>') 
node = orig_doc.at('/*/*[1]') 

puts Nokogiri::XML::Builder.new do |doc| 
    doc.another { 
     # FIXME: this is the round-trip I would like to avoid 
     xml_text = node.to_xml(:skip_instruct => true).to_s 
     doc << xml_text 

     doc.second("hi") 
    } 
end.to_xml 

# The expected result is 
# 
# <another> 
# <a xmlns="foobar">test</a> 
# <second>hi</second> 
# </another> 

Tuy nhiên Nokogiri::XML::Element là một nút khá lớn (theo thứ tự của kilobyte và hàng ngàn nút) và mã này là trong đường dẫn nóng. Hồ sơ cho thấy rằng chuyến đi vòng/tuần tự phân tích rất tốn kém.

Làm cách nào tôi có thể hướng dẫn Trình tạo Nokogiri thêm thành phần XML hiện có node vào vị trí "hiện tại"?

Trả lời

6

Nếu không sử dụng một phương pháp riêng, bạn có thể có được một tay cầm ở yếu tố phụ huynh hiện nay sử dụng the parent method of the Builder dụ. Sau đó, bạn có thể thêm một phần tử vào đó (ngay cả từ một tài liệu khác). Ví dụ:

require 'nokogiri' 
doc1 = Nokogiri.XML('<r><a>success!</a></r>') 
a = doc1.at('a') 

# note that `xml` is not a Nokogiri::XML::Document, 
# but rather a Nokogiri::XML::Builder instance. 
doc2 = Nokogiri::XML::Builder.new do |xml| 
    xml.some do 
    xml.more do 
     xml.parent << a 
    end 
    end 
end.doc 

puts doc2 
#=> <?xml version="1.0"?> 
#=> <some> 
#=> <more> 
#=>  <a>success!</a> 
#=> </more> 
#=> </some> 
+0

Điều này tốt hơn nhiều so với kludge của tôi với '# insert'. – gioele

3

Sau khi xem nguồn Nokogiri, tôi đã tìm thấy giải pháp mong manh này: sử dụng phương pháp #insert(node) được bảo vệ.

Mã, sửa đổi để sử dụng phương pháp riêng trông như thế này:

doc.another { 
    xml_text = node.to_xml(:skip_instruct => true).to_s 
    doc.send('insert', xml_text) # <= use `#insert` instead of `<<` 

    doc.second("hi") 
} 
Các vấn đề liên quan