在C语言中调用SOAP API通常需要借助第三方库来处理HTTP请求和XML解析,因为C语言本身并没有内置对SOAP协议的直接支持,以下是详细的步骤和示例代码,帮助你在C语言中调用SOAP API:
1、准备工作
安装必要的库:确保你的开发环境中安装了libcurl(用于HTTP请求)和libxml2(用于解析XML),在Ubuntu系统中,可以使用以下命令安装这些库:
sudo apt-get install libcurl4-openssl-dev libxml2-dev
2、创建SOAP请求
SOAP请求是一个XML格式的字符串,包含了调用的Web服务方法和所需的参数,以下是一个调用名为GetWeather
的方法的SOAP请求示例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET"> <soapenv:Header/> <soapenv:Body> <web:GetWeather> <web:CityName>New York</web:CityName> <web:CountryName>United States</web:CountryName> </web:GetWeather> </soapenv:Body> </soapenv:Envelope>
在C语言中,你可以将这个XML字符串存储在一个字符数组中:
const char *soapRequest = "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">" "<soapenv:Header/>" "<soapenv:Body>" "<web:GetWeather>" "<web:CityName>New York</web:CityName>" "<web:CountryName>United States</web:CountryName>" "</web:GetWeather>" "</soapenv:Body>" "</soapenv:Envelope>";
3、发送SOAP请求
使用libcurl库发送HTTP请求,将SOAP请求发送到Web服务的URL,以下是一个使用libcurl发送HTTP POST请求的示例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> const char *soapRequest = "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">" "<soapenv:Header/>" "<soapenv:Body>" "<web:GetWeather>" "<web:CityName>New York</web:CityName>" "<web:CountryName>United States</web:CountryName>" "</web:GetWeather>" "</soapenv:Body>" "</soapenv:Envelope>"; 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; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if(ptr == NULL) { printf("not enough memory (realloc returned NULL) "); return 0; } mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } int main(void) { CURL *curl; CURLcode res; struct MemoryStruct chunk; chunk.memory = malloc(1); // 分配初始内存 chunk.size = 0; // 初始化大小为0 curl_global_init(CURL_GLOBAL_ALL); // 初始化libcurl curl = curl_easy_init(); // 初始化CURL对象 if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://www.webservicex.net/globalweather.asmx"); // 设置目标URL curl_easy_setopt(curl, CURLOPT_POSTFIELDS, soapRequest); // 设置POST数据为SOAP请求 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // 设置回调函数处理响应数据 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // 设置回调函数的用户数据指针 // 如果需要,可以添加额外的HTTP头,例如Content-Type struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: text/xml; charset=utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 设置HTTP头 res = curl_easy_perform(curl); // 执行请求 if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s ", curl_easy_strerror(res)); } else { printf("%lu bytes retrieved ", (unsigned long)chunk.size); printf("Response: %s ", chunk.memory); // 打印响应数据 } curl_slist_free_all(headers); // 释放HTTP头列表 curl_easy_cleanup(curl); // 清理CURL对象 } free(chunk.memory); // 释放内存 curl_global_cleanup(); // 清理libcurl全局数据 return 0; }
上述代码中,首先定义了一个MemoryStruct
结构体来存储响应数据,使用curl_easy_setopt
函数设置了请求的URL、POST数据、回调函数等选项,通过curl_easy_perform
函数发送请求并获取响应。
4、解析响应
接收到的响应是一个XML格式的字符串,需要将其解析成可用的C语言结构,这通常需要使用XML解析库,如libxml2,以下是一个使用libxml2解析XML响应的简单示例:
#include <libxml/parser.h> #include <libxml/tree.h> #include <stdio.h> #include <string.h> void parseXmlResponse(const char *response) { xmlDocPtr doc; // 定义文档指针 xmlNode *root_element = NULL; // 解析XML文档 doc = xmlReadMemory(response, strlen(response), "noname.xml", NULL, 0); if (doc == NULL) { fprintf(stderr, "Failed to parse document "); return; } // 获取根元素节点 root_element = xmlDocGetRootElement(doc); for (xmlNode *node = root_element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (const xmlChar *)"GetWeatherResult")) { xmlChar *weatherText = xmlNodeGetContent(node); printf("Weather: %s ", weatherText); xmlFree(weatherText); } } // 清理文档树 xmlFreeDoc(doc); // 清理全局变量 xmlCleanupParser(); }
上述代码中,首先使用xmlReadMemory
函数将响应字符串解析成一个XML文档对象,遍历文档的子节点,找到名为GetWeatherResult
的元素节点,并获取其内容,释放文档对象和全局变量。
5、完整示例
将上述发送请求和解析响应的代码结合起来,就可以实现一个完整的在C语言中调用SOAP API的示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> #include <libxml/parser.h> #include <libxml/tree.h> const char *soapRequest = "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">" "<soapenv:Header/>" "<soapenv:Body>" "<web:GetWeather>" "<web:CityName>New York</web:CityName>" "<web:CountryName>United States</web:CountryName>" "</web:GetWeather>" "</soapenv:Body>" "</soapenv:Envelope>"; 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; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if(ptr == NULL) { printf("not enough memory (realloc returned NULL) "); return 0; } mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } void parseXmlResponse(const char *response) { xmlDocPtr doc; // 定义文档指针 xmlNode *root_element = NULL; // 解析XML文档 doc = xmlReadMemory(response, strlen(response), "noname.xml", NULL, 0); if (doc == NULL) { fprintf(stderr, "Failed to parse document "); return; } // 获取根元素节点 root_element = xmlDocGetRootElement(doc); for (xmlNode *node = root_element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (const xmlChar *)"GetWeatherResult")) { xmlChar *weatherText = xmlNodeGetContent(node); printf("Weather: %s ", weatherText); xmlFree(weatherText); } } // 清理文档树 xmlFreeDoc(doc); // 清理全局变量 xmlCleanupParser(); } int main(void) { CURL *curl; CURLcode res; struct MemoryStruct chunk; chunk.memory = malloc(1); // 分配初始内存 chunk.size = 0; // 初始化大小为0 curl_global_init(CURL_GLOBAL_ALL); // 初始化libcurl curl = curl_easy_init(); // 初始化CURL对象 if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://www.webservicex.net/globalweather.asmx"); // 设置目标URL curl_easy_setopt(curl, CURLOPT_POSTFIELDS, soapRequest); // 设置POST数据为SOAP请求 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // 设置回调函数处理响应数据 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // 设置回调函数的用户数据指针 // 如果需要,可以添加额外的HTTP头,例如Content-Type struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: text/xml; charset=utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 设置HTTP头 res = curl_easy_perform(curl); // 执行请求 if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s ", curl_easy_strerror(res)); } else { printf("%lu bytes retrieved ", (unsigned long)chunk.size); parseXmlResponse(chunk.memory); // 解析响应数据 } curl_slist_free_all(headers); // 释放HTTP头列表 curl_easy_cleanup(curl); // 清理CURL对象 } free(chunk.memory); // 释放内存 curl_global_cleanup(); // 清理libcurl全局数据 return 0; }