httpステータスコードをチェックしてからXML解析
前回の記事で使ったlibxml2はhttpレスポンスヘッダのステータスコードの取得ができない。
まずCURLでhttpのヘッダ情報と本文を取得して、ヘッダのチェックをしてステータスコードが200なら本文をlibxml2に渡してパースするようにした。
yahoo!掲示板のRSSのitem要素を出力するだけのプログラム
#include <stdio.h> #include <libxml/xpath.h> #include <curl/curl.h> #include <string> const char* REQUEST_API = "http://messages.yahoo.co.jp/bbs?action=4&board=552019556&sid=552019556&tid=kcc08bc0obafb3u"; const char* XPATH_ITEM = "/rss//item/*/text()"; // item以下全てのXPATH int writer(char *data, size_t size, size_t nmemb, std::string *writerData) { if (writerData == NULL) { return 0; } writerData->append(data, size*nmemb); return size * nmemb; } bool getXML(const char* url, std::string& buf) { CURL *handle = curl_easy_init(); CURLcode rc; long statusCode = -1; if (handle) { rc = curl_easy_setopt(handle, CURLOPT_URL, url); if (rc != CURLE_OK) { printf("failed curl_easy_setopt() CURLcode=%d\n", rc); return false; } rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writer); if (rc != CURLE_OK) { printf("failed curl_easy_setopt() CURLcode=%d\n", rc); return false; } rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, &buf); if (rc != CURLE_OK) { printf("failed curl_easy_setopt() CURLcode=%d\n", rc); return false; } rc = curl_easy_perform(handle); if (rc != CURLE_OK) { printf("failed curl_easy_setopt() CURLcode=%d\n", rc); return false; } rc = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &statusCode); if (rc != CURLE_OK) { printf("failed curl_easy_setopt() CURLcode=%d\n", rc); return false; } curl_easy_cleanup(handle); } if (statusCode != 200) { // HTTP response headerのstatus codeをチェック printf("failed HTTP request statusCode=%d\n", statusCode); return false; } return true; } bool parseXML(const char* buf, const char* xpath) { xmlDocPtr doc = xmlParseDoc((xmlChar *)buf); if (doc == NULL) { return false; } xmlXPathContextPtr ctx = xmlXPathNewContext(doc); if (ctx == NULL) { xmlFreeDoc(doc); return false; } xmlXPathObjectPtr xpobj = xmlXPathEvalExpression((xmlChar *)xpath, ctx); if (xpobj == NULL) { xmlXPathFreeContext(ctx); xmlFreeDoc(doc); return false; } xmlNodeSetPtr nodes = xpobj->nodesetval; int size = (nodes) ? nodes->nodeNr : 0; for (int i = 0; i < size; ++i) { if (!xmlXPathNodeSetIsEmpty(nodes)) { xmlNodePtr node = xmlXPathNodeSetItem(nodes, i); if (node->content) { printf("%s => %s\n", node->parent->name, node->content); } else { printf("invalid node\n"); return false; } } } xmlXPathFreeObject(xpobj); xmlXPathFreeContext(ctx); xmlFreeDoc(doc); xmlCleanupParser(); return true; } int main(void) { std::string buf; if (!getXML(REQUEST_API, buf)) { printf("failed get XML\n"); return -1; } if (!parseXML(buf.c_str(), XPATH_ITEM)) { printf("failed parse XML\n"); return -1; } return 0; }