Ashitaka
Ashitaka

Reputation: 19203

How to join/merge xml files into a single file and return it?

I'm using the Last.fm API and I'm trying to get a lot of info about a certain user and returning it in xml. So, here's the call in my view:

<%= form_tag fetch_user_path, :remote => true, :'data-type' => 'xml', :id => 'search' do %>
  <%= text_field_tag :q %>
<% end %>

So, as you can see, it's expecting XML, and I'm correctly handling the callback using jQuery. Then, in my controller:

# fetch_controller.rb
def user
  username = params[:q].gsub(' ','+')
  get_info_url = "http://ws.audioscrobbler.com/2.0/?method=user.getinfo&user=#{username}&api_key=#{API_KEY}"
  get_friends_url = "http://ws.audioscrobbler.com/2.0/?method=user.getfriends&user=#{username}&api_key=#{API_KEY}"

  respond_to do |format|
    format.xml {
      begin
        @info = Nokogiri::XML(open(get_info_url))
        @friends = Nokogiri::XML(open(get_friends_url))
      rescue Exception => e
        if e.message == '400 Bad Request'
          render xml: { :error => 'User not found.' }, :status => 400
        else
          render xml: { :error => 'Connection to Last.fm failed.' }, :status => 500
        end
      else
        # Here, I want to render @info + @friends!
        render xml: @info
      end
    }
end

This way, I'm correctly returning the xml returned by get_info_url. However, I want to join that xml to the xml returned by get_friends_url. How would I go about that?

Following Ben Miller's answer, I'm getting a parserror on my callback. I think it's got to to do with both xml files containing xml version. And maybe the combined file does not? I'm seeing that the xml files are being concatenated, here's how they look using console.log:

Error: Invalid XML: <?xml version="1.0"?>
<Combined>
  <UserInfo>
    <?xml version="1.0" encoding="utf-8"??>
    <lfm status="ok">
      <user>
        # lots of info about the user
      </user>
    </lfm>
  </UserInfo>
  <FriendInfo>
    <?xml version="1.0" encoding="utf-8"??>
      <lfm status="ok">
        <friends for="user" page="1" perpage="50" totalpages="2" total="96">
          # lots of info about the user's friends
        </friends>
      </lfm>
  </FriendInfo>
</Combined>

Upvotes: 3

Views: 2158

Answers (1)

Ben Miller
Ben Miller

Reputation: 1484

One option it so convert the two XML object to a string and concat them, then wrap in a new root node.

Or you could do it with Nokogiri builder

def user
  username = params[:q].gsub(' ','+')
  get_info_url = "http://ws.audioscrobbler.com/2.0/?method=user.getinfo&user=#{username}&api_key=#{API_KEY}"
  get_friends_url = "http://ws.audioscrobbler.com/2.0/?method=user.getfriends&user=#{username}&api_key=#{API_KEY}"

  respond_to do |format|
    format.xml {
      begin
        info_xml = Nokogiri::XML(open(get_info_url))
        friends_xml = Nokogiri::XML(open(get_friends_url))
        builder = Nokogiri::XML::Builder.new do |xml_out|
          xml_out.Combined {
            xml_out.UserInfo {
              node = info_xml.at_xpath("//user")
              xml_out << node.to_xml.to_str
            }
            xml_out.FriendInfo {
              node = friends_xml.at_xpath("//friends")
              xml_out << node.to_xml.to_str
            }
          }
        end
      rescue Exception => e
        if e.message == '400 Bad Request'
          render xml: { :error => 'User not found.' }, :status => 400
        else
          render xml: { :error => 'Connection to Last.fm failed.' }, :status => 500
        end
      else
        render xml: builder.to_xml
      end
    }
  end
end

Upvotes: 4

Related Questions