Ruby to_xml change attributes name for Api request - ruby-on-rails

I want to convert the keys for xml response So that they match with third party Api request.
class Person1
include ActiveModel::Serializers::Xml
attr_accessor :name, :age
def attributes
{'name' => nil, 'age' => nil}
end
def capitalized_name
name.capitalize
end
end
p = Person1.new
p.name = "test"
puts p.to_xml
output ::-
<?xml version="1.0" encoding="UTF-8"?>
<person1>
<age nil="true"/>
<name>test</name>
</person1>
I am looking for a way to change keys in xml output like.
<?xml version="1.0" encoding="UTF-8"?>
<person1>
<Age nil="true"/>
<Name>test</Name>
</person1>

How about:
puts p.to_xml(:camelize => true)
<?xml version="1.0" encoding="UTF-8"?>
<Person1>
<Age nil="true"/>
<Name>test</Name>
</Person1>
Or if the uppercase Person bothers you, I guess you can do something like that:
puts p.to_xml(:camelize => true).sub('<Person1>','<person1>').sub('</Person1>','</person1>')
<?xml version="1.0" encoding="UTF-8"?>
<person1>
<Age nil="true"/>
<Name>test</Name>
</person1>

Related

Savon using built in request builder instead of raw xml

If i use savon with raw xml everything works fine, this is the raw xml example:
request = client.call(:authenticate, xml:'<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="xxxx/">
<SOAP-ENV:Body>
<ns1:authenticate>
<ns1:username>user</ns1:username>
<ns1:password>pwd</ns1:password>
<ns1:cultureInfo>it</ns1:cultureInfo>
</ns1:authenticate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>')
If I use the builtin method to call the method I got an error, this is the code:
credentials={ username: 'user', password: 'pwd!!', cultureInfo: "it" }
response = client.call(:authenticate, message: credentials)
This is the xml produced by the above code:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://tempuri.org/"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<wsdl:authenticate>
<username>user</username>
<password>pwd</password>
<cultureInfo>it</cultureInfo>
</wsdl:authenticate>
</env:Body>
</env:Envelope>
Any Idea?
I usually do just this (untested). It's not pretty but it works.
credentials = { 'ns1:username' => 'user',
'ns1:password' => 'pwd!!',
'ns1:cultureInfo' => "it" }
response = client.call(:authenticate, message: credentials)
You might want to adapt the use of ns1 to the actually used namespace in your case.

Add a node to XML using Nokogiri::XML::Builder

I have a Nokogiri::XML::Builder instance, when I call to_xml it produces following structure:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>...</item>
<item>...</item>
</root>
Using this instance I'd like to add one more <item> node under <root> like this:
def add_static_job(builder)
source = builder.doc.root
item = Nokogiri::XML::Node.new('item', source)
item.content = '<title>Hello</title>'
source << item
end
Unfortunatelly this doesn't produce valid xml in the end, rather something like:
<item><title>Hello<title></item>
What could the problem be?
You could do it in 2 steps :
create title node with "Hello" as content
create item node with title as content
xml = '<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>A</item>
<item>B</item>
</root>'
require 'nokogiri'
doc = Nokogiri::XML.parse(xml)
source = doc.root
title = Nokogiri::XML::Node.new('title', doc)
title.content = "Hello"
item = Nokogiri::XML::Node.new('item', doc)
item << title
source << item
puts doc
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <root>
# <item>A</item>
# <item>B</item>
# <item><title>Hello</title></item></root>

ruby to_xml set root attributes

I need to convert a ruby hash to xml. Here is the hash:
hash = {
"AffiliateInfo" => {
"Username" => '123456',
"Password" => "Mypass",
"TrackingCampaign" => "MyTrackingCampaign",
"Env" => "production"
}
}
and the xml I wanted to generate:
<?xml version="1.0" encoding="UTF-8"?>
<InsuranceRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AffiliateInfo>
<Username>12696</Username>
<Password>MyPassword</Password>
<TrackingCampaign>MyTrackingCampaign</TrackingCampaign>
<LeadSourceID>SourceID</LeadSourceID>
<ProductionEnvironment>true</ProductionEnvironment>
</AffiliateInfo>
</InsuranceRequest>
When I do:
hash.to_xml(root: 'InsuranceRequest')
I get the following xml output
<?xml version="1.0" encoding="UTF-8"?>
<InsuranceRequest>
<AffiliateInfo>
<Username>123456</Username>
<Password>Mypass</Password>
<TrackingCampaign>MyTrackingCampaign</TrackingCampaign>
<Env>production</Env>
</AffiliateInfo>
</InsuranceRequest>
The output is missing the properties of the root node attributes:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
I cannot add attributes to the root node. Is there a way to add these attributes using to_xml method?
Please suggest if there is any other means to solve my problem.
You need to use custom builder. Here is example with Nokogiri builder
require 'nokogiri'
hash = {"AffiliateInfo" => {
"Username" => '123456',
"Password" => "Mypass",
"TrackingCampaign" => "MyTrackingCampaign",
"Env" => "production"
}
}
builder = Nokogiri::XML::Builder.new do |xml|
xml.InsuranceRequest('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema') do
xml.AffiliateInfo do
hash['AffiliateInfo'].each do |k, v|
xml.send(k, v)
end
end
end
end
builder.to_xml
This produces the following XML document
<?xml version="1.0"?>
<InsuranceRequest
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AffiliateInfo>
<Username>123456</Username>
<Password>Mypass</Password>
<TrackingCampaign>MyTrackingCampaign</TrackingCampaign>
<Env>production</Env>
</AffiliateInfo>
</InsuranceRequest>
Please note that hash should be defined before builder
Here is Nokogiri documentation http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Builder

How can I use :only in conjunction with :include in the to_xml in a Rails app?

I'm trying to make use of both :only and :include options in to_xml call in a Rails app. Here's the code:
current_user.to_xml(
:include => :subscription,
:only => [:email, :username]
)
The result of this is somthing like:
<?xml version="1.0" encoding="UTF-8"?>
<user>
<username>cristi</username>
<email>cristi#example.com</email>
<subscription>
</subscription>
</user>
The problem is that subscription has more fields, which are not included. I assume its because of the :only option.
Is there a way to overcome this (show all fields in the subsscription element), without using :except as an option in to_xml ?
I am using Rails 3.
Yes, you can. It works perfectly for me.
>> u = User.first
>> puts u.to_xml(:only => %w( id name ))
<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>Simone Carletti</name>
<id type="integer">1</id>
</user>
>> puts u.to_xml(:only => %w( id name ), :include => :domains)
<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>Simone Carletti</name>
<id type="integer">1</id>
<domains type="array">
<domain>
<name>...</name>
<id type="integer">0</id>
</domain>
<domain>
<name>...</name>
<id type="integer">0</id>
</domain>
</domains>
</user>
Make sure the :subscription association is correct. If it's a one-to-many association, you need to use the pluralized version :subscriptions.

rails inverting to_xml and getting the original model

I did this:
[User.first, User.last].to_xml
and got this:
<users type="array">
<user>
<created-at type="datetime">2010-03-16T06:40:51Z</created-at>
<id type="integer">3</id>
<password-hash></password-hash>
<salt></salt>
<updated-at type="datetime">2010-03-16T06:40:51Z</updated-at>
<username nil="true"></username>
</user>
<user>
<created-at type="datetime">2010-03-23T03:58:15Z</created-at>
<id type="integer">7</id>
<password-hash></password-hash>
<salt></salt>
<tutorial-state nil="true"></tutorial-state>
<updated-at type="datetime">2010-03-23T03:58:15Z</updated-at>
<username nil="true"></username>
</user>
</users>
How can I take that string of xml and invert it to get the original activerecord objects back?
Try this:
Model object xml:
xml = User.first.to_xml
User.new(Hash.from_xml(xml))
Array of model xml:
xml = User.all.to_xml
users = (Hash.from_xml(xml)["users"] || []).collect{|attr| User.new(attr)}
I do know that you can do this on individual users; doing it on an array will require your own bit of XML parsing.
user = User.new
user.from_xml '<user><id type="integer">1</id></user>'

Resources