How to parse and send whole complicated XML from code in Rails - ruby

So I have this complicated XML and want it to parse it to array and send by Savon to the server. The question is how can I parse parameters?
<soapenv:Header>
<add:MessageID
xmlns:add="http://www.w3.org">sdhuf78dd67-8932
</add:MessageID>
<add:Action
xmlns:add="http://www.w3.org/2005">http://google/FMP
</add:Action>
<add:To
xmlns:add="http://www.w3.org/2005/08/addressing">https://no1.testbla.com/1HAD9ANA1
</add:To>
<link:TransactionFlowLink
xmlns:link="http://google/2010/06/"/>
<oas:Security
xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<oas:UsernameToken oas1:Id="UsernameToken-1"
xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<oas:Username>AHOJHOLA</oas:Username>
<oas:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">Nonce</oas:Nonce>
<oas:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">HashedPassword</oas:Password>
<oas1:Created>CurrentGMTDateAndTime</oas1:Created>
</oas:UsernameToken>
</oas:Security>
<AMA_SecurityHostedUser
xmlns="http://xml.amfds.com/2010/06">
<UserID AgentDutyCode="DA" RequestorType="BO" PseudoCityCode="HIATRA67" POS_Type="5"/>
</AMA_SecurityHostedUser>
</soapenv:Header>
I know how to parse for example add:Action without parameter:
"add:Action" => "http://google/FMP"
And I know that parameter should be written with # prefix.
But I dont know how to write it together. Is this right?
"add:Action" => {
"#xmlns:add" => "http://www.w3.org/2005",
"http://google/FMP"
},etc.

To find out this information, you need to go and have a look at the Gyoku gem: the gem that Savon uses to translate Ruby hashes into XML. Specifically, the documentation on using explicit XML attributes. Looking at that, we can get the XML you're looking for with the following hash:
{
"add:Action" => {
"#xmlns:add" => "http://www.w3.org/2005",
:content! => "http://google/FMP"
}
}
We can test this in IRB directly with Gyoku:
irb> require 'gyoku'
# => true
irb> Gyoku.xml({"add:Action" => { "#xmlns:add" => "http://www.w3.org/2005", :content! => "http://google/FMP" } })
# => "<add:Action xmlns:add=\"http://www.w3.org/2005\">http://google/FMP</add:Action>"

Related

In which version of ruby appeared ':' instead '=>'?

I mean
some: true
vs
:some => true
I have problem with compatibility my Rails version and Ruby version and I have to know in which version appeared only : instead =>.
I don't know how to find this kind of info by Google.
This is a feature introduced into Ruby 1.9:
{ example: 'key' }
# => { :example => 'key' }
This is similar to how JavaScript and other languages define their dictionary-type structures. The keys generated this way are always Symbol-type.
It's also possible to mix and match:
variable = :foo
{ example: 'key', 'string' => 'stored', variable => 'thing' }
# => {:example=>"key", "string"=>"stored", :foo=>"thing"}
This is a good thing because the x: approach is more limited. If you want dots in your keys, for example, you'll need to use the older style.

In Ruby, how to upload multiple files in single request using RESTClient

I have to upload multiple files as form request. I am using the Rest Client to post my request. I am able to upload single file but I am not sure how to add multiple files in a single request.
I searched/googled for such option and I am not finding any solution that solves my problem.
Below is my code.
It has variable argument (*yamlfile) which takes one or more files. I have to upload all the files together.
The issue now is , I am getting syntax error when I add the loop to extract the file within the payload.
my assumption is now to form this outside the payload and include it inside the payload block but I am not sure how to do it.
Can someone help me with that.
( I have tried net/http/post/multipart library too and I don't find much documents around it)
def uploadRest(endpoint,archive_file_path,,yaml_file_path,*yamlfile)
$arg_len=yamlfile.length
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => {
:multipart => true,
:job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp",
# Trying to add multiple file, but I get syntax error
yamlfile.each_with_index { |yaml, index|
:job_upload_yaml_file+index => File.new("#{yaml_file_path}/#{pmml}")
}
})
response=request.execute
puts response.code
end
uploadRest(endpoint,archive_file_path,yaml_file_path,*yamlfile)
#files=Array.new
yamlfile.each{ |yaml_file|
#files.push(File.new("#{yaml_file_path}/#{yaml_file}"))
}
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => { :multipart => true, :job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp", :job_upload_yaml_file => #files })
response=request.execute
end
I had a similar problem and was able to get this to work by passing an array of arrays as a requests.
file1 = File.new("#{yaml_file_path}/#{yaml_file1}", 'rb')
file2 = File.new("#{yaml_file_path}/#{yaml_file}", 'rb')
request_body = [["files", file1], ["files", file2]]
RestClient.post url, request_body, request_headers
There were two issues with your question code:
1) Attempt to add a symbol to an integer
2) Attempt to insert contents of yamlfile direct into the hash (because that is what yamlfile.each_with_index returns, as opposed to how it calls your block. The return value from the block is not used)
Both of these code issues read as if you have gained experience in HAML or another templating language, and are using structures/ideas that would work in that?
There are lots of possble solutions in Ruby, but a simple approach to build up the hash in parts, as opposed to generate it in one go with clever hash-returning routines embedded. Try something like this:
payload_hash = {
:multipart => true,
:job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp",
}
# This does not use the return value from each_with_index, instead it relies
# on the block to make changes to the hash by adding new key/value pairs
yamlfile.each_with_index { |yaml, index|
# This concatenates two strings, and then converts the combined
# string into the symbol that you want
file_key = ("job_upload_yaml_file"+index.to_s).to_sym
payload_hash[file_key] = File.new("#{yaml_file_path}/#{yaml}")
}
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => payload_hash
)
For added code cleanliness, you could make the first two parts a separate method, and call it where it currently has payload_hash.
This should get you over current syntax hurdles. However, I have made no attempt to check whether this will allow you to upload multiple files via RESTClient.
Section1:
#params = {
"FacialImage" => UploadIO.new(File.new('C:\temp\ATDD\Test\test\sachin.jpg'), "image/jpeg"),
"Login" => UploadIO.new(File.new('C:\temp\ATDD\Test\test\login.txt'), "application/json")
}

