If you want to optimize for speed, I'd recommend using Nokogiri, but not the Nokogiri::XML::Builder which will perform about as well as the Builder gem. Instead, use the lower-level Document and Node APIs.
Here's some code showing equivalent document construction for Builder, Nokogiri::XML::Builder, and Nokogiri::XML::Document ... and a benchmark if it's helpful (higher numbers are better, it's iterations per second):
#! /usr/bin/env ruby
require "bundler/inline"
gemfile do
source "
https://rubygems.org"
gem "builder"
gem "nokogiri"
gem "benchmark-ips"
end
require "builder"
require "nokogiri"
require "benchmark/ips"
N = 100
# using Builder::XmlMarkup, build an XML document representing attributes of a person
def builder_person
xml = Builder::XmlMarkup.new
xml.people do |p|
N.times do
xml.person do |p|
p.name "John Doe"
p.age 42
p.address do |a|
a.street "123 Main Street"
a.city "Anytown"
end
end
end
end
end
# using Nokogiri::XML::Builder, build an XML document representing attributes of a person
def nokogiri_person
Nokogiri::XML::Builder.new do |xml|
xml.people do
N.times do
xml.person do |p|
p.name "John Doe"
p.age 42
p.address do |a|
a.street "123 Main Street"
a.city "Anytown"
end
end
end
end
end.to_xml
end
# use Nokogiri's bare API to build an XML document representing attributes of a person
def nokogiri_raw_person
xml = Nokogiri::XML::Document.new
xml.root = xml.create_element("people")
N.times do
xml.root.add_child(xml.create_element("person")).tap do |p|
p.add_child(xml.create_element("name", "John Doe"))
p.add_child(xml.create_element("age", 42))
p.add_child(xml.create_element("address")).tap do |a|
a.add_child(xml.create_element("street", "123 Main Street"))
a.add_child(xml.create_element("city", "Anytown"))
end
end
end
xml.to_xml
end
puts RUBY_DESCRIPTION
# pp builder_person
# pp nokogiri_person
# pp nokogiri_raw_person
Benchmark.ips do |x|
x.report("builder") { builder_person }
x.report("nokogiri") { nokogiri_person }
x.report("nokogiri raw") { nokogiri_raw_person }
x.compare!
end