DeliciousFS を作ってみる - libxml2 を使ってみる

DeliciousFS を作ってみる - curl で早速こける」の続きです。

会社で、C++ で XML 扱うときってみんなどうしてんのと聞いてみたら、expat とか xerces-c とか libxml2 とかでゴリゴリやるんじゃないですかねってことだったので、しょうがねえからやってみます。

curl はこの間インストールしたので、今回は libxml2 を追加。

CODE:
  1. [ihara@barcelona.local:~/work] $ sudo port install -dv libxml2

こんな感じですか。test.cc。

C++:
  1. #include <string>
  2. #include <iostream>
  3. #include <libxml/parser.h>
  4. #include <libxml/tree.h>
  5. #include <curl/curl.h>
  6. #include <curl/easy.h>
  7.  
  8. using namespace std;
  9.  
  10. struct memchunk {
  11.     char* memory;
  12.     size_t size;
  13. };
  14.                                                                                                                                                                    
  15. void* myrealloc(void* ptr, size_t size) {
  16.     if (ptr) {
  17.         return realloc(ptr, size);
  18.     } else {
  19.         return malloc(size);
  20.     }
  21. }
  22.  
  23. size_t writeMemoryCallback(void* ptr, size_t size, size_t nmemb, void* data) {
  24.     size_t realsize = size * nmemb;
  25.     struct memchunk* mem = (struct memchunk*)data;
  26.     mem->memory = static_cast<char*>(myrealloc(mem->memory, mem->size + realsize + 1));
  27.     if (mem->memory) {
  28.         memcpy(&(mem->memory[mem->size]), ptr, realsize);
  29.         mem->size += realsize;
  30.         mem->memory[mem->size] = 0;
  31.     }
  32.     return realsize;
  33. }
  34.  
  35. void parse(xmlNode* a_node) {
  36.     xmlNode* cur_node = NULL;
  37.     for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
  38.         if (cur_node->type == XML_ELEMENT_NODE) {                                                                                                                 
  39.             string cur_node_name = reinterpret_cast<const char*>(cur_node->name);
  40.             if (cur_node_name == "tags") {                                                                                                                         
  41.                 // やることなし
  42.             } else if (cur_node_name == "tag") {
  43.                 // タグの名前とカウントを出力
  44.                 cout <<reinterpret_cast<const char*>(xmlGetProp(cur_node, reinterpret_cast<const xmlChar*>("count")))
  45.                      <<" : "
  46.                      <<reinterpret_cast<const char*>(xmlGetProp(cur_node, reinterpret_cast<const xmlChar*>("tag")))
  47.                      <<endl;
  48.             }
  49.         }
  50.         parse(cur_node->children);
  51.     }
  52. }
  53.  
  54. int main(void) {
  55.     CURL* curl = curl_easy_init();
  56.     if (curl == NULL) {
  57.         exit(1);
  58.     }
  59.     CURLcode code = curl_easy_setopt(curl, CURLOPT_URL, "https://api.del.icio.us/v1/tags/get");
  60.     if (code != CURLE_OK) {
  61.         exit(1);
  62.     }
  63.     code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeMemoryCallback);
  64.     if (code != CURLE_OK) {
  65.         exit(1);
  66.     }
  67.     // データの書き込み先を設定
  68.     struct memchunk chunk;
  69.     memset(&chunk, 0, sizeof(memchunk));
  70.     code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(&chunk));                                                                                 
  71.     if (code != CURLE_OK) {
  72.         exit(1);
  73.     }
  74.     // ユーザ名、パスワードを設定
  75.     code = curl_easy_setopt(curl, CURLOPT_USERPWD, "YOUR_ID:YOUR_PASSWORD");                                                                                         
  76.     if (code != CURLE_OK) {
  77.         exit(1);
  78.     }
  79.     // 実行
  80.     code = curl_easy_perform(curl);
  81.     if (code != CURLE_OK) {
  82.         exit(1);
  83.     }
  84.  
  85.     LIBXML_TEST_VERSION
  86.     xmlDocPtr doc = xmlReadMemory(chunk.memory, chunk.size, NULL, NULL, 0);
  87.     if (doc == NULL) {
  88.         cerr <<"failed to parse document" <<endl;
  89.         exit(1);
  90.     }
  91.     xmlNode* root_element = xmlDocGetRootElement(doc);
  92.     parse(root_element);
  93.     xmlFreeDoc(doc);
  94.     xmlCleanupParser();
  95.     xmlMemoryDump();
  96.  
  97.     // 後始末
  98.     curl_easy_cleanup(curl);
  99.     if (chunk.memory) {
  100.         free(chunk.memory);
  101.     }
  102.  
  103.     return 0;
  104. }

でコンパイル。

CODE:
  1. [ihara@barcelona.local:~/work] $ g++ -I/opt/local/include -I/opt/local/include/libxml2 -L/opt/local/lib -lcurl -lxml2 test.cc -o test

で、./test で実行するとカウント : タグの名前って感じで出力されました。

ムー、なんかこう、XML 渡すとオブジェクトの階層だったり名前と配列のハッシュだったりが返ってきてくれたら超楽なんですが。PHP の SimpleXML の実装見ても libxml2 で頑張ってやってるみたいなので、こんな感じなんですかね。


About this entry