类似于这样的格式就是好的格式,但是既然人家规定了就用上面的格式来写,那就没有办法了,将我VC下编译过的函数给共享一下吧,其中有创建和检索属性,可能有些不太直观,不分步调试的话就很难一下全部看懂,呵呵,不过注释丰富
// 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部分的人开了个头.