gumbo-parseがどのようにデータを保持しているのかをチェックするためのコード。
タグはenumで区別するため、タグ名は保持していない。<から始まっていることを利用してstd::regexでタグ名を取得している。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
std::string getTagName(std::string str) { // HTMLのタグ名を取得する関数 // タグは< > で囲まれているが、attribute等があるかもしれないので // < スペース 文字列 という構造になっている部分の文字列部分だけを取り出す std::regex tagPattern("<\\s*([^ >]+)\\s*"); std::smatch matches; std::regex_search(str, matches, tagPattern); return matches[1].str(); }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: { // 要素開始位置 const char* tag_start = node->v.element.original_tag.data; // 要素終了位置 const char* tag_end = node->v.element.original_end_tag.data; std::string tagname; // タグ名を抽出 tagname = getTagName(tag_start); std::cout << "tag: '" << tagname << "'" << std::endl; // 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { for (unsigned int i = 0; i < children->length; ++i) { const GumboNode* node = static_cast<GumboNode*>(children->data[i]); myTraceCore(node, src); } } // タグ名を抽出 tagname = getTagName(tag_end); std::cout << "tag: '" << tagname << "'" << std::endl; break; } case GUMBO_NODE_TEXT: // テキストノードの場合 std::cout << "text: '" << node->v.text.text << "'" << std::endl; break; case GUMBO_NODE_WHITESPACE: // 空白ノードの場合 std::cout << "whitespace: '" << node->v.text.text << "'" << std::endl; break; default: std::cout << "others: '" << node->v.text.text << "'" << std::endl; break; } }
void myTrace(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // 自作関数の本体呼び出し myTraceCore(output->root,html.c_str()); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); } int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
tag: 'html' tag: 'head' whitespace: ' ' tag: 'title' text: 'The Title' tag: '/title' whitespace: ' ' tag: '/head' whitespace: ' ' tag: 'body' whitespace: ' ' tag: 'h1' text: 'Test' tag: '/h1' whitespace: ' ' tag: '/body' tag: '/html'
node->typeがGUMBO_NODE_ELEMENTの時は、属性を取得できる。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
// 要素の属性を取得する関数 void myAttributes(const GumboNode* node) { if (node->type != GUMBO_NODE_ELEMENT) { return; } // 要素の属性を取得 const GumboVector* attributes = &node->v.element.attributes; // 属性リストへアクセス for (unsigned int i = 0; i < attributes->length; ++i) { GumboAttribute* attr = (GumboAttribute*)attributes->data[i]; std::cout << " "; std::cout << " " << attr->name << " : " << attr->value << std::endl; } }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: {
/* ... */ myAttributes(node); // 要素の取得
/* ... */ break; } /* ... */ } }
int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title id = "bodyid" style="color:red;">The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
id : bodyid
style : color:red;