Nokogiri to_xml without carriage returns

11,066

Solution 1

Builder#to_xml by default outputs formatted (i.e. indented) XML. You can use the Nokogiri::XML::Node::SaveOptions to get an almost unformatted result.

b = Nokogiri::XML::Builder.new do |xml|
  xml.root do
    xml.foo do
      xml.text("Value")
    end
  end
end

b.to_xml
# => "<?xml version=\"1.0\"?>\n<root>\n  <foo>Value</foo>\n</root>\n"

b.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
# => "<?xml version=\"1.0\"?>\n<root><foo>Value</foo></root>\n"

Now you could either just get rid of the XML header (which is optional anyway) and remove the last newline

b.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION).strip
# => "<root><foo>Value</foo></root>"

Just removing all newlines in the XML is probably a bad idea as newlines can actually be significant (e.g. in <pre> blocks of XHTML). If that is not the case for you (and you are really sure of that) you could just do it.

Solution 2

This is not something that Nokogiri is designed to do. The closest you can get is to serialize the root of the document with no newlines or indentation, and then add the PI yourself (if you really need it):

require 'nokogiri'

b = Nokogiri::XML::Builder.new{ |xml| xml.root{ xml.foo "Value" } }
p b.to_xml
#=> "<?xml version=\"1.0\"?>\n<root>\n  <foo>Value</foo>\n</root>\n"

p b.doc.serialize(save_with:0)
#=> "<?xml version=\"1.0\"?>\n<root><foo>Value</foo></root>\n"

flat_root = b.doc.root.serialize(save_with:0)
p flat_root
#=> "<root><foo>Value</foo></root>"

puts %Q{<?xml version="1.0"?>#{flat_root}}
#=> <?xml version="1.0"?><root><foo>Value</foo></root>

Alternatively, you could simply cheat and do:

puts b.doc.serialize(save_with:0).sub("\n","")
#=> <?xml version="1.0"?><root><foo>Value</foo></root>

Note the usage of sub instead of gsub to only replace the first known-present newline.

Share:
11,066
Cameron
Author by

Cameron

Updated on June 03, 2022

Comments

  • Cameron
    Cameron about 2 years

    I'm currently using the Nokogiri::XML::Builder class to construct an XML document, then calling .to_xml on it. The resulting string always contains a bunch of spaces, linefeeds and carriage returns in between the nodes, and I can't for the life of me figure out how to get rid of them. Here's an example:

    b = Nokogiri::XML::Builder.new do |xml|
      xml.root do
        xml.text("Value")
      end
    end
    
    b.to_xml
    

    This results in the following:

    <?xml version="1.0"?>
    <root>Value</root>
    

    What I want is this (notice the missing newline):

    <?xml version="1.0"?><root>Value</root>
    

    How can this be done? Thanks in advance!

  • Cameron
    Cameron over 12 years
    Unfortunately I'm stuck using Nokogiri v1.3.3 which doesn't allow any arguments to be passed to to_xml. Otherwise, this would be a great solution.
  • Cameron
    Cameron over 12 years
    Replacing just the first \n won't work - the document I'm actually creating is many levels deep, and each node has a \n after it. Some of the text in the nodes contains \n characters as well, which I have to preserve (this is for Android, which requires Java-style strings).
  • Cameron
    Cameron over 12 years
    Ah ok, got it. Looks like you can use this method by passing the save options to serialize instead of to_xml: b.doc.serialize(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
  • Cameron
    Cameron over 12 years
    My final solution looks like this: builder.doc.serialize(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML).sub("\n", "").strip
  • Cameron
    Cameron over 12 years
    This solution is almost the same as the accepted one - thanks!
  • MEENAKSHI KUMARI
    MEENAKSHI KUMARI over 5 years
    thanks this code really helped, but can you please explain me the what save_with does?