I want to read the suffix column of the table that I see at http://finance.yahoo.com/exchanges.
I read the page with QNetworkManager. storing data in QNetworkReply *reply. If I read all the page with reply->readAll() I obtain the page, so it's retrieved correctly. I set it inside a QWebPage and then I want to retrieve all tables that are inside.
In order to obtain the table I want to use QWebElement but I'm not be able to read it. I read all tables at the same level of the one that I want but the QWebElementCollection that I obtain is empty.
What I'm doing wrong and that I must do in order to read the table?
void getMarketListFromReply(QNetworkReply *reply) {
std::cout << "Reading page" << std::endl;
const QString html(reply->readAll()); // html contain the code
QWebPage page;
std::cout << "Setting page." << std::endl;
page.mainFrame()->setHtml(html);
std::cout << "Retrieving tables" << std::endl;
QWebElementCollection tables = page.mainFrame()->documentElement().findAll("html body div.screen div.content table");
const int size = tables.count(); // size it's 0 :-(
std::cout << "size: " << size << std::endl;
for (int i = 0; i < size; i++) {
std::cout << i << ": " << tables.at(i).toPlainText().toStdString() << std::endl;
}
}
Dot in findAll() selector denotes tag class. However, in your case "screen" and "content" are element ids that can be selected by sharp (#). So, the following selectors should work
.findAll("html body div#screen div#content table");
.findAll("#content table");
Related
I'm trying to build a program that can register a user to the database (still learning cpp, I hope that in the near future I'll be able to work with database).
What I'm trying to do with this code is to check whether an index of array is empty for the user to store an ID in it. If it isn't empty, I want the program to keep looking for an empty index of array, for the new info to be stored in.
Here is the code:
void registro() {
std::string userid[3];
userid[0] = "Houkros"; // eventually I'll try to have this being read from a file or server database..
std::string userpass[3];
std::string usermail[3];
std::string userkey[3];
std::string getUid[3];
std::string getUpass[3];
std::string getUmail[3];
std::string getUkey[3];
std::cout << std::endl << " >>>> REGISTRATION <<<< " << std::endl;
std::cout << " =============================================== " << std::endl;
std::cout << std::endl;
std::cout << "Please, enter the desired user id: " << std::flush;
if (userid[0].empty())
{
std::cin >> userid[0];
}
else {
std::cin >> userid[1];
}
for (int i = 0; i < 2; i++)
{
std::cout << " Element of array: " << i << " is > " << userid[i] << std::endl;
}
Please consider the following definitions for an "empty" array element:
a) not initialised (unhelpful, cannot be checked)
b) never yet written to (same as a) )
c) contains "" (possible, but means that "" must not be accepted as an actual content)
d) is empty according to a second array in which that info is maintained (this is what I almost recommend)
e) contains a struct with a string and a maintained "empty" flag (this I recommend)
Whatever you do, make sure that you init all variables and array elements before first read-accessing them; i.e. in all cases first write something meaningful to it.
SQLiteCpp is a open sourced library for operating sqlite database. Here's an example.
try
{
// Open a database file
SQLite::Database db("example.db3");
// Compile a SQL query, containing one parameter (index 1)
SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");
// Bind the integer value 6 to the first parameter of the SQL query
query.bind(1, 6);
// Loop to execute the query step by step, to get rows of result
while (query.executeStep())
{
// Demonstrate how to get some typed column value
int id = query.getColumn(0);
const char* value = query.getColumn(1);
int size = query.getColumn(2);
std::cout << "row: " << id << ", " << value << ", " << size << std::endl;
}
}
catch (std::exception& e)
{
std::cout << "exception: " << e.what() << std::endl;
}
Since the query is passed in the constructor of Statement SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");, how do I reuse it?
I didn't see a method accepts a string like query.setQuery("select * from table"). Do you know how do I reuse it?
If it bothers you that much you can just reassign it:
query = SQLite::Statement{db, "select * from table"};
I have yahoo finance json file from which I want to isolate Date,Close and volume from the quote list and save it in the same order with a comma separtion in a single text file. This is my json script.
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
bool parsingSuccessful = reader.parse( YahooJson, root );
if(not parsingSuccessful)
{
// Report failures and their locations
// in the document.
std::cout<<"Failed to parse JSON"<<std::endl
<<reader.getFormatedErrorMessages()
<<std::endl;
return 1;
}else{
std::cout<<"\nSucess parsing json\n"<<std::endl;
std::cout << root<< std::endl;
std::cout <<"No of Days = "<< root["query"]["count"].asInt() << std::endl;
//below for loop returns an error
for (auto itr : root["query"]["result"]["quote"]) {
std::string val = itr.asString();
}
}
I was able to succed in fetching the json values and print root["query"]["count"].asInt() but when I go to the list values(quote) I dont know how to iterate through quote (query->result->quote) to get Date,close and volume values?
EDIT
Also tried this method
const Json::Value& quotes = root["query"]["results"]["quote"];
for (int i = 0; i < quotes.size(); i++){
std::cout << " Date: " << quotes[i]["Date"].asString();
std::cout << " Close: " << quotes[i]["Close"].asFloat();
std::cout << " Volume: " << quotes[i]["Volume"].asFloat();
std::cout << std::endl;
}
It works only when output was Date. For close and volume output it exits with a runtime error message and also this error
what() type is not convertible to string
You haven't specified which JSON library you are using, and I don't know the Yahoo finance data well enough to know the exact field names, but if you are using the JsonCpp library, which has documentation here, and you are asking about how to iterate over a JSON array, then one way to do it using iterators would look something like this
const Json::Value quote = root["query"]["results"]["quote"];
for (Json::ValueConstIterator itr = quote.begin(); itr != quote.end(); ++itr)
{
const Json::Value date = (*itr)["Date"];
const Json::Value close = (*itr)["Close"];
const Json::Value volume = (*itr)["Volume"];
std::cout << "Date: " << date.asString() << std::endl;
std::cout << "Close: " << close.asString() << std::endl;
std::cout << "Volume: " << volume.asString() << std::endl;
}
I have 2 QCheckbox tables, each contains 11 elements.
I declare them as following in my class :
QCheckBox *sectionTable[10];
QCheckBox *postTable[10];
For each QCheckBox, I do this
QCheckBox* checkboxA = new QCheckBox("A");
sectionTable[0] = checkboxA;
Through my test method, I would like to return the content of each element of my QCheckbox tables.
To do so, I've done this test :
/** TEST() **/
void VGCCC::test()
{
sectionTable[0]->setText("A");
sectionTable[1]->setText("B");
sectionTable[2]->setText("C");
sectionTable[3]->setText("D");
postTable[0]->setText("E");
postTable[1]->setText("F");
postTable[2]->setText("G");
postTable[3]->setText("H");
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
}
My application is compiling, and also running. But when I call the test function, my application crash.
How can we explain this problem ?
I would like to notify that I get a result in my console. It seems my test is half working, but is crashing at the end of the 1st do/while loop, when I get out of my condition.
With regard to the 11 elements: QCheckBox *sectionTable[10]; defines only 10 slots (0 through 9) for elements.
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
Has the potential to reach past ten or eleven elements. Unless the terminating condition is found earlier, there is nothing to stop sectionTable[i] from trying to read sectionTable[11] to call its text method. If it manages to survive the call to the out-of-range sectionTable[11]->text(), it will then try calling sectionTable[11]->text().isNull(). Possibly this will be survivable as well and not be NULL. In this case sectionTable[12] will be tested. This will continue until the program hits really bad memory and crashes, a null is found, or pigs become the terror of the airways we all know they truly wish to be.
Note that i is not set back to 0 after this loop, so the first postTable to be inspected in the next loop will be at the same index as the last sectionTable.
So if sectionTable[5]->text().isNull() was NULL, postTable[5] will be the first postTable indexed and inspected.
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
This loop has the same error in the exit condition as the sectionTable loop.
I find out how to solve the problem. As said in the answer before (#user4581301), I didn't set back my iterator i to 0.
Also, to avoid the "out of range" crash, I put a second condition which is i<sizeof(sectionTable[i]);
This is my fonctional test function :
/** TEST() **/
void VGCCC::test()
{
int i = 0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << m_materialMap[sectionTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull() && i<sizeof(sectionTable[i]));
i = 0;
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
std::cout << "POST TABLE " << m_materialMap[postTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty() && i<sizeof(postTable[i]));
}
I have a subclass of QTableWidget with the following code:
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(pushCellChange(int, int)), Qt::QueuedConnection);
...
void MyTableView::pushCellChange(int row, int column)
{
QString text(item(row, column)->text());
QByteArray data = text.toAscii();
cout << data.length() << endl;
const char* cellData = text.toAscii().constData();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
}
When I change the upper-right cell to anything this outputs:
2
Cell (0, 0) changed to: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌░▬∟C▌▌
However, while this corrupt data is spewed out on the console, the table widget itself seems to behave normally and shows the correct string. Does anyone know what is going on here?
The call toAscii() is storing the QString's data to a QByteArray. In your code, you do this twice:
QByteArray data = text.toAscii();
const char* cellData = text.toAscii().constData();
_____________^ <-- temporary QByteArray
The const char* is actually pointing to the data within a temporary variable, which goes out of scope at the semicolon, at which point the pointer becomes invalid. If instead you were to make use of the local variable data, you'd be OK:
const char* cellData = data.constData();
___^ <-- still-in-scope QByteArray
Alternatively, you can do this all in-line with the cout and the data will still be valid when it is copied to the output stream:
cout << "Cell ("<<row<<","<<column<<") changed to: " << text.toAscii().constData() << endl;
std::string cellData = text.ToStdString();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
That should work fine. As for why toAscii doesn't work, I have no clue.
If it's just about the console output, you could also use qDebug() (available after #include <QDebug>) and pass the QString directly:
void MyTableView::pushCellChange(int row, int column)
{
qDebug() << item(row, column)->text().length();
qDebug() << "Cell (" << row << ", " << column << ") changed to: "
<< item(row, column)->text();
}
This way, you don't have to mess with data conversion …