首先给大家一个解析xml的源代码,自己可以随意的改写

 

1XML解析流程

解析一个XML文档,从中取出想要的信息,例如节点中包含的文字,或者某个节点的属性。其流程如下:

xmlReadFile函数读入一个文件,并返回一个文档指针doc

xmlDocGetRootElement函数得到根节点curNode

此时curNode->xmlChildrenNode就是根节点的首个儿子节点,该儿子节点的兄弟节点可用next指针进行轮询。

轮询所有子节点,找到所需的节点,用xmlNodeGetContent取出其内容。

xmlHasProp查找含有某个属性的节点,属性列表指针xmlAttrPtr将指向该节点的属性列表。

取出该节点的属性,用xmlGetProp取出其属性值。

xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。

2XML解析举例

ParseXmlFile.c源代码如下:

#include<stdio.h>

#include<libxml/parser.h>

#include<libxml/tree.h>

intmain(int argc, char* argv[])

{

xmlDocPtrdoc; //定义解析文件指针

xmlNodePtrcurNode; //定义结点指针

xmlChar*szKey; //临时字符串变量

char*szDocName;

if(argc <= 1)

{

printf("Usage:%s docname", argv[0]);

return(0);

}

szDocName= argv[1];

doc =xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER);

//解析文件

//检查解析文档是否成功,如果不成功,libxml将报错并停止解析。

//一个常见错误是不适当的编码,XML标准文档除了用UTF-8UTF-16外还可用其它编码保存

if(NULL == doc)

{

fprintf(stderr,"Documentnot parsed successfully.");

return-1;

}

//获取根节点

curNode= xmlDocGetRootElement(doc);

if(NULL == curNode)

{

fprintf(stderr,"emptydocument");

xmlFreeDoc(doc);

return-1;

}

//确认根元素名字是否符合

if(xmlStrcmp(curNode->name, BAD_CAST "root"))

{

fprintf(stderr,"documentof the wrong type, root node != root");

xmlFreeDoc(doc);

return-1;

}

curNode= curNode->xmlChildrenNode;

xmlNodePtrpropNodePtr = curNode;

while(curNode!= NULL)

{

//取出节点中的内容

if((!xmlStrcmp(curNode->name, (const xmlChar *) "newNode1")))

{

szKey =xmlNodeGetContent(curNode);

printf("newNode1:%s\n",  );

xmlFree(szKey);

}

//查找带有属性attribute的节点

if(xmlHasProp(curNode,BAD_CAST "attribute"))

{

propNodePtr = curNode;

}

curNode = curNode->next;

}

//查找属性

xmlAttrPtr attrPtr =propNodePtr->properties;

while (attrPtr != NULL)

{

if(!xmlStrcmp(attrPtr->name, BAD_CAST "attribute"))

{

xmlChar* szAttr =xmlGetProp(propNodePtr,BAD_CAST "attribute");

printf("getattribute=%s\n", szAttr) ;

xmlFree(szAttr);

}

attrPtr = attrPtr->next;

}

xmlFreeDoc(doc);

return 0;

}

编译 gcc ParseXmlFile.c -oParseXmlFile -I/usr/local/include/libxml2 -lxml2

执行 ./ParseXmlFile CreateXml.xml

结果就会显示在屏幕上。

接下来我要做的就是运用上面的源代码将我自己的xml文件解析出来。

#include <stdio.h>

#include <assert.h>//设定插入点
#include <ctype.h>//字符处理
#include <errno.h>//定义错误码
#include <float.h>//浮点数处理
#include <limits.h>//定义各种数据类型最值常量
#include <locale.h>//定义本地化函数
#include <math.h>//定义数学函数
#include <stdio.h>//定义输入/输出函数
#include <stdlib.h>//定义杂项函数及内存分配函数
#include <string.h>//字符串处理
#include <time.h>//定义关于时间的函数
#include <wchar.h>//宽字符处理及输入/输出
#include <wctype.h>

#include <libxml/parser.h>

#include <libxml/tree.h>

int main(int argc, char* argv[])
 
