2013
12-27

根据导师的要求,要用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 %d\n",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


留下一个回复