[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]
BBSのボードタイトルをカテゴリーと共に2次元vectorとして取得しました。
全てのaタグをnodeのリストとして取得し、aタグのhref、aタグの内容、すぐ上にあるbタグの内容(カテゴリー)の3要素をvectorにプッシュバックしています。bタグがない場合は”XXX”をカテゴリーとします。
2要素の場合はmake_pair関数かmake_tuple関数、3要素以上の場合はmake_tuple関数を使います。make_pairでは変数名.first、変数名.secondでそれぞれ呼び出すことができます。make_tupleの要素はstd::get<番号>(変数名)で取得します。
aタグから遡ってbタグを探す、などややこしめの課題を与えるとChatGPTからまともな答えがほぼ返ってこないのですが、今回は一発正解でした。
int main() {
std::vector<std::tuple<std::string, std::string, std::string>> idTitleCat;
std::string cat;
<中略>
xmlDoc* doc = htmlReadMemory(htmlBuffer.c_str(), htmlBuffer.size(), nullptr, nullptr, HTML_PARSE_RECOVER);
if (doc) {
xmlNodeSetPtr boardObj = executeXpath(doc, (xmlChar *)"//*[name()='a']");
if (boardObj) {
for (int i = 0; i < boardObj->nodeNr; i++) {
xmlNodePtr node = boardObj->nodeTab[i];
xmlChar* id0 = xmlGetProp(node, (xmlChar*)"href");
xmlChar* title0 = xmlNodeGetContent(node);
string id = convertToString(id0);
id.erase(id.size() - 4);
string title = convertToString(title0);
xmlNodePtr catNode = node->prev;
while (catNode != nullptr && xmlStrcmp(catNode->name, (const xmlChar*)"b") != 0) {
catNode = catNode->prev;
}
if (catNode != nullptr) {
xmlChar* cat0 = xmlNodeGetContent(catNode);
cat = convertToString(cat0);
xmlFree(cat0);
} else {
cat = "XXX";
}
idTitleCat.push_back(std::make_tuple(id, title, cat));
xmlFree(id0);
xmlFree(title0);
}
}
xmlFreeDoc(doc);
}
for (const auto& element : idTitleCat) {
std::cout << "id: " << std::get<0>(element) << std::endl;
std::cout << "title: " << std::get<1>(element) << std::endl;
std::cout << "cat: " << std::get<2>(element) << std::endl;
}