HTMLを扱う方法を探している。gumbo-parserはgoogleが公開したApache-2.0 licenseのパーサー。
ソースコードをGitHubからダウンロード・展開する。
https://github.com/google/gumbo-parser
CMake不要。.cファイルをコピーしてプロジェクトに加える。
注意点として、windowsにはstrings.hが存在しない。
追加のインクルードディレクトリ:
visualc/includeにはstrings.hが入っている。
・gumbo-parser-master/src
・gumbo-parser-master/visualc/include
プロジェクトへ追加
src/*.c ファイルをプロジェクトへ追加する。
attribute.c
char_ref.c
error.c
parser.c
string_buffer.c
string_piece.c
tag.c
tokenizer.c
utf8.c
util.c
vector.c
・gumbo_parse関数でパースを行う。
・GumboVectorはGumboNodeの配列となっている。
・node->v.element.children->data から子ノードにアクセスできる
#include <iostream> #include <fstream> #include <sstream> #include <gumbo.h>
std::unique_ptr<std::string> getTitleCore(const GumboNode* node) { // ノードがHTML要素の場合だけ処理 if (node->type == GUMBO_NODE_ELEMENT) { // titleタグの場合 if (node->v.element.tag == GUMBO_TAG_TITLE) {
// 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { // 子要素の先頭を取得 const GumboNode* child = static_cast<GumboNode*>(children->data[0]); if (child->type == GUMBO_NODE_TEXT) { return std::make_unique<std::string>(child->v.text.text); } }
}
// titleタグ以外の場合、このタグの子要素を全て調査。それを再帰的に行う else {
const GumboVector* children = &node->v.element.children; for (unsigned int i = 0; i < children->length; ++i) { std::unique_ptr<std::string> result = getTitleCore(static_cast<GumboNode*>(children->data[i])); if (result != nullptr) { return result; } }
}
} return nullptr; }
std::unique_ptr<std::string> getTitle(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // タイトルを取得する自作関数の本体呼び出し std::unique_ptr<std::string> result = getTitleCore(output->root); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); return result; }
int main() { std::string html = R"( <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; std::unique_ptr<std::string> mytitle = getTitle(html); if (mytitle != nullptr) { std::cout << *mytitle << std::endl; } else { std::cout << "** No title **" << std::endl; } }