{
 xmlDocPtr doc;           //定义解析文件指针
 
    xmlNodePtr curNode;      //定义结点指针
 
    xmlChar *szKey;          //临时字符串变量
 
    char *szDocName;


 char line[1024*512];
 char dest_gb18030[1024*512];
 char dest_utf8[1024*512];
 int ret ;

 

 FILE *fp = fopen("/root/czy/test/test/123_GB18030.xml","r");
 if(fp == NULL)
    {
  printf("oh my dear,open fail...\n");
  return 1;
    }
 
 memset(line,0,sizeof(line));
 if( NULL == fread(line,1,sizeof(line)-1,fp))
    {
  printf("oh fread fail...\n");
  return 2;
    }
 printf( "----- :%s\n",line );
 
 
 ret  = gb18030toutf8(line,strlen(line),dest_gb18030,1024*512);
 // ret  = gb18030toutf8(dest_gb18030,strlen(dest_gb18030),dest_utf8,80);
 //printf( "ret=%d\n\n\n",ret);
 //printf( "gb18030:%s\n",line );
 printf( " utf-8:%s\n\n\n\n\n\n", dest_gb18030 );
 
 ret  = utf8togb18030(dest_gb18030,strlen(dest_gb18030),dest_utf8,1024*512);
// printf( "ret=%d\n\n\n ",ret);
// printf( " utf-8:%s\n ",dest_gb18030);
// printf( "gb18030:%s\n ",dest_utf8);
 

 
 //   xmlDocPtr doc;           //定义解析文件指针
 
 //   xmlNodePtr curNode;      //定义结点指针
 
 //   xmlChar *szKey;          //临时字符串变量
 
   // char *szDocName;

 
 
    doc = xmlReadMemory(dest_gb18030,sizeof(dest_gb18030),szDocName,"UTF-8",XML_PARSE_RECOVER);

// xmlReadMemory这个函数的作用是读出内存的,因为我是先转换后解析的,所有我要把我自己转换出来的XML文件解析出来,就要把那段内存读出来。原来的xmlReadFile是用来读文件的。
 //   doc = xmlReadFile(szDocName,"GB18030",XML_PARSE_RECOVER);
 

 
    if (NULL == doc)
 
    {
 
        fprintf(stderr,"Document not parsed successfully.");   
 
        return -1;
 
    }

 
    curNode = xmlDocGetRootElement(doc);
 
    if (NULL == curNode)
 
    {
 
        fprintf(stderr,"empty document");
 
        xmlFreeDoc(doc);
 
        return -1;
 
    }
 printf("@@@@@@@@@@@@@@@@@%s\n",curNode->name);
 

 
    if (xmlStrcmp(curNode->name, BAD_CAST "print_task")) 

 //上面这个if 语句是用来做对比的,如果因为我不知道我的curNode->name会指到哪里,所以我在上面写了一个printf语句找到了这个位置,就是我要解析的XML文件的print_task处。
 
    {
 
        fprintf(stderr,"document of the wrong type, print node != print");
 
        xmlFreeDoc(doc);
 
        return -1;
 
    }

 
    curNode = curNode->xmlChildrenNode;
 
    xmlNodePtr propNodePtr = curNode;
 
    while(curNode != NULL)
 
    {
  printf("!!!!!!!!!!!!%s\n",curNode->name);
 
        if ((!xmlStrcmp(curNode->name, (const xmlChar *) "text")))
 
        {
 
            szKey = xmlNodeGetContent(curNode);
 
            printf("text: %s\n", szKey);
 
            xmlFree(szKey);
        }
  else if ((!xmlStrcmp(curNode->name, (const xmlChar *) "line")))
 
        {
 
            szKey = xmlNodeGetContent(curNode);
 
            printf("text: %s\n", szKey);
   memset(dest_utf8,0,sizeof(dest_utf8));
   ret  = utf8togb18030(szKey,strlen(szKey),dest_utf8,1024*512);
   printf( "test%s\n ",dest_utf8);
 
            xmlFree(szKey);
        }
  if (xmlHasProp(curNode,BAD_CAST "align"))
  {
   propNodePtr = curNode;
  }
  curNode = curNode->next;
 }
 //查找属性
 xmlAttrPtr attrPtr = propNodePtr->properties;
 while (attrPtr != NULL)
 {
  if (!xmlStrcmp(attrPtr->name, BAD_CAST "align"))  //align 是我自己文件的一个属性,大家可以自己改成自己想要解析文件的属性
  {
   xmlChar* szAttr = xmlGetProp(propNodePtr,BAD_CAST "align");
   printf("get attribute=%s\n", szAttr) ;
   xmlFree(szAttr);
  }
  attrPtr = attrPtr->next;
 }
 xmlFreeDoc(doc);
 
 return 0;
}

这是我修改的源代码,改动的地方我已经做出了注释

接着我的代码还需要一个动态库来链接

#include<iconv.h>
#include <stdio.h>

#include<iconv.h>

#include <stdio.h>

int utf8togb18030(const char *sourcebuf,size_t sourcelen,char *destbuf,size_t destlen)
{
  iconv_t cd;
  if( (cd = iconv_open("gb18030","utf-8")) ==0 )
    return -1;
  memset(destbuf,0,destlen);
  const char **source = &sourcebuf;
  char **dest = &destbuf;

  if(-1 == iconv(cd,source,&sourcelen,dest,&destlen))
    return -1;
  iconv_close(cd);
  return 0;
}

int gb18030toutf8(const char *sourcebuf,size_t sourcelen,char *destbuf,size_t destlen)
{
  iconv_t cd;
  if( (cd = iconv_open("utf-8","gb18030")) ==0 )
    return -1;
  memset(destbuf,0,destlen);
  const char **source = &sourcebuf;
  char **dest = &destbuf;

  if(-1 == iconv(cd,source,&sourcelen,dest,&destlen))
    return -1;
  iconv_close(cd);
  return 0;
}

动态库的代码已给出,现在要做的就是生成动态库

gcc -shared -fpic -o libmy.so iconv1.c

然后在做解析

gcc-I/root/czy/test/libxml/libxml2-2.9.0/include -o t main.c -L./ -lmy -lxml2-L/root/czy/test/libxml/libiconv-1.14/lib/.libs –liconv

接着运行./t 就会得到了我们所要的文件了

这里给出一个需要注意的地方,如果 ./t 没有出现结果,反而出错了,这可能就是因为我们没有定义环境变量

这时只需要们加上一条命令 就可以解决了,命令如下:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

 

 

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