How to parse an XML file with RapidXml
Asked Answered
B

4

21

I have to parse an XML file in C++. I was researching and found the RapidXml library for this.

I have doubts about doc.parse<0>(xml).

Can xml be an .xml file or does it need to be a string or char *?

If I can only use string or char * then I guess I need to read the whole file and store it in a char array and pass the pointer of it to the function?

Is there a way to directly use a file because I would need to change the XML file inside the code also.

If that is not possible in RapidXml then please suggest some other XML libraries in C++.

Thanks!!!

Ashd

Brambling answered 11/5, 2010 at 4:12 Comment(1)
The argument of xml_document::parse() is a zero-terminated string containing the xml. So you just need to create a file2string function. Read the file into a vector<char> buffer and then pass &buffer[0] to parse().Tavey
S
37

RapidXml comes with a class to do this for you, rapidxml::file in the rapidxml_utils.hpp file. Something like:

#include "rapidxml_utils.hpp"

int main() {
    rapidxml::file<> xmlFile("somefile.xml"); // Default template is char
    rapidxml::xml_document<> doc;
    doc.parse<0>(xmlFile.data());
...
}

Note that the xmlFile object now contains all of the data for the XML, which means that once it goes out of scope and is destroyed the doc variable is no longer safely usable. If you call parse inside of a function, you must somehow retain the xmlFile object in memory (global variable, new, etc) so that the doc remains valid.

Slangy answered 25/1, 2013 at 15:3 Comment(3)
I'm new to c++ but where is the function xmlFile() defined at? I can't find it in any of the header files.Karelian
xmlFile is a variable not a function - so this is the definitionSlangy
then why is it taking a parameter? What does that mean in C++Karelian
M
9

New to C++ myself... but I wanted to share a solution.

YMMV!

Shout Out to SiCrane on this thread: -- and just replacing 'string' with a vector --- (thanks anno)

Please comment and help me learn also! I'm very new to this

Anyway, this seems to work for a good start:

#include <iostream>
#include <fstream>
#include <vector>

#include "../../rapidxml/rapidxml.hpp"

using namespace std;

int main(){
   ifstream myfile("sampleconfig.xml");
   rapidxml::xml_document<> doc;

   /* "Read file into vector<char>"  See linked thread above*/
   vector<char> buffer((istreambuf_iterator<char>(myfile)), istreambuf_iterator<char>( ));

   buffer.push_back('\0');

   cout<<&buffer[0]<<endl; /*test the buffer */

   doc.parse<0>(&buffer[0]); 

   cout << "Name of my first node is: " << doc.first_node()->name() << "\n";  /*test the xml_document */


}
Markel answered 15/5, 2011 at 17:18 Comment(1)
This works well, but only if 'vector<char> buffer' does not fall out of scope: a quick and dirty way to solve this is by adding the 'static' keyword to the vector, but I don't think that's really clean. See this: #6364219Markel
R
1

We usually read the XML from the disk into a std::string, then make a safe copy of it into a std::vector<char> as demonstrated below:

string input_xml;
string line;
ifstream in("demo.xml");

// read file into input_xml
while(getline(in,line))
    input_xml += line;

// make a safe-to-modify copy of input_xml
// (you should never modify the contents of an std::string directly)
vector<char> xml_copy(input_xml.begin(), input_xml.end());
xml_copy.push_back('\0');

// only use xml_copy from here on!
xml_document<> doc;
// we are choosing to parse the XML declaration
// parse_no_data_nodes prevents RapidXML from using the somewhat surprising
// behavior of having both values and data nodes, and having data nodes take
// precedence over values when printing
// >>> note that this will skip parsing of CDATA nodes <<<
doc.parse<parse_declaration_node | parse_no_data_nodes>(&xml_copy[0]);

For a complete source code check:

Read a line from xml file using C++

Rodrique answered 14/6, 2011 at 18:50 Comment(1)
This is way too slow due to resizing vector. Compare to Superfly Jon's answer, it is much faster.Diatomaceous
W
0

The manual tells us:

function xml_document::parse

[...] Parses zero-terminated XML string according to given flags.

RapidXML leaves loading the character data from a file to you. Either read the file into a buffer, like anno suggested or alternatively use some memory mapping technique. (But look up parse_non_destructive flag first.)

Wahlstrom answered 13/9, 2010 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.