C xpath表达式中缺少属性的默认值
我正在使用cURL检索一个XML,该XML使用libxml2和xpath进行解析。结果(关键字)填充我的二维数组(myarray)。它工作得很好! 但我得到的XML(基于openweathermap.org的特定城市的当前天气数据)有时会缺少以下属性,具体取决于天气状况: 前 如果天空晴朗,XML如下所示:C xpath表达式中缺少属性的默认值,c,xpath,libxml2,C,Xpath,Libxml2,我正在使用cURL检索一个XML,该XML使用libxml2和xpath进行解析。结果(关键字)填充我的二维数组(myarray)。它工作得很好! 但我得到的XML(基于openweathermap.org的特定城市的当前天气数据)有时会缺少以下属性,具体取决于天气状况: 前 如果天空晴朗,XML如下所示: <current> <city id="4219762" name="Rome"> <coord lon="-85.164673" lat="34.257038
<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>
在第二种情况下,获得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行)。如果某些特定服务器端问题缺少其他节点/属性,则可以应用相同的行为。
是否有办法为缺失的节点/属性指定一个默认值(例如N/a),以便myarray始终获得一致的数据(和行分别获得相同类型的信息)?有人也有同样的问题吗?有解决办法吗?
谢谢你的帮助,
最好的,
乔瓦尼
#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
结构内存结构{
字符*内存;
大小;
};
静态大小\u t WriteMemoryCallback(void*contents、size\u t size、size\u t nmemb、void*userp){
大小\u t realsize=大小*nmemb;
struct MemoryStruct*mem=(struct MemoryStruct*)userp;
mem->memory=realloc(mem->memory,mem->size+realsize+1);
如果(mem->memory==NULL){/*内存不足!*/
printf(“内存不足(realloc返回NULL)\n”);
退出(退出失败);}
memcpy(&(mem->memory[mem->size]),contents,realsize;
mem->size+=realsize;
mem->memory[mem->size]=0;
返回realsize;
}
xmlXPathObjectPtr getnodeset(xmlDocPtr doc,xmlChar*xpath){
XMLXPathContextR上下文;
xmlXPathObjectPtr结果;
context=xmlXPathNewContext(doc);
if(上下文==NULL){
printf(“xmlXPathNewContext中的错误”);
返回NULL;}
结果=XmlXpathValeXpression(xpath,上下文);
xmlXPathFreeContext(上下文);
如果(结果==NULL){
printf(“xmlXPathEvalExpression\n中的错误”);
返回NULL;}
if(xmlXPathNodeSetIsEmpty(结果->nodesetval)){
xmlXPathFreeObject(结果);
printf(“无结果”);
返回NULL;}
返回结果;
}
int xmlretrive(char*myurl,char*myxpath,char***myarray){
卷曲*卷曲柄;
xmlDocPtr文件;
xmlChar*xpath=(xmlChar*)myxpath;
xmlNodeSetPtr节点集;
xmlXPathObjectPtr结果;
int i;
xmlChar*关键字;
结构记忆结构块;
chunk.memory=malloc(1);
chunk.size=0;
curl\u global\u init(curl\u global\u ALL);
curl_handle=curl_easy_init();
curl\u easy\u setopt(curl\u句柄、CURLOPT\u URL、myurl);
curl\u easy\u setopt(curl\u句柄、CURLOPT\u WRITEFUNCTION、WriteMemoryCallback);
curl_easy_setopt(curl_句柄、CURLOPT_WRITEDATA、(void*)和chunk);
curl_easy_setopt(curl_句柄,CURLOPT_用户代理,“libcurl代理/1.0”);
卷曲易于执行(卷曲手柄);
卷曲易于清理(卷曲手柄);
//printf(“%s\n”,chunk.memory);
doc=xmlParseDoc(chunk.memory);
如果(doc==NULL){
fprintf(stderr,“文档未成功解析。\n”);
返回NULL;}
结果=getnodeset(doc,xpath);
如果(结果){
nodeset=result->nodesetval;
*myarray=malloc((nodeset->nodeNr+1)*sizeof(*myarray));
对于(i=0;inodeNr;i++){
关键字=xmlNodeListGetString(doc,nodeset->nodeTab[i]->xmlChildrenNode,1);
(*myarray)[i]=malloc(strlen(关键字)+1);
if((*myarray)[i]==NULL){
//内存不足。打印错误消息,然后退出
}
strcpy((*myarray)[i],关键字);
xmlFree(关键字);
}
xmlXPathFreeObject(结果);
}
xmlFreeDoc(doc);
xmlcleanuparser();
if(chunk.memory)
空闲(块内存);
curl_global_cleanup();
返回i-1;
}
内部主(空){
char-thisxpath[300];
char-thisurl[200];
char**myarray=NULL;
字符输出[900]=“”;
int arr_行;
strcpy(此URL,“http://api.openweathermap.org/data/2.5/weather?q=Rome&mode=xml&units=metric");
strcpy(thisxpath,“//city//*[name()='name'或name()='id'].//country///weather//@value |///temperature//@value |///deposition/*[name()='value'或name()='mode'].//湿度//@value |//速度//*[name()='name()='name'或name()='value']”;
arr_rows=xmlRetve(thisurl、thisxpath和myarray);
//循环打印myarray的一些伟大的布局
免费(myarray);
返回0;
}
如果您使用的是XPath 2.0,则以下构造将起作用:
(/precipitation/@value, "NA")[1]
然而,由于您使用的是libxml2,我相信您会被XPath 1所困扰,而在XPath 1中这是行不通的
在这两种情况下,我都建议采用不同的方法。我将把逻辑放入c代码中,而不是使用一个大型复杂的XPath来选择一组节点,然后假设您关心的节点将以正确的顺序出现一次。循环遍历您感兴趣的节点,并使用特定的XPath为每个节点调用一次getnodeset()
。然后可以研究返回值以确定该值是否存在,并在所需位置将该值或某个占位符插入数组中
我的方法是将单个XPath表达式放入一个数组中并在其上循环;然后简单地使用XPath数组中的索引作为输出数组中的索引;这样,输出值总是在一个可预测的位置,但c代码不需要知道任何关于实际XPath的信息,也不需要知道值的去向。如果您使用的是XPath 2.0,则以下构造将起作用:
(/precipitation/@value, "NA")[1]
然而,由于您使用的是libxml2,我相信您会被XPath 1所困扰,而在XPath 1中这是行不通的
在这两种情况下,我都建议采用不同的方法。而不是使用一个大型复杂的XPath来选择一组节点
(/precipitation/@value, "NA")[1]