<title>Webisode 200 Playlist</title>
<item>
<title>Testing 201</title>
<media:credit role="author">Adam Houston</media:credit>
<media:content url="http://www.youtube.com/watch?v=gb0bGZ06vXn" type="video/x-flv" />
<jwplayer:duration>200</jwplayer:duration>
</item>
i'm using rails xml to generate the corresponding xml but my question is how do i generate tags with namespace like or also how do i tell xml about the attirbutes like role="author".
Regards,
use the tag! method if you want to create such tags:
xml.tag!("SOAP:Envelope") # => <SOAP:Envelope/>
attributes are passed as hash options:
xml.target("name"=>"compile") # => <target name="compile"\>
see the documentation for more infos: http://ap.rubyonrails.org/classes/Builder/XmlMarkup.html#M000157
Related
I'm trying to parse a simple XML data with nokogiri.
this is my XML:
POST /.... HTTP/1.1
Host: ....
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://...."
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="...." xmlns:xsd="...." xmlns:soap="....">
<soap:Body>
<WS_QueryOnSec xmlns="......">
<type>string</type>
<ID>string</ID>
</WS_QueryOnSec>
</soap:Body>
</soap:Envelope>
and this is my simle request:
require "nokogiri"
#doc = Nokogiri::XML(request.body.read)
#something = #doc.at('type').inner_html
But Nokogiri can not find the Type or ID node.
When I change the data into this every thing works fine:
<soap:Body>
<type>string</type>
<ID>string</ID>
</soap:Body>
It seems the problem is the raw text above the data and the nods with xmlns or the other attributes!
What do you recommend to resolve this ?
The first "XML" isn't XML. It's text that contains XML. Remove the header information down to the blank line and try it again.
I think it'd help you to read the XML spec or to read some tutorials about creating XML which will help you understand how it's defined. XML is a tight specification and doesn't allow any deviation. The syntax is pretty flexible, but you have to play by its rules.
Consider these examples:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
foo
<root>
<node />
</root>
EOT
doc.errors # => [#<Nokogiri::XML::SyntaxError: Start tag expected, '<' not found>]
Removing the text, which is outside the root tag results in a proper parse:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<root>
<node />
</root>
EOT
doc.errors # => []
<root> isn't neccesarily the name of the "root" node, it's just the outermost tag:
doc = Nokogiri::XML(<<EOT)
<foo>
<node />
</foo>
EOT
doc.errors # => []
and still results in a valid DOM/internal representation of the document:
puts doc.to_html
# >> <foo>
# >> <node></node>
# >> </foo>
Your XML sample is using namespaces, which complicate matters somewhat. The Nokogiri documentation talks about how to deal with them, so you'll want to understand that part of parsing XML because you'll encounter it again. Here's the easy way of working with them:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns:xsi="...." xmlns:xsd="...." xmlns:soap="....">
<Body>
<WS_QueryOnSec xmlns="......">
<type>string</type>
<ID>string</ID>
</WS_QueryOnSec>
</Body>
</Envelope>
EOT
namespaces = doc.collect_namespaces
doc.at('type', namespaces).text # => "string"
I'm attempting to parse this XML with nokogirl but I'm having trouble. Any ideas where I'm going wrong? I'd like to get each Dealer and get the values for each of them.
doc = Nokogiri::Slop(response.body)
puts doc.content #works, shows the response below
puts doc.DTX_LEAD_ID.content #errors, no method found.
puts doc.NEWCAR_PINGGX_RESPONSE.content #errors, no method found
returned XML:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="www.example.com/">
<?xml version="1.0" encoding="utf-8"?>
<NEWCAR_PINGGX_RESPONSE xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="www.example.com/SellerMessages">
<DTX_LEAD_ID>1779853194</DTX_LEAD_ID>
<SUCCESS>true</SUCCESS>
<CACHED_RESPONSE>false</CACHED_RESPONSE>
<PRICE>20</PRICE>
<DealerList>
<Dealer>
<BUYER_ID>0000-2127</BUYER_ID>
<Reservation_ID>1779853194|0000-2067|520a8037-57c8-497e-be4b-f4ea8dfa6c6f|14187-20</Reservation_ID>
<Price>20</Price>
<Name>Randy's Rides</Name>
<State>MI</State>
<City>Southfield</City>
<Street>2001 Town Center</Street>
<Postalcode>48076</Postalcode>
<Distance>2.56002068066733</Distance>
<DealerGroup id="2067" max_post="5" />
<Contact><Name>John Campbell</Name>
<Phone>2483521314</Phone>
</Contact>
</Dealer>
</DealerList>
</NEWCAR_PINGGX_RESPONSE></string>
Previously I've had a response like this:
<?xml version="1.0" encoding="utf-8"?>
<results>
<status>accepted</status>
<id>1724128693</id>
<purchaseprice>8.0000</purchaseprice>
<error>false</error>
<messages>
<message>coverage available</message>
</messages>
</results>
Which parses really easily with nokogiri:
doc.results.messages.message.content #coverage available
I want to do something like:
doc.NEWCAR_PINGGX_RESPONSE.DealerList.Dealer.Name.content #returns "Randy's Rides"
To see what's wrong with a document use the errors method. After parsing your XML:
doc.errors
# => [#<Nokogiri::XML::SyntaxError: xmlns: URI www.example.com/ is not absolute>,
# #<Nokogiri::XML::SyntaxError: XML declaration allowed only at the start of the document>,
# #<Nokogiri::XML::SyntaxError: xmlns: URI www.example.com/SellerMessages is not absolute>]
To extract the data I'd use something like this:
doc = Nokogiri::XML(XML)
doc.remove_namespaces!
dealers = doc.search('Dealer').map{ |dealer|
{
buyer_id: dealer.at( 'BUYER_ID' ).text,
reservation_id: dealer.at( 'Reservation_ID' ).text,
name: dealer.at( 'Name' ).text
}
}
dealers
# => [{:buyer_id=>"0000-2127",
# :reservation_id=>
# "1779853194|0000-2067|520a8037-57c8-497e-be4b-f4ea8dfa6c6f|14187-20",
# :name=>"Randy's Rides"},
# {:buyer_id=>"0000-2127",
# :reservation_id=>
# "1779853194|0000-2067|e42fd5c6-0a36-4552-8b6a-ad2decebd0db|14200-10",
# :name=>"Jarrett's New Car Dealership 01"},
# {:buyer_id=>"0000-2127",
# :reservation_id=>
# "1779853194|0000-2067|3fecb591-3a81-49f9-82b3-1f0d7fb3f7a6|14160-20",
# :name=>"Campbell's Crazy Cars"},
# {:buyer_id=>"0000-2127",
# :reservation_id=>
# "1779853194|0000-2067|731b09e9-700b-4f41-8cb0-eaf80e861d76|14158-7",
# :name=>"Demo Dealer 3"}]
Of course you'll want to add/remove/change fields being extracted to fit your use-case.
Using slop mode has its dangers, as stated by the Nokogiri documentation.
Don’t use this.
This may or may not be a backhanded compliment.
No, really, don’t use this. If you use it, don’t report bugs.
You’ve been warned!
I've never used it as a result. Often we don't want to use remove_namespaces! either, but it appears safe in your situation.
Im using Rails 3 to_xml on a Model with a few options like include, except and methods.
So this is not my first time using to_xml.
I'm doing something like this:
to_xml(include: {
order: {
methods: [:my_avg],
except: [:this_attr, :and_this_attr ]
},
customer: {}
})
The XML result:
<?xml version="1.0" encoding="UTF-8"?>
<my-model>
<attr1 type="integer">12</attr1>
<attr2 type="integer">12</attr2>
<order>
<name>foo</name>
<desc>bar</desc>
<my-avg>
<avg type="integer">123</avg>
<foo>ok</foo>
</my-avg>
</order>
<updated-at type="datetime">2014-04-14T11:16:56-03:00</updated-at>
</my-model>
But now I want to change the xml encoding ISO_8859_1 instead of utf8.
I haven't seen an encoding option on ActiveRecord::Serialization module.
If I simply add one encoding option it creates a XML attribute instead of changing the encoding that results on this XML:
<?xml version="1.0" encoding="UTF-8"?>
<my-model>
<attr1 type="integer" encoding="ISO-8859-1">12</attr1>
<attr2 type="integer" encoding="ISO-8859-1">12</attr2>
<order>
<name>foo</name>
<desc>bar</desc>
<my-avg>
<avg type="integer">123</avg>
<foo>ok</foo>
</my-avg>
</order>
<updated-at type="datetime">2014-04-14T11:16:56-03:00</updated-at>
</my-model>
Is there a way to specify the encoding using ActiveRecord's to_xml?
you may override to_xml in your Model & specify encoding. something like this could work:
class ModelName < ActiveRecord::Base
def to_xml(options = {})
require 'builder'
options[:indent] ||= 2
xml = options[:builder] ||= ::Builder::XmlMarkup.new(indent: options[:indent])
xml.instruct! :xml, :version=>"1.0", :encoding => "ISO-8859-1"
xml.level_one do
xml.tag!(:second_level, 'content')
end
end
end
I want to insert the current date/time into my xml feed using Rails Builder.
Here is what I am trying to get:
<?xml version="1.0" encoding="utf-8" ?>
<FirstObject timestamp="2002-06-01T07:00:00">
....
I have:
xml.instruct!
xml.FirstObject
....
What is the command to put in the current date? Thanks!
xml.FirstObject :timestamp => Time.now
I'm using Ruby's XML Builder and trying to find the proper syntax to recreate the following RSS 2.0 declaration:
<rss version="2.0"
xmlns:g="http://base.google.com/ns/1.0">
What's the appropriate way of going about this with XML Builder to put together the above block?
Try this builder script:
xml.rss :version => "2.0", "xmlns:g" => "http://base.google.com/ns/1.0" do
end
This will yield:
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
</rss>