根据导师的要求,要用c语言解析一个xml文件,用于对升级文件进行合法性判断,进而对软件进行升级。
上网搜了一些关于这方面的资料,发现有一些是用C++或java等语言写的,当然也可以直接下载开源的代码,也可以下载库文件直接使用。但考虑到对xml文件解析其实用不到那么多功能,也考虑到硬件方面无法支持这么大的库文件。因此,决定自己写一段代码用于解析简单的xml文件。
看了一些源代码,发现他们主要使用树型结构来实现对xml 的解析,由于能力有限吧,感觉很麻烦,可能占用内存也会很大,所以我苦苦思索了好久,决定使用递归的方法解析xml文件,每当解析出相应的数值时,可以立即对这些数值进行判定是否合法,如果合法的话,可以继续解析;如果不合法的话,就可以直接跳出。
对这个xml文件,我做了很严格的定义:
<!– 注释–>
<主标签 属性值1>
<子标签> 属性值2 </子标签>
<子标签>
<下级子标签>属性值3</下级子标签>
</子标签>
</主标签>
在这里,可以在标签间的任何地方进行注释,但禁止在标签内部进行注释;标签可以有多层嵌套,但必须保证标签有结束标志,嵌套必须合法。
属性值的规定方面,可以正确的解析属性值2和属性值3,但不会解析属性值1,属性值1可以起到注释的作用。
下面贴出一些主要的代码:
首先读取xml文件:
fp = fopen("update.xml","r");
if(fp == NULL) return 0;
while((c = getc(fp)) != EOF)
{
data[i++] = c;
}
然后对data数组进行相应的处理,如下:
int xml_takecell(char *data, int start, int end, char *name)
{
int flag = 0;
int j = 0;
int nowstart = 0;
int nowend = 0;
char value[45] = {0};
int keywords = 0;
int isok = 0;
if(update == 1) return 1;
nowstart = xml_getnamestart(data,start,end,name);
nowend = xml_getnameend(data,nowstart,end,name);
keywords = iskeywords(name);
switch(keywords)
{
case KEY_UPDATELIST:
xml_getvalue(data,nowstart,nowend,value);
node_name = keywords;
flag = 0;
break;
case KEY_ENABLE:
xml_getvalue(data,nowstart,nowend,value);
flag = 0;
break;
case KEY_START:
xml_getvalue(data,nowstart,nowend,value);
flag = 0;
break;
case KEY_END:
xml_getvalue(data,nowstart,nowend,value);
flag = 0;
break;
case KEY_ID:
node_name = keywords;
flag = 1;
break;
case KEY_SWVERSION:
node_name = keywords;
flag = 1;
break;
case KEY_CONFIG:
node_name = keywords;
flag = 1;
break;
……
default:
flag = 1;
node_name = 0;
break;
}
isok = checkupdate(node_name,keywords,value);
if(isok == 1) return 0;
if(flag == 1 && nowend <end)
{
cleanstring(name, 15);
xml_takecell(data,nowstart,nowend,name);
}
if(nowend <end)
{
cleanstring(name, 15);
xml_takecell(data,nowend,end,name);
}
return 0;
}
这是实现递归的核心代码,其中,函数xml_getnamestart()、xml_getnameend()是对同一个标签的开始处和结尾处进行查询,返回值是所在数组的位置,然后可以在此标签内部进行递归查询,直到找到最低一级的标签,并利用 xml_getvalue()获取标签的属性值。函数checkupdate()是对获取的属性值合法性做判断,如果是非法的,可以直接跳出此次处理。KEY_UPDATELIST、KEY_SWVERSION这些是自己事先定义的标签名。
各函数如下:
函数xml_getnamestart:
int xml_getnamestart(char *data, int start, int end, char *name)
{
int now = start;
int i = 0;
int flag = 0;
while(now < end)
{
now++;
/*在这里,可以忽略<!–注释 –>形式的注释*/
if(data[now-1] == '<' && data[now] != '!' && data[now] != '/')
flag = 1;
else if((data[now] == '>' || data[now] == ' ') && flag == 1)
{
flag = 0;
// printf("xml_getnamestart—->name is %s now is %dn",name,now);
break;
}
if(flag == 1)
{
name[i] = data[now];
i++;
}
}
return now;
}
函数xml_getnameend:
int xml_getnameend(char *data, int start, int end, char *name)
{
int now = start;
int i = 0;
int flag = 0;
char value[15] = {0};
int ok = 0;
while(now < end)
{
now++;
if(data[now-1] == '<' && data[now] == '/')
{
flag = 1;
i = 0;
ok = 0;
now++;
}
/*这里表示标签以空格或>结尾,也解释了属性值1为什么不能解析*/
else if((data[now] == '>' || data[now] == ' ') && flag == 1)
{
flag = 0;
}
if(flag == 1)
{
if(name[i] == data[now])
{
i++;
ok++;
}
else if(name[i] != data[now])
{
i = 0;
ok = 0;
flag = 0;
}
}
if(ok == strlen(name)) break;
}
// printf("xml_getnameend—->name is %s now is %d n",name,now);
return now;
}
函数xml_getvalue:
/*在 > 和 < 之间为属性值*/
int xml_getvalue(char *data, int start, int end, char *value)
{
int i = 0;
// char value[45] = {0};
cleanstring(value,45);
if(data[i+start] == '>') start++;
for(i = 0; i+start< end; i++)
{
if(data[i+start] == '<') break;
value[i] = data[start+i];
}
return 0;
}
这些代码写的比较业余,以后还要多多锻炼一下代码的编写规范。
这些参考资料是利用树型结构解析xml文件的思想,现在看的不是很明白,供以后修炼:
http://dangle2046.blog.163.com/blog/static/832104472008929101736243/
http://www.oschina.net/p/mini-xml
FROM:http://blog.csdn.net/xiaosong521/article/details/7410451
>> 本文固定链接: http://www.vcgood.com/archives/3757