Parsing an XML body from a response.

Sep 3, 2015 at 8:18 PM
Hi,

I am trying to parse an XML body from a response using RapidXML but am getting an access violation on parse.

I am not familiar with the way CPP REST uses streams and would appreciate any advice.

Here is my code so far:
                auto t = client.request(request);
                task_status state = t.wait();

                http_response resp = t.get();
                auto body = utility::conversions::to_utf8string(resp.extract_string().get());
                char* cstr = new char[body.size() + 1];
                strcpy(cstr, body.c_str());

                xml_document<> doc;
                doc.parse<0>(cstr);                     // Pass the non-const char* to parse()
Sep 3, 2015 at 10:01 PM
Hi jamesbew

The above code using the http_client looks alright to me, I don't believe it has anything to do with the access violation. I would suggest looking at the string returned, verify if it is indeed a valid XML. You can also look at the "Content-Type" header returned in the http_response::headers() to ensure that the response is indeed an utf8 string.

Some improvements that you can consider doing:
  • It is not required to use both t.wait() and t.get(). A call to get() will wait for the task to finish.
  • get() and wait() will block the execution, consider using task::then() to attach a continuation that will be executed when the response is received.
  • Use the http_response::extract_utf8string() API to obtain a task that will return the utf8string.
Thanks
Kavya
Sep 4, 2015 at 9:56 AM
Hi Kavya,

I updated the code to include your suggestions but now it just trows a "Operation timed out" exception.
Any idea what is going on?
                auto t = client.request(request);
                http_response resp = t.get();
                auto body = resp.extract_utf8string().get();
                char* cstr = new char[body.size() + 1];
                strcpy(cstr, body.c_str());
Sep 4, 2015 at 10:12 AM
Ok so the "operation timed out" exception was being caused by a network issue when trying to monitor localhost with wireshark.

Response is well formed and encoded UTF8.

Still getting an access violation on parse.
Sep 4, 2015 at 10:15 AM
I am trying to integrate my application with MySQL fabric. This is the response from fabric as printed to stdout:
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><array><data>
<value><int>1</int></value>
<value><string>5ca1ab1e-a007-feed-f00d-cab3fe13249e</string></value>
<value><int>1</int></value>
<value><string></string></value>
<value><array><data>
<value><struct>
<member>
<name>info</name>
<value><struct>
<member>
<name>names</name>
<value><array><data>
<value><string>server_uuid</string></value>
<value><string>address</string></value>
<value><string>status</string></value>
<value><string>mode</string></value>
<value><string>weight</string></value>
</data></array></value>
</member>
</struct></value>
</member>
<member>
<name>rows</name>
<value><array><data>
<value><array><data>
<value><string>7454f14c-5182-11e5-a109-bc5ff4f7185d</string></value>
<value><string>127.0.0.1:3308</string></value>
<value><string>SECONDARY</string></value>
<value><string>READ_ONLY</string></value>
<value><double>1.0</double></value>
</data></array></value>
<value><array><data>
<value><string>780116a4-5182-11e5-a109-bc5ff4f7185d</string></value>
<value><string>127.0.0.1:3307</string></value>
<value><string>PRIMARY</string></value>
<value><string>READ_WRITE</string></value>
<value><double>1.0</double></value>
</data></array></value>
</data></array></value>
</member>
</struct></value>
</data></array></value>
</data></array></value>
</param>
</params>
</methodResponse>
Sep 4, 2015 at 12:24 PM
Ok so for anyone looking to use RCP XML or integrate with MySQL fabric, the following code works using CPP REST 2,6 and RapidXML 1.13:
            client::http_client_config client_config;
            client_config.set_credentials(client::credentials(U("admin"), U("fabric")));

            client::http_client client(U("http://localhost:32274"), client_config);


            http_request request(web::http::methods::POST);
            request.set_request_uri(U("/"));
            request.headers().add(header_names::accept, L"text/xml");
            request.set_body(utility::conversions::to_utf8string(U("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><methodCall><methodName>group.lookup_servers</methodName><params><param><value><string>ha</string></value></param></params></methodCall>")));
            request.set_method(web::http::methods::POST);

            try {
                auto t = client.request(request);
                http_response resp = t.get();
                auto body = resp.extract_string().get();
                vector<char> xml_copy(body.begin(), body.end());
                xml_copy.push_back('\0');

                xml_document<> doc;
                try
                {
                    doc.parse<parse_declaration_node | parse_no_data_nodes>(&xml_copy[0]);
                }
                catch (rapidxml::parse_error & err)
                {
                    cout << err.what();
                    return false;
                }
                
                // Who in thier right mind uses XML?
                xml_node<> *node = doc.first_node("methodResponse")->first_node()->first_node()->first_node()->first_node()->first_node()->first_node()\
                    ->next_sibling()->next_sibling()->next_sibling()->next_sibling()->first_node()->first_node()->first_node()->first_node()->first_node("member")\
                    ->next_sibling()->first_node()->next_sibling()->first_node()->first_node("data");
                
                for (xml_node<> *node1 = node->first_node(); node1; node1 = node1->next_sibling())
                {   
                    xml_node<> *node2 = node1->first_node()->first_node()->first_node("value")->next_sibling();

                    cout << "Host address: '" << node2->first_node()->value() << "'\n";
                    cout << "Role: '" << node2->next_sibling()->first_node()->value() << "'\n";
                    cout << "State: '" << node2->next_sibling()->next_sibling()->first_node()->value() << "'\n\n";
                }
            }
            catch (const std::exception& e){
                std::cout << e.what();
            }
Marked as answer by jamesbew on 9/4/2015 at 4:24 AM