I'm using Rails 2.1.0 and Nokogiri 1.6.1. What I want seems pretty simple. I want my Rails Rest API to return XML with an element like this:
<PeopleNumber unit="NumberOfPeople">2.235075</PeopleNumber>
I tried writing something like:
xml = Nokogiri::NML::Builder.new do |xml|
xml.PeopleNumber(:unit => "NumberOfPeople") 2.235075
ActionController fires off a syntax error.
If I try re-writing this as
xml = Nokogiri::NML::Builder.new do |xml|
xml.PeopleNumber(:unit => "NumberOfPeople") { 2.235075 }
I get something like
<PeopleNumber unit="NumberOfPeople" />
Does anyone know of a way to get the desired behavior in Nokogiri?
I know this is quite old question, but even I stumbled upon same problem.
I found a clean solution.
builder = Nokogiri::NML::Builder.new do |xml|
xml.PeopleNumber(2.235075, :unit => "NumberOfPeople")
end
now if you debug the XML output you will get the right output
puts builder.to_xml
# output will be following
<PeopleNumber unit="NumberOfPeople">2.235075</PeopleNumber>
Explanation: When you want to set some attributes and text content to XML tag using Nokogiri builder then you need to directly pass text content as first argument and then other attributes as key-value pairs same as we pass to any method.
builder = Nokogiri::NML::Builder.new do |xml|
xml.YourTagName(PLAIN_TEXT_CONTENT, attr1: value1, attr2: value2, attrN: valueN)
end
This will output as
puts builder.to_xml
# output will be following
<YourTagName attr1="value1" attr2="value2" attrN="valueN">PLAIN_TEXT_CONTENT</YourTagName>
Even there are other ways but this is the cleanest one.
Do it the simple way:
require 'nokogiri'
doc = Nokogiri::XML('<foo></foo>')
doc.at('foo').add_child('<PeopleNumber unit="NumberOfPeople">2.235075</PeopleNumber>')
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >> <PeopleNumber unit="NumberOfPeople">2.235075</PeopleNumber>
# >> </foo>
The trick is add_child
, which can take a predefined node, or a string consisting of the XML you want to add. From the documentation:
Add node_or_tags as a child of this Node. node_or_tags can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
"a string containing markup" is a free-pass to doing it an easy way.
If you need a different value for the unit
parameter, or a different value for the tag itself, you can interpolate those into the string:
foo = 'WheelSize'
bar = '355/113'
doc = Nokogiri::XML('<foo></foo>')
doc.at('foo').add_child("<PeopleNumber unit='#{foo}'>#{bar}</PeopleNumber>")
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >> <PeopleNumber unit="WheelSize">355/113</PeopleNumber>
# >> </foo>
Or you can directly modify the DOM and nodes:
doc = Nokogiri::XML('<foo><PeopleNumber /></foo>')
people_number = doc.at('PeopleNumber')
people_number['unit'] = 'fred'
people_number.content = 'ethel'
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >> <PeopleNumber unit="fred">ethel</PeopleNumber>
# >> </foo>
There are other ways to do this in addition, but it's really up to you to use whatever fits your head best.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With