• Forum
  • Lounge
  • Way to convert a CSV file into an XML do

 
 
Way to convert a CSV file into an XML document

Hi, I have written a parser in C++ few days ago that is capable of parsing a well-formed XML document and also output an excel (csv) file of the XML as well. I would like my tool to be able to convert the csv file into an XML document. What is a good way to do this?

Thanks in advance.
Something like this, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <sstream>

std::vector<std::string> split( const std::string& csv )
{
    boost::tokenizer< boost::escaped_list_separator<char> > tokenizer(csv) ;
    std::vector<std::string> result { tokenizer.begin(), tokenizer.end() } ;
    for( std::string& tok : result ) boost::trim(tok) ;
    return result ;
}

std::string csv_to_xml( const std::string& csv, const std::vector<std::string>& fld_names,
                        const std::string& item_tag = "Line", const std::string& def_fld_tag = "Field" )
{
    std::string result = '<' + item_tag + ">\n" ;

    std::vector<std::string> flds = split(csv) ;

    for( std::size_t i = 0 ; i < flds.size() ; ++i )
    {
        if( !flds[i].empty() )
        {
            const std::string& tag = i < fld_names.size() ? fld_names[i] : def_fld_tag ;
            result += "    <" + tag + '>' + flds[i] + "</" + tag + ">\n" ;
        }
    }

    return result + "</" + item_tag + ">\n" ;
}

std::string csv_to_xml( std::istream& csv_stm, const std::string& item_tag = "Line",
                        bool has_header = true, const std::string& def_fld_tag = "Field" )
{
   std::string xml ;

   std::string line ;

   if(has_header) while( std::getline( csv_stm, line ) && line.empty() ) ;
   const auto fld_names = split(line) ;

   while( std::getline( csv_stm, line ) )
       if( !line.empty() ) xml += csv_to_xml( line, fld_names, item_tag, def_fld_tag ) ;

   return xml ;
}

int main()
{
    std::istringstream csv_stream(
R"(Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL!\nair, moon roof, loaded",4799.00 )" );

   std::cout << "csv:\n----\n" << csv_stream.str() << '\n' ;

   std::cout << "\nxml:\n----\n" << csv_to_xml( csv_stream, "Car" ) << '\n' ;
}

http://coliru.stacked-crooked.com/a/13db351e44127c07

Notes:

1. Uses boost::tokenizer which does all the heavy lifting.

2. Assumes that the csv file conforms to RFC 4180, except that the following two requirements are relaxed:
a. The file must have internet standard (ie. windows-style) line endings.
b. All records should have the same number of fields.

Thank you so much :)
Registered users can post here. Sign in or register to post.