0xA 换行 /n LF
0xD 回车 /r CR
0x9 tab /t HT
0x3C <
0x3D =
0x3E >
0x2F /
再给出几个常用的宏,便于构建XML.在C下
#define x_EOL "/r/n" // can be /r/n or /n or empty #define x_EOLLEN (sizeof(x_EOL)-1); // string length of x_EOL #define x_ATTRIB "/"" // it is also can be ' #define x_TABLE "/t" #define x_SLASH "/" #define x_BACK_SLASH "//" #define x_LEFT "<" #define x_RIGHT ">"
如果要创建如下的报文,应该如何做呢?
/*
*/
其实这样的报文是不好的,因为XML标准本身推荐使用元素和属性的方式,而不是在元素后面将所有的属性全部跟上,后面的是比较好的格式
Bob Dylan
USA
Columbia
10.90
1985
Bonnie Tyler
UK
CBS Records
9.90
1988
类似于这样的格式就是好的格式,但是既然人家规定了就用上面的格式来写,那就没有办法了,将我VC下编译过的函数给共享一下吧,其中有创建和检索属性,可能有些不太直观,不分步调试的话就很难一下全部看懂,呵呵,不过注释丰富
test.h文件内容:
#ifndef __TEST_H__ #define __TEST_H__ //Author:scarlettsp #include #include #include #include #define x_EOL "/r/n" // can be /r/n or /n or empty #define x_EOLLEN (sizeof(x_EOL)-1); // string length of x_EOL #define x_ATTRIB "/"" // it is also can be ' #define x_TABLE "/t" #define x_SLASH "/" #define x_BACK_SLASH "//" #define x_LEFT "<" #define x_RIGHT ">" #define x_HEAD " " #define x_HEAD_LENGTH sizeof(x_HEAD) #define x_set_head(xmlbody) strcat(xmlbody, "<") #define x_set_head_ex(xmlbody) strcat(xmlbody, "") #define x_set_trail(xmlbody) strcat(xmlbody, ">") #define x_set_trail_ex(xmlbody) strcat(xmlbody, "/>") #define x_set_space(xmlbody) strcat(xmlbody, " ") #define x_set_N(xmlbody) strcat(xmlbody, x_EOL) #define x_set_T(xmlbody) strcat(xmlbody, x_TABLE) #define x_set_NT(xmlbody) strcat(xmlbody, x_EOL);strcat(xmlbody, x_TABLE) #define x_set_NTT(xmlbody) strcat(xmlbody, x_EOL);strcat(xmlbody, x_TABLE);strcat(xmlbody, x_TABLE) int get_attrib_value(char *pParse, char *dst); int isNumber(char *string); /* */ #endif//__TEST_H__
test.cpp 的内容是:
// test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "test.h" //craet a void x_set_element(char *buf, const char *element) { //strcat(buf, x_EOL); x_set_head(buf); strcat(buf, element); x_set_trail(buf); } //craet a void x_set_element_begin(char *buf, const char *element) { //strcat(buf, x_EOL); x_set_head(buf); strcat(buf, element); } //craet a void x_set_element_end(char *buf, const char *element) { //strcat(buf, x_EOL); x_set_head_ex(buf); strcat(buf, element); x_set_trail(buf); } void x_set_n_tab(char *buf, int nCount) { for(; nCount > 0; nCount--) { strcat(buf, x_TABLE); } } void x_set_attrib_string(char *xmlbody, const char* szAttrib, const char* szValue) { strcat(xmlbody, " "); strcat(xmlbody, szAttrib); strcat(xmlbody, "="); strcat(xmlbody, x_ATTRIB); strcat(xmlbody, szValue); strcat(xmlbody, x_ATTRIB); } void x_set_attrib_number(char *xmlbody, const char* szAttrib, const int nVal) { char tmp[32]; strcat(xmlbody, " "); strcat(xmlbody, szAttrib); strcat(xmlbody, "="); strcat(xmlbody, x_ATTRIB); sprintf(tmp, "%d", nVal); strcat(xmlbody, tmp); strcat(xmlbody, x_ATTRIB); } void x_creat_header(char *buf) { memcpy(buf, x_HEAD, sizeof(x_HEAD)); } void x_creat_login(char *buf, const char *szHost_id, const int nSerial) { int nChannel; char tmp[32]; x_creat_header(buf); strcat(buf, x_EOL); x_set_head(buf); strcat(buf, "Login"); x_set_attrib_string(buf, "HostID", szHost_id); x_set_attrib_number(buf, "SerialNumber", nSerial); x_set_attrib_number(buf, "ChannelCount", CHANNEL_COUNT); x_set_attrib_number(buf, "AlarmInputCount", ALARM_IN_COUNT); x_set_attrib_number(buf, "AlarmOutCount", ALARM_OUT_COUNT); x_set_trail(buf); strcat(buf, x_EOL); strcat(buf, x_TABLE); x_set_element(buf, "Channel"); for (nChannel = 0; nChannel < CHANNEL_COUNT; nChannel++) { strcat(buf, x_EOL); strcat(buf, x_TABLE); strcat(buf, x_TABLE); sprintf(tmp, "device%d", nChannel); x_set_head(buf); strcat(buf, "Item"); x_set_attrib_string(buf, "Name", "device"); x_set_attrib_number(buf, "Value", nChannel); x_set_trail_ex(buf); } strcat(buf, x_EOL); strcat(buf, x_TABLE); x_set_element_end(buf, "Channel"); strcat(buf, x_EOL); x_set_element_end(buf, "Login"); } // // void x_creat_ptz_info(char *buf, /*const int nCmd*/ char *pcmd, const int nSelect, const int nSpeed, const int nPreSet) { strcat(buf, x_EOL); x_set_head(buf); strcat(buf, "DecodeControl"); x_set_attrib_string(buf, "DecodeCmd", pcmd); x_set_attrib_number(buf, "Open", nSelect); x_set_attrib_number(buf, "Speed", nSpeed); x_set_attrib_number(buf, "PresetNum", nPreSet); x_set_trail_ex(buf); //printf(">>>>>>[%s]/n", buf); } //返回值:0:在xml中有target这个元素;-1:没有这个元素 //xml:要被解析的数据;在xml要查找的元素;res在xml中target的位置 //规定:只有左边是<,紧接着是target的才认为是xml里面有target这个元素; //至于后面是>还是有别的属性的话是后面函数处理的. int find_element(const char* xml, char* target, char** res) { int nRet; const char* pTmp = xml + x_HEAD_LENGTH; char* pLeft; while((pLeft = strstr(pTmp, x_LEFT)) != NULL) { if (pLeft != NULL) { printf("has </n"); pLeft++; nRet = memcmp(pLeft, target, strlen(target)); if (nRet == 0)//有< 并且是 { *res = pLeft; return 0; } else { printf("not find/n"); pLeft += strlen(target); pTmp = pLeft; //Sleep(100); continue; } } else { res = NULL; return -1; } } res = NULL; return -1; } //对xml内容为: 的解析而言. //在元素element的部分查找属性attrib的值(可能为数字,可能为string) //算法: //1.在xml中查找是否有element这个元素; //2.如果有的话看 还是空格,如果是空格则认为有属性值; //3.首先找到遍历的右限.之后遍历从发现 之间的内存 //4.找到 attrib="some" 的部分 //5.之后将指针指在 some 的位置,但是后面还是跟着xml中剩余的字符 //关于返回值:res指向的是属性some的地址,有效的some值是 " 之前的部分 //返回0表示含有这个属性 //如果没有这个属性,那么返回-1 //如果属性是数字的话返回数字(大于等于0的值),如果数字不合法的话(如含有字符等),返回-2 int find_attrib(const char* xml, char *element, char *attrib, char **res) { int nRet; int nRes; //char szAttrib[nLen] = {0}; char *pAttrib; char *pLocate = NULL;//指针遍历的左限 char *pRightBound = NULL;//指针遍历的右限 char *pTmp;//用于遍历的临时变量 //指针的遍历是从发现 或者是 ) // /> 这种形式用于同行的时候, 用于元素还有子元素,跨行的时候. //其实 是 的简化形式 nRet = find_element(xml, element, &pLocate);//1 if (nRet == -1) { printf("There no element in xml/n"); } else//现在只是有 或者是 这样的形式 { pLocate += strlen(element); if (*pLocate == '>') { printf("It is only a element, don't have attrib/n"); } else if (*pLocate == ' ')//2 { printf("element has attrib/n"); pRightBound = strstr(pLocate, ">"); //printf("find_attrib locate(%p) right bound(%p)/n", pLocate, pRightBound); if (pRightBound == NULL) { printf("xml is broken/n"); } else//3 { pTmp = pLocate; pTmp = strstr(pLocate, attrib); if (pTmp == NULL) { printf("element(%s) has no attrib(%s)/n", element, attrib); } else if (pTmp > pRightBound) { printf("override /n"); } else//4.到这里仅仅是找到 pTmp指向attrib="some" 的位置了,值还是要根据类型取出来 { //5 while (*pTmp != 34)// " 的ASCII 就是34,找到" 后面的就是要查找的数据了 { //Sleep(100); //printf("next(%d)/n", *pTmp); pTmp++; } //出此循环就得到了 "some"..... 这样的数据,现在要将不是属性的部分去掉,只保留 "some" 这部分 pTmp++;//去左引号 *res = pTmp;//这个时候赋值给返回值,指向不含左引号的数据,后面的行为是去右引号 // while (*pTmp != 34)// 知道到后面那个匹配的 " // { // //Sleep(100); // //printf("next(%d)/n", *pTmp); // pTmp++; // } //这里还是不要截断了,截断的话会破坏输入数据 //*pTmp = 0;//此时指针只在了引号后面的一个字符上,不管你是什么内容,截断,来去掉右引号 //写了const还能修改原来数据,果然不安全,这也是改变const变量的一个方法 //可以不截断,但是返回复制内存的时候要复制到 " 而不是 /0,这个要注意 //思前想后这个不能改,如果要获取同一个xml中的多个属性的时候,截断这个后面的属性就读取不到了 //动态分配内存,免得后来有比较长的xml文件或者属性的时候内存溢出 //这里必须加1,分配的内存要够存放剩余xml属性,初期分配32调试ptz的时候溢出了,64也不行,不能写死这里 pAttrib = (char *)malloc(strlen(*res) + 1); printf("find (%d)(%s)/n", strlen(*res), *res); get_attrib_value(*res, pAttrib); nRes = isNumber(pAttrib); printf("find number(%s)(%d)/n", *res, nRes); free(pAttrib); pAttrib = NULL; return nRes; } } } } printf("error:no element/n"); res = NULL; return -1; } //判断一个string是否全是数字,如果全是数字的话就返回数字,如果不是数组就返回-2 int isNumber(char *string) { int i = 0; int nLen = strlen(string); printf("isNumber input (%s)(%d)/n", string, nLen); while(string[i] != '/0' && i < nLen) { if (isdigit(string[i])) { i++; } else return -2; } return atoi(string); } //对指向 some" attrib2="some2" ... /> 这样的字符进行处理,只获取第一个引号之前some的内容 //和上面的函数配套使用 int get_attrib_value(char *pParse, char *dst) { int i = 0; char *tmp; sprintf(dst, "%s", pParse); printf("[get_attrib_value]:1 dst(%s)/n", dst); tmp = dst; while(*tmp != '/"') { tmp++; i++; } *(dst + i) = '/0'; printf("[get_attrib_value]:2 dst(%s)/n", dst); return 0; } int main(int argc, char* argv[]) { int nRet; char *pRes; char login[1024] = {0}; char *p = (char *)malloc(3072); memset(p, 0, 3072); /* */ x_creat_header(p); x_creat_ptz_info(p, "hello", 10, 40, 1); //printf("11>>>>>>[%d][%s]/n", nRet, pRes); nRet = find_element(p, "DecodeControl", &pRes); if(nRet == 0) { printf("It is a ptz cmd/n"); } printf("%%%%%%%%%%%%%%%%%%%%%%%%(%s)/n", p); nRet = find_attrib(p, "DecodeControl", "AAADecodeCmd", &pRes);//这里改值多次测试 printf("22>>>>>>[%d][%s]/n", nRet, pRes); nRet = find_attrib(p, "DecodeControl", "Open", &pRes); printf("33>>>>>>[%d][%s]/n", nRet, pRes); nRet = find_attrib(p, "DecodeControl", "Speed", &pRes); printf("44>>>>>>[%d][%s]/n", nRet, pRes); nRet = find_attrib(p, "DecodeControl", "PresetNum", &pRes); printf("55>>>>>>[%d][%s]/n", nRet, pRes); free(p);//记得释放内存 p = NULL; return 0; }
呵呵,通过自己写的函数接口可以灵活的构建出所需的XML文件并可以进行元素的查找和获取,虽然没有一些人效率高吧,但是自己写的难免吧,不过在C下是无现成可用的函数的,这里本着GPL的精神进行发布,照搬也要测试下接口的可用性,这个是我在工程是实际使用的函数,有一定的保障,刚解决了一个缓存过小的而内存溢出的问题,所以在后来你可以看到动态分配的内存的处理方式.
起个抛砖引玉的作用,万事开头难,给做XML部分的人开了个头.