jimweirich / builder

Provide a simple way to create XML markup and data structures.
http://builder.rubyforge.org
MIT License
361 stars 103 forks source link

Using text! introduces unwanted whitespace #45

Closed cnk closed 11 years ago

cnk commented 11 years ago

I am not sure if I am reporting a code or a documentation issue. I am trying to create an XML file for import into a third party system and other than using :indent => 0 (which makes the file unreadable to humans), I can't see how to get around Builder introducing extra whitespace around the content of a tag.

If I have "xml.language1('en-US')", I get what I want: <language1>en-US</language1> but if I use tag! + text! to get the same thing, I get an extra new line and some spaces: xml.tag!("language2"){ xml.text!('en-US') }

    <language2>                                                                                                         
en-US    </language2>

The reason I am using tag! + text! is that I have tags with colons in them. A stripped down rake script that demonstrates the issue is:

require 'builder'

namespace :export do
  desc "Export articles into XML - in Wordpress's modified RSS format"
  task :example do
    FILEDIR = "/tmp"
    EXP_FILE = "#{FILEDIR}/example.xml"

    File.open(EXP_FILE, 'w') { |file|
      xml = Builder::XmlMarkup.new(:target => file, :indent => 2)
      xml.instruct! :xml, :version=>"1.0"
      xml.rss(:version=>"2.0", "xmlns:wp" => "http://wordpress.org/export/1.2/", "xmlns:excerpt" => "http://wordpress.org/export/1.2/excerpt/", "xmlns:content" => "http://purl.org/rss/1.0/modules/content/" , "xmlns:dc" => "http://purl.org/dc/elements/1.1/", "xmlns:wfw" => "http://wellformedweb.org/CommentAPI/") {

        xml.channel {
          xml.title("News")
          xml.pubDate(Time.new.strftime("%a, %d %b %Y %H:%M:%S %z"))
          xml.description()
          xml.language1('en-US')
          xml.tag!("language2"){ xml.text!('en-US') }
          xml.tag!("wp:wxr_version"){ xml.text!('1.2') }
          xml.wp :wxr_version do xml.text!('2.1') end

        } # close channel                                                                                               
      } # close rss                                                                                                     
    } # close File                                                                                                      
  end
end

The output I get from that is:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:wp="http://wordpress.org/export/1.2/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:excerpt="http:/\
/wordpress.org/export/1.2/excerpt/" version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="ht\
tp://purl.org/dc/elements/1.1/">
  <channel>
    <title>News</title>
    <pubDate>Mon, 28 Oct 2013 18:42:04 -0700</pubDate>
    <description/>
    <language1>en-US</language1>
    <language2>                                                                                                         
en-US    </language2>
    <wp:wxr_version>                                                                                                    
1.2    </wp:wxr_version>
    <wp:wxr_version>                                                                                                    
2.1    </wp:wxr_version>
  </channel>
</rss>

(NB the Markdown rendering is showing 2 newlines after the opening tag, but I only have one newline in the output)

Versions of things: ruby 1.8.7 - quite old Ruby Enterprise Edition builder (3.2.2)

This does seem to have been this way for a while - at least if I am reading this thread from Ruby Forum correctly. https://www.ruby-forum.com/topic/157276

Is this a bug? or should I be doing something differently?

jimweirich commented 11 years ago

Try this:

  xml.channel {
    xml.title("News")
    xml.pubDate(Time.new.strftime("%a, %d %b %Y %H:%M:%S %z"))
    xml.description()
    xml.language1('en-US')
    xml.tag!("language2",'en-US')
    xml.tag!("wp:wxr_version", '1.2')
    xml.wp :wxr_version, '2.1'
  }
cnk commented 11 years ago

Thanks. That is perfect. And now that I know the answer, I see how the docs indicate that is the answer.

Could you answer one more question? Why is the output of text! other than what I expected? Here are a couple of tests extracted from test_markupbuillder.rb plus one failing test when I use text! in an indented context.

require 'test/unit'
require 'test/preload'
require 'builder'
require 'builder/xmlmarkup'

class TestMarkupIntending < Test::Unit::TestCase
  def test_no_indent_does_not_add_extra_newlines_nor_spaces
    @xml = Builder::XmlMarkup.new(:indent => 0)
    @xml.p { |x|
      x.ol { x.li "text" }
      x.br
    }
    assert_equal "<p><ol><li>text</li></ol><br/></p>", @xml.target!
  end

  def test_indent_does_not_add_extra_newlines_with_regular_tags
    @xml = Builder::XmlMarkup.new(:indent => 2)
    @xml.p { |x|
      x.ol { x.li "text" }
      x.br
    }
    assert_equal "<p>\n  <ol>\n    <li>text</li>\n  </ol>\n  <br/>\n</p>\n", @xml.target!
  end

  def test_indent_does_not_add_extra_newlines_with_text_bang
    @xml = Builder::XmlMarkup.new(:indent => 2)
    @xml.p { |x|
      x.ol { x.li { |y| y.text! "text" } }
      x.br
    }
    assert_equal "<p>\n  <ol>\n    <li>text</li>\n  </ol>\n  <br/>\n</p>\n", @xml.target!
    @xml.p { |x| x.text! "HI" }
  end
end

  1) Failure:
test_indent_does_not_add_extra_newlines_with_text_bang(TestMarkupIntending) [/Users/cnk/Code/ruby/builder/test/test_iss\
ue_45.rb:34]:
<"<p>\n  <ol>\n    <li>text</li>\n  </ol>\n  <br/>\n</p>\n"> expected but was
<"<p>\n  <ol>\n    <li>\ntext    </li>\n  </ol>\n  <br/>\n</p>\n">.