如何将Nokogiri::XML::Element
添加到使用Nokogiri::XML::Buider
创建的XML文档?
我目前的解决方案是序列化元素并使用<<
方法让Builder重新解释它。
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
添加到“当前”位置?
答案 0 :(得分:9)
不使用私有方法,您可以使用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>
答案 1 :(得分: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")
}