2015-02-03 2 views
6

Nokogiri::XML::Buider으로 생성되는 XML 문서에 Nokogiri::XML::Element을 어떻게 추가 할 수 있습니까?Nokogiri :: XML :: Builder 문서에 XML 요소 추가

현재 해결 방법은 요소를 serialize하고 << 메서드를 사용하여 작성자가 다시 해석하도록하는 것입니다.

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> 

는 그러나 Nokogiri::XML::Element는 (노드의 킬로바이트 그리고 수천의 순서로) 아주 큰 노드이며,이 코드는 뜨거운 경로에 있습니다. 프로파일 링은 직렬화/구문 분석 왕복이 매우 비쌉니다.

어떻게 Nokogiri Builder에 기존 XML 요소 node을 "현재"위치에 추가하도록 지시 할 수 있습니까?

답변

6

개인 방법을 사용하지 않고 당신이 the parent method of the Builder 인스턴스를 사용하여 현재 부모 요소에 대한 핸들을 얻을 수 있습니다. 그런 다음 다른 문서에서도 그 요소를 추가 할 수 있습니다. 예 :

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

이것은'# insert'를 사용하는 나의 kludge보다 훨씬 낫습니다. – gioele

3

Nokogiri 소스를 살펴본 후이 취약한 솔루션을 발견했습니다. 보호 된 #insert(node) 메소드를 사용했습니다.

은 개인 방법을 사용하도록 수정 코드는 다음과 같습니다

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

    doc.second("hi") 
}