In one class, our teacher gave us a project to convert CSV to XML format, and from XML to CSV again, and told us to choose between Python and Ruby. I preferred Ruby as it seemed easier and more understandable to me as a language.
I have done the first part, convert from CSV to XML and it works fine. But when I want to convert from XML to CSV, my code works but only for a specific XML file. I want to make it work for any XML file.
Here is my XML, and I don't put it all because it's big:
<?xml version="1.0"?>
<records>
<company>
<id>p1</id>
<name>Skoda</name>
<price>10000</price>
<stock>4</stock>
<country>Czech Republic</country>
</company>
<company>
<id>p2</id>
<name>Mercedes</name>
<price>50000</price>
<stock>5</stock>
<country>Germany</country>
</company>
<company>
<id>p3</id>
<name>Alfa Romeo</name>
<price>18000</price>
<stock>19</stock>
<country>Italy</country>
</company>
<company>
<id>p4</id>
<name>Fiat</name>
<price>1500</price>
<stock>15000</stock>
<country>Italy</country>
</compa开发者_Python百科ny>
</records>
And my Ruby code for XML to CSV convertion is:
xmlinputfile = gets.chomp
print "\n"
csvoutputfile = gets.chomp
print "\n"
puts "Writing CSV..."
print "\n"
xml_file = File.open(xmlinputfile, "r")
xml = REXML::Document.new( xml_file )
csv_file = File.new(csvoutputfile, "w")
xml.elements.each("records") do |e|
e.elements.each("company") do |f|
csv_file.puts f.elements['id'].text + "," + f.elements['name'].text + ","
+ f.elements['price'].text + "," +
f.elements['stock'].text + ","+ f.elements['country'].text + ","
end
end
print "Job Done !!! \n"
puts "Contents of #{xmlinputfile} were written in CSV format to #{csvoutputfile}.\n\n"
The problem is that this Ruby code will do it's job only for the above XML, and not for any other XML code because I can't find a way to make the code to read by itself the XML tags, and to put their content in CSV format. In this code above, I'm putting myself by hand the XML tags as string argument in
f.elements['xml_tag']
and thus it can take their content and write in CSV format. But that's not good because when I take another XML with many more tags it won't work.
What I want to do is that when I insert the xml input file's name, the code to find itself how many tags are there in the xml and take their content and put in CSV format.
Please it's very important. I have to give this project in 3 days, and I was trying almost for a week and didn't do anything. You guys are my last chance!
require 'nokogiri' # http://nokogiri.org aka gem install nokogiri
xmldoc = Nokogiri::XML(IO.read("records.xml"))
rows = []
xmldoc.xpath('/*/*').each do |row_xml|
row_values = []
rows << row_values
row_xml.xpath('./*').each do |field|
row_values << field.text
end
end
require 'pp'
pp rows
#=> [["p1", "Skoda", "10000", "4", "Czech Republic"],
#=> ["p2", "Mercedes", "50000", "5", "Germany"],
#=> ["p3", "Alfa Romeo", "18000", "19", "Italy"],
#=> ["p4", "Fiat", "1500", "15000", "Italy"]]
Or more tersely, you can get the same results with:
rows = xmldoc.xpath('/*/*').map{ |row| row.xpath('./*').map(&:text) }
If you want the names of the 'columns':
columns = xmldoc.xpath('/*/*[position()=1]/*').map(&:name)
#=> ["id", "name", "price", "stock", "country"]
精彩评论