Adding an XML Element to a Nokogiri :: XML :: Builder Document

How to add Nokogiri::XML::Element to an XML document created using Nokogiri::XML::Buider ?

My current solution is to serialize the element and use the << method so that Builder interprets it.

 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> 

However, Nokogiri::XML::Element is a rather large node (in kilobyte order and thousands of nodes), and this code is in a hot way. Profiling shows that serializing / disassembling both ways is very expensive.

How can I tell Nokogiri Builder to add an existing node XML element to the "current" position?

+6
source share
2 answers

Without using a private method, you can get the handle to the current parent using the parent method of the Builder instance . Then you can add an element to this (even from another document). For instance:

 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> 
+6
source

After looking at the Nokogiri source, I found this fragile solution: using the protected #insert(node) method.

The code modified to use this private method is as follows:

 doc.another { xml_text = node.to_xml(:skip_instruct => true).to_s doc.send('insert', xml_text) # <= use `#insert` instead of `<<` doc.second("hi") } 
+3
source

Source: https://habr.com/ru/post/981932/


All Articles