Looping through XML to create an array of hashes in Ruby

I have the following XML
<CallResult>
<Success>true</Success>
<Result>
<ZoneInfo>
<Id>3</Id>
<Name>test-room</Name>
<NId>sdfsdg</NId>
</ZoneInfo>
<ZoneInfo>
<Id>16</Id>
<Name>Dynamic</Name>
<NId>sadadrwed543th</NId>
</ZoneInfo>
<ZoneInfo>
<Id>32</Id>
<Name>lobby</Name>
<NId>ssdfrgfdfg</NId>
</ZoneInfo>
<ZoneInfo>
<Id>33</Id>
<Name>conf</Name>
<NId>sdfsfewr232f</NId>
</ZoneInfo>
</Result>
<Message>Success</Message>
</CallResult>
I am trying to parse the XML so that each different 'ZoneInfo' attributes is a hash in an array.
E.g.
Zones[0] = Hash[Id => 32, Name => lobby, NId => ssdfrgfdfg]
Zones[1] = Hash[Id => 33, Name => conf, NId => sdfsfewr232f]
etc...
My limited XML parsing knowledge has come a croper. All I really know is how to extract a single element. E.g.
doc = REXML::Document.new(xmlData)
doc.elements.each("CallResult/Success") do |ele|
p ele.text;
end
Could someone help with some more info on how to loop through just extracting info from each 'ZoneInfo' element?
Thanks
I use another gem 'nokogiri', maybe the best gem to parse HTML/XML now.
require 'nokogiri'
str = "<CallResult> ......"
doc = Nokogiri.XML(str)
Zones = []
doc.xpath('//ZoneInfo').each do |zone|
Zones << { "Id" => zone.xpath('Id').text, "Name" => zone.xpath('Name').text, "NId" => zone.xpath("NId").text}
end
You just need to use nori gem
require 'nori'
your_hash = Nori.parse(your_xml)
And then it should be straightforward to convert this nested hash to an array of hashes if you need to store your data that way.
If you need more info, api doc is here - http://rubydoc.info/gems/nori/1.1.3/frames

Ruby RestClient converts XML to Hash

I need to send a POST request as an XML string but I get odd results. The code:
require 'rest_client'
response = RestClient.post "http://127.0.0.1:2000", "<tag1>text</tag1>", :content_type => "text/xml"
I expect to receive "<tag1>text</tag1>" as the parameter on the request server. Instead, I get "tag1"=>"text". It converts the XML to a hash. Why is that? Any way around this?
Try this:
response = RestClient.post "http://127.0.0.1:2000",
"<tag1>text</tag1>",
{:accept => :xml, :content_type => :xml}
I think you just needed to specify the ":accept" to let it know you wanted to receive it in the XML format. Assuming it's your own server, you can debug on the server and see the request format used is probably html.
Hope that helps.
Instead of using RestClient, use Ruby's built-in Open::URI for GET requests or something like Net::HTTP or the incredibly powerful Typhoeus:
uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
In Typhoeus, you'd use:
res = Typhoeus::Request.post(
'http://localhost:3000/posts',
:params => {
:title => 'test post',
:content => 'this is my test'
}
)
Your resulting page, if it's in XML will be easy to parse using Nokogiri:
doc = Nokogiri::XML(res.body)
At that point you'll have a fully parsed DOM, ready to be searched, using Nokogiri's search methods, such as search and at, or any of their related methods.

how RestClient gem work in ruby

I'm using Rest-client gem in ruby.My code is as follows..,
require 'rest_client'
puts RestClient.get 'http://localhost:3000/articles'
puts RestClient.put 'http://localhost:3000/', {:params => {:Bat => 'ball'}}
RestClient.post 'http://localhost:3000/articles', {:params => {:Name => 'list1', 'Content' => 'Article1'}}
I refer the URL which runs in rails application, the user can can create, delete, edit,list the articles using the above url.For put,delete,post,get methods it produces the html code of the URL in my prompt.But it cannnot able to insert the post/delete an item from the list via ruby code.
It is possible in RestClient?
I think the problem here is that you need to be authenticated. You can do that with RestClient but you will need to chain your calls. See the rest_client Readme how to do that.

Resources