libxml2 と xpath で解析される XML を cURL で取得しています。結果 (キーワード) が 2D 配列 (myarray) に入力されます。それはうまくいきます!しかし、私が取得した XML (openweathermap.org に基づく指定された都市の現在の気象データ) には、気象条件によっては、属性が欠落している場合があります。
空が澄んでいる場合、XML は次のようになります。
<current>
<city id="4219762" name="Rome">
<coord lon="-85.164673" lat="34.257038"/>
<country>US</country>
<sun rise="2013-06-18T10:28:40" set="2013-06-19T00:55:19"/>
</city>
<temperature value="21.59" min="21" max="22" unit="celsius"/>
<humidity value="88" unit="%"/>
<pressure value="1014" unit="hPa"/>
<wind>
<speed value="1.03" name="Calm"/>
<direction value="87.001" code="E" name="East"/>
</wind>
<clouds value="75" name="broken clouds"/>
<precipitation mode="no"/>
<weather number="701" value="mist" icon="50n"/>
<lastupdate value="2013-06-18T05:35:00"/>
</current>
雨が降っている場合は次のようになります。
//same as above
<precipitation value="0.125" mode="rain" unit="3h"/>
//same as above
問題は、最初のケースで myarray が 9 行になることです。
id: 0 string: 3171168
id: 1 string: Pescara
id: 2 string: IT
id: 3 string: 24.646
id: 4 string: 92
id: 5 string: 5.7
id: 6 string: Moderate breeze
id: 7 string: no
id: 8 string: Sky is Clear
2番目に10行を取得します:
id: 0 string: 3171168
id: 1 string: Pescara
id: 2 string: IT
id: 3 string: 24.646
id: 4 string: 92
id: 5 string: 5.7
id: 6 string: Moderate breeze
id: 7 string: 0.125
id: 8 string: rain
id: 9 string: broken clouds
したがって、メイン関数で myarray を出力すると
printf("Cloudiness:%s",myarray[8]);
空が晴れている場合は正しい値が得られますが、雨が降っている場合は一貫性のないデータが得られます (曇りが 9 行目にあるため)。特定のサーバー側の問題のために他のノード/属性が欠落している場合、同じ動作が適用される可能性があります。myarray が常に一貫したデータを取得する (そして行がそれぞれ同じ種類の情報を取得する) ように、欠落しているノード/属性のデフォルト値(例: N/A)を指定する方法はありますか? 誰かが同じ問題を抱えていましたか?回避策はありますか? 助けてくれてありがとう、ベスト、ジョバンニ。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory == NULL) { /* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
exit(EXIT_FAILURE); }
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
xmlXPathObjectPtr getnodeset (xmlDocPtr doc, xmlChar *xpath) {
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
context = xmlXPathNewContext(doc);
if (context == NULL) {
printf("Error in xmlXPathNewContext\n");
return NULL; }
result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
if (result == NULL) {
printf("Error in xmlXPathEvalExpression\n");
return NULL; }
if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf("No result\n");
return NULL; }
return result;
}
int xmlretrive(char* myurl, char* myxpath, char*** myarray) {
CURL *curl_handle;
xmlDocPtr doc;
xmlChar *xpath = (xmlChar*) myxpath;
xmlNodeSetPtr nodeset;
xmlXPathObjectPtr result;
int i;
xmlChar *keyword;
struct MemoryStruct chunk;
chunk.memory = malloc(1);
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, myurl);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
//printf("%s\n", chunk.memory);
doc = xmlParseDoc(chunk.memory);
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully. \n");
return NULL; }
result = getnodeset (doc, xpath);
if (result) {
nodeset = result->nodesetval;
*myarray = malloc((nodeset->nodeNr + 1) * sizeof(*myarray));
for (i=0; i < nodeset->nodeNr; i++) {
keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
(*myarray)[i] = malloc(strlen(keyword)+1);
if ((*myarray)[i] == NULL) {
// out of memory. print error msg then exit
}
strcpy((*myarray)[i], keyword);
xmlFree(keyword);
}
xmlXPathFreeObject (result);
}
xmlFreeDoc(doc);
xmlCleanupParser();
if(chunk.memory)
free(chunk.memory);
curl_global_cleanup();
return i-1;
}
int main(void) {
char thisxpath[300];
char thisurl[200];
char** myarray = NULL;
char output[900] = "";
int arr_rows;
strcpy (thisurl,"http://api.openweathermap.org/data/2.5/weather?q=Rome&mode=xml&units=metric");
strcpy (thisxpath,"//city/@*[name()='name' or name()='id'] | //country | //weather/@value | //temperature/@value | //precipitation/@*[name()='value' or name()='mode'] | //humidity/@value | //speed/@*[name()='name' or name()='value']");
arr_rows = xmlretrive (thisurl, thisxpath, &myarray);
// for cycle to print myarray with some great layout
free(myarray);
return 0;
}