I want to read xml lines from an internet url( url will be input) and extract the date value( dd,mm,yyyy) to a string or int. How can I do that using visual c++,mfc in an efficient way ?
The lines available on the web page are as shown below.
thanks.
<location>
<latitude>0</latitude>
<longitude>0</longitude>
</location>
<offset>0</offset>
<suffix>Z</suffix>
<localtime>11 Nov 2013 15:23:58</localtime>
<isotime>2013-11-11 15:23:58 +0000</isotime>
<utctime>2013-11-11 15:23:58</utctime>
<dst>False</dst>
Thank you guys for your all comments. I searched and used cURL library to overcome my issue.Possibly the easiest way with some examples. Also thanks to previous topic, it helped a lot: How do I download xml from the internet in C++
size_t AppendDataToStringCurlCallback(void *ptr, size_t size, size_t nmemb, void *vstring)
{
std::string * pstring = (std::string*)vstring;
pstring->append((char*)ptr, size * nmemb);
return size * nmemb;
}
std::string DownloadUrlAsString(const std::string & url)
{
std::string body;
CURL *curl_handle;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, AppendDataToStringCurlCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &body);
curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
return body;
}
int main(void)
{
CURL *curl;
CURLcode res;
std::string data_to_read;
curl = curl_easy_init();
if(curl) {
//curl_easy_setopt(curl, CURLOPT_URL, "www.earthtools.org/timezone/0/0");
data_to_read=DownloadUrlAsString("www.earthtools.org/timezone/0/0");
res = curl_easy_perform(curl);
// always cleanup
curl_easy_cleanup(curl);
}
std::string str=data_to_read;
std::string str2 ("<utctime>");
std::size_t found = str.find(str2);
if (found!=std::string::npos)
std::cout << "first data found at: " << found << '\n';
//data_to_read[found+9]
char year[4];//="yyyy";
char month[2];//="mm";
char day[2];//="dd";
int delta=0;
int start=found+9;
for (int k=start; k<start+10;k++)
{
if(k<start+4){
year[delta]= data_to_read[k];
delta++;
}
else if (k==start+4)
delta=0;
else if ((k>=start+5) && (k<=start+6))
{
month[delta]=data_to_read[k];
delta++;
}
else if (k==start+7)
delta=0;
else if ((k>=start+8) && (k<=start+9))
{
day[delta]=data_to_read[k];
delta++;
}
}
int year_m=atoi(year);
int month_m=atoi(month);
int day_m=atoi(day);
Use IXMLHTTPRequest object to download the content.
Once downloaded, the object's responseXML property returns IXMLDOMDocument pointer representing the parsed XML document.
Use its selectNodes or selectSingleNode methods to locate the desired node, as represented by IXMLDOMNode interface.
Read its nodeValue property to get the text it contains.
InternetTimeToSystemTime could be used to parse the string like "11 Nov 2013 15:23:58". I can't think, off the top of my head, of a ready-made function to parse an ISO date like "2013-11-11 15:23:58", but it seems amenable to a plain old sscanf.
Related
Scenario:
Im writing a c++ program which should retrieve files and strings from an expressJS API..
Downloading txt.files with curlRequests works perfectly but as soon as i try to retrieve plain strings, they can only be used for printing..
Problem: When trying to do anything with the response from my GET request (from the expressjs api), my response doesnt get treated as a string.
string myText = curlRequest.GetText("/templates/names");
string myTextB = "react.txt, scss.txt"
cout << myText << endl; // prints"react.txt, scss.txt"
cout << myTextB << endl; // prints "react.txt, scss.txt"
cout << stringHelper.GetSubstringPos(myText, "scss") << endl; // printsstring::npos
cout << stringHelper.GetSubstringPos(myTextB, "scss") << endl; // printsposition of 's' as expected
Here is my GetText function of the curlrequest.h in c++
string GetText(string ACTIONURL) {
CURL* curl;
CURLcode curlRes;
string res;
string url = templateCreator.APIURL + ACTIONURL;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curlRes = curl_easy_perform(curl);
res = curlRes;
if (curlRes == CURLE_HTTP_RETURNED_ERROR) {
res = "FAILED";
}
else if (curlRes != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(curlRes));
res = "FAILED";
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return res;
}
Here is the route in expressjs (receiving the request and responding with a string)
router.get('/names', function(req, res, next) {
var str = "react.txt, scss.txt, example.txt";
res.send(str);
});
// I also tried sending a buffer but as its sended as string i face the same problem..
// C++ could decode the buffer ..
router.get('/buf', function(req, res, next) {
let data = 'hello world: (1 + 2 !== 4)';
let buff = new Buffer.from(data);
let base64data = buff.toString('base64');
console.log(base64data);
res.send(base64data);
});
Retrieving textfiles from my expressjs API is not a problem..
void GetFile(string ACTIONURL, string OUTDIR) {
CURL* curl;
FILE* fp;
CURLcode res;
string url = templateCreator.APIURL + ACTIONURL;
curl = curl_easy_init();
if (curl)
{
fopen_s(&fp, OUTDIR.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
return;
}
(After download I can read those line by line and store in a vector).
Still im hoping to get sending actual strings working..
Does anyone have a clue why im facing problems here?
I literally spent days on this unexpected 'small' issue already..
Thank you #n.'pronouns'm.
I Updated my function and realised that res = curlRes was a nobrainer..
Also the checks for valid response is gone for now.
//those 2 lines and a write_to_string function were missing and `res = curlRes` should do their job
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
The following 2 functions replace my GetText function now, and everything works as expected.
size_t write_to_string(void* ptr, size_t size, size_t count, void* stream) {
((string*)stream)->append((char*)ptr, 0, size * count);
return size * count;
}
string GetText(string ACTIONURL) {
CURL* curl;
CURLcode res;
string response;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, templateCreator.APIURL + ACTIONURL.c_str());
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
return response;
}
Thank you! I found the fix on 1 or 2 questions earlier too but was not aware that this was the actual problem. Working with strings is possible now!
I'm trying to load the contents of this URL in order to send an SMS;
https://app2.simpletexting.com/v1/send?token=[api key]&phone=[phone number]&message=Weather%20Alert!
Using this bit of code implementing libcurl:
std::string sendSMS(std::string smsMessage, std::string usrID) {
std::string simplePath = "debugOld/libDoc.txt";
std::string preSmsURL = "https://app2.simpletexting.com/v1/send?token=";
std::cout << "\n" << getFile(simplePath) << "\n";
std::string fullSmsURL = preSmsURL + getFile(simplePath) + "&phone=" + usrID + "&message=" + smsMessage;
std::cout << fullSmsURL;
//Outputs URL contents into a file
CURL *curl;
FILE *fd;
CURLcode res;
char newFile[FILENAME_MAX] = "debugOld/noSuccess.md";
curl = curl_easy_init();
if (curl) {
fd = fopen(newFile, "wb");
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fd);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fd);
}
}
I've used pretty much this exact code before to save the JSON contents of a URL to a file, although I'm trying something a bit different here.
This URL will actually send an SMS when visited. When using curl in a cli, I have no problem doing this. Although from C++, it doesn't treat anything as a error, just perhaps the actual function to send the sms isn't being actuated in the same way it would had I visited the URL physically.
I've scoured google for some kind of a solution to no avail. Perhaps I'm too novice to curl to know exactly what to search for.
Edit #1: getFile function
//Read given file
std::string getFile(std::string path) {
std::string nLine;
std::ifstream file_(path);
if (file_.is_open()) {
while (getline(file_, nLine)) {
return nLine;
}
file_.close();
}
else {
std::cout << "file is not open" << "\n";
return "Error 0x000001: inaccesable file location";
}
return "Unknown error in function 'getFile()'"; //This should never happen
}
This line is wrong:
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL);
CURLOPT_URL expects a char* pointer to null-terminated C string, not a std::string object. You need to use this instead:
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL.c_str());
Also, you are not performing any error checking on the return values of getFile(), fopen(), or curl_easy_perform() at all. So, your code could be failing in any one of those places and you would never know it.
I have a long base64 encoded text string. It's about 1024 characters. From my Objective C code, I want to send it to my PHP script, have it dump it to a log, and return an "OK" response back. I tried this cookbook example, but it only has an example of upload and download (not both combined), and it doesn't even work in my case.
I'd be willing to switch this to a C++ solution if I knew how.
The Objective C Client Code (command line client)
NSString *sMessage = #"My Long Base64 Encoded Message";
NSString *sURL = "http://example.com/request.php";
NSURL *oURL = [NSURL URLWithString:sURL];
NSData *data = [NSData dataWithBytes:sMessage.UTF8String length:sMessage.length];
NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]
dataTaskWithURL:oURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"\n\nDATA\n\n%#",data);
NSLog(#"\n\nRESPONSE\n\n%#",response);
NSLog(#"\n\nERROR\n\n%#",error);
}];
[downloadTask resume];
The PHP Web Server Code
<?php
error_reporting(E_ALL);
ini_set('display_errors','On');
$sRaw = file_get_contents('php://input');
file_put_contents('TEST.TXT',$sRaw);
die('OK');
There's a far easier route using ordinary C++. You'll have to convert your .m file to a .mm file in order to be able to mix Objective C and C++ code.
The PHP code is good and doesn't require a revision. Here's the C++ example I used that worked. It used the STL and curl. I was doing this on a Mac, and by default OSX has the curl libraries pre-installed. Note that the example below is synchronous -- it jams program execution until the server call is completed. (I desired this in my case -- you may not.)
The C++ Client Code (class)
#pragma once
#include <string>
#include <sstream>
#include <iostream>
#include <curl/curl.h>
class Webby {
public:
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) {
std::string buf = std::string(static_cast<char *>(ptr), size * nmemb);
std::stringstream *response = static_cast<std::stringstream *>(stream);
response->write(buf.c_str(), (std::streamsize)buf.size());
return size * nmemb;
}
static std::string sendRawHTTP(std::string sHostURL, std::string &sStringData) {
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
std::stringstream response;
curl_easy_setopt(curl, CURLOPT_URL, sHostURL.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sStringData.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Webby::write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return response.str();
}
return "";
}
}; // end class
I’m writing the program sending POST-requests to the server and getting answers from it. (using curl library) (OS Linux, Red Hat Linux 3.2.2.-5). Sometimes I see , that response from server contains only second part of the message. ( I print _sResponse and sometimes I see full message(more often) and sometimes broken message(only last part of it)).
Class CurlSoapHandler
{
……..
static std::string _sResponse;
static std::string GetResponse() {return _sResponse;}
static size_t write_data(char *ptr, size_t size, size_t count, std::string *buffer)
{
int result = 0;
if (buffer != NULL)
{
std::string tmp_buffer(ptr, size * count);
_sResponse = tmp_buffer;
result = size * count;
}
else
{
std::cout<<"Buffer is not OK!"<<std::endl;
}
return result;
}
};
void CurlSoapHandler::DoRequest(const std::string& sRequest, std::string& sResponse)
{
CURL* _CURL;
CURLcode res;
struct curl_slist *headerlist=NULL;
headerlist = curl_slist_append(headerlist, "Content-Type:text/xml");
curl_global_init(CURL_GLOBAL_ALL);
_CURL = curl_easy_init();
if(_CURL)
{
curl_easy_setopt( _CURL, CURLOPT_URL, ttp://10.10.10.11:8083/Server/Server.asmx);
curl_easy_setopt( _CURL, CURLOPT_USERPWD, "user#password");
curl_easy_setopt( _CURL, CURLOPT_POSTFIELDS, sRequest.c_str());
curl_easy_setopt( _CURL, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt( _CURL, CURLOPT_TIMEOUT, 20);
curl_easy_setopt( _CURL, CURLOPT_WRITEFUNCTION, CurlSoapHandler::write_data);
res = curl_easy_perform(_CURL);
sResponse = GetResponse();
if(res != CURLE_OK)
{
std::cerr<<"CURL message: "<<curl_easy_strerror(res)<<std::endl;
}
curl_easy_cleanup(_CURL);
}
else
{
std::cout<<"Curl initialization problem!"<<std::endl;
}
curl_global_cleanup();
curl_slist_free_all (headerlist);
}
I have no ideas why it occurs. Does someone have ideas? (May be it’s necessary to set some curl options, for example). How can I determine the reason for it and understand if it’s problem of my applications or not. I'd caught traffic using tcpdump utility (I run it on my Virtual Machine (VMWARe)) and saw full message in the dump. So, I think that server sends the correct response. Thanks in advance!
Just replace _sResponse = tmp_buffer; by _sResponse += tmp_buffer; shoulds work.
I would like to dowload some page content of wikitionary. I use curl in a loop. The first iteration is ok but the others give me the same result as the first. What is missing/wrong?. Thank you. This is the loop:
std::string buffer;
size_t curl_write( void *ptr, size_t size, size_t nmemb, void *stream)
{
buffer.append((char*)ptr, size*nmemb);
return size*nmemb;
}
int main(int argc, char **argv)
{
CURL *curl = curl_easy_init();
string data;
data="http://fr.wiktionary.org/w/api.php?format=json&action=query&titles=";
//Page titles are read from local file. The code is not shown to make short.
while ( not_end_of_file){
//list_of_page_title is pages requested for the current iteration.
data=data+list_of_page_title+"prop=revisions&rvprop=content";
curl_easy_setopt(curl, CURLOPT_URL, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write);
curl_easy_perform(curl);
curl_easy_reset(curl);
}
curl_easy_cleanup(curl);
return 0;
}
I am new to curl. May be many things are missed. Thank you for the help.
data=data+list_of_page_title will append the new title onto your previous URL instead of replacing the previous. By the end you'll have a gigantic URL full of garbage. The server is probably paying attention to the first title and ignoring the rest.
And this would be obvious if you just output your URL as the first step of debugging... "Am I requesting what I think I'm requesting?"
One problem is that you are not resetting your buffer variable.
while ( not_end_of_file){
buffer = ""; // reset buffer to empty string
//list_of_page_title is pages requested for the current iteration.
data="http://fr.wiktionary.org/w/api.php?format=json&action=query&titles=" +
list_of_page_title +
"prop=revisions&rvprop=content";
curl_easy_setopt(curl, CURLOPT_URL, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write);
curl_easy_perform(curl);
curl_easy_reset(curl);
}
And as Peter points out your handling of the data variable has a very similar problem.