前言:今天在做一个小项目时,客户要求的xml,跟现在有系统要求的不一样,所以要自己重新写函数支持返回,进行简单总结,希望对大家有所帮助。

  首先,使用xml函数需要链上动态库libxml2,需要在电脑上安装libxml的开发包,安装方法如下:

      Ubuntu系统: sudo apt-get install libxml2-dev
      CentOS系统:yum install libxml2-devel  

1.   创建XML文档

(1)相关函数有许多,网上也有特别多的解释,大家可以百度一下,这里只是简单介绍一部分;创建一个XML文档非常简单,其流程如下:

①    用xmlNewDoc函数创建一个文档指针doc。

②    用xmlNewNode函数创建一个节点指针root_node。

③    用xmlDocSetRootElement将root_node设置为doc的根结点。

④    给root_node添加一系列的子节点,并设置子节点的内容和属性。

⑤    用xmlSaveFile将XML文档存入文件(用xmlDocDumpFormatMemoryEnc将XML存入内存)。

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

 有多种方式可以添加子节点,如可以用xmlNewTextChild直接添加一个文本子节点。也可以先创建新节点,然后用xmlAddChild将新节点加入到上层节点中。

  注:xmlSaveFile存入文件方便单独执行程序查看结果,一般项目用用xmlDocDumpFormatMemoryEnc将XML存入内存!

   (2)创建xml文件举例

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h> int main()
{
xmlChar *result = NULL;
int size = ;
xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); //定义文档和节点指针 xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST "root");
xmlDocSetRootElement(doc,root_node); //设置根节点 //在根节点中直接创建节点
xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content");
xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content");
xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content"); //创建一个节点,设置其内容和属性,然后加入根结点
xmlNodePtr node = xmlNewNode(NULL,BAD_CAST "node2");
xmlNodePtr content = xmlNewText(BAD_CAST "NODE CONTENT");
xmlAddChild(root_node,node);
xmlAddChild(node,content);
xmlNewProp(node,BAD_CAST "attribute",BAD_CAST "yes"); //创建一个儿子和孙子节点
node = xmlNewNode(NULL, BAD_CAST "son");
xmlAddChild(root_node,node);
xmlNodePtr grandson = xmlNewNode(NULL, BAD_CAST "grandson");
xmlAddChild(node,grandson);
//xmlAddChild(grandson, xmlNewText(BAD_CAST "This is a grandson node"));
xmlNodePtr congson = xmlNewNode(NULL, BAD_CAST "congson");
xmlAddChild(grandson,congson); //存储xml文档
//xmlKeepBlanksDefault(0);
//xmlDocDumpFormatMemoryEnc(doc, &result, &size, "UTF-8", 1); int nRel = xmlSaveFile("CreateXml.xml",doc);
if (nRel != -)
{
printf("一个xml文档被创建,写入%d个字节\n", nRel);
}
//释放文档内节点动态申请的内存
xmlFreeDoc(doc);
return ;
}

 CentOS系统下面执行:gcc CreateXmlFile.c -o CreateXmlFile -I /usr/include/libxml2 -lxml2

执行./CreateXmlFile,会生成一个XML文件CreatedXml.xml。

2.   解析XML文档

(1)XML解析流程

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

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

②    用xmlDocGetRootElement函数得到根节点curNode。

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

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

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

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

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

(2). 解析XML文件并获取属性示例

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h> int main(int argc, char* argv[])
{
xmlDocPtr doc; //定义解析文件指针
xmlNodePtr curNode; //定义结点指针
xmlChar *szKey; //临时字符串变量
char *szDocName;
if (argc <= ) {
printf("Usage: %s docname", argv[]);
return();
}
szDocName = argv[];
doc = xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER);
//解析文件
//检查解析文档是否成功,如果不成功,libxml将报错并停止解析。
//一个常见错误是不适当的编码,XML标准文档除了用UTF-8或UTF-16外还可用其它编码保存
if (NULL == doc) {
fprintf(stderr,"Document not parsed successfully.");
return -;
}
//获取根节点
curNode = xmlDocGetRootElement(doc);
if (NULL == curNode) {
fprintf(stderr,"empty document");
xmlFreeDoc(doc);
return -;
}
//确认根元素名字是否符合
if (xmlStrcmp(curNode->name, BAD_CAST "root")) {
fprintf(stderr,"document of the wrong type, root node != root");
xmlFreeDoc(doc);
return -;
}
curNode = curNode->xmlChildrenNode;
xmlNodePtr propNodePtr = curNode;
while(curNode != NULL) {
//取出节点中的内容
if ((!xmlStrcmp(curNode->name, (const xmlChar *) "newNode1"))) {
szKey = xmlNodeGetContent(curNode);
printf("newNode1: %s\n", szKey);
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("get attribute=%s\n", szAttr) ;
xmlFree(szAttr);
}
attrPtr = attrPtr->next;
}
xmlFreeDoc(doc);
return ;
}

编译:gcc ParseXmlFile.c -o ParseXmlFile -I /usr/include/libxml2  -lxml2

执行:./ParseXmlFile  xxx.xml

3、用iconv解决XML中字符集问题

libxml2中默认的内码是UTF-8,所有使用libxml2进行处理的xml文件,必须首先显式或者默认转换为UTF-8编码才能被处理。

要在XML中使用中文,就必须能够在UTF-8和GB2312之间进行转换。libxml2提供了默认的内码转换机制,并且在libxml2的Tutorial中有一个例子,事实证明这个例子并不很适合用来转换中文。

有些场合需要使用iconv来进行编码转换,libxml2本身也是使用iconv进行编码转换的。iconv是一个专门用来进行编码转换的库,基本上支持目前所有常用的编码,它是glibc库的一个部分。

本节其实和libxml没有太大关系,可以把它简单看作是一个编码转换方面的专题。下文提供了一个通用转码函数,并在此基础上实现了两个转码封装函数,即从UTF-8转换到GB2312的函数u2g,以及反向转换的函数g2u。其代码如下:

  

#include <iconv.h>
#include <string.h> //代码转换,从一种编码转为另一种编码
int code_convert(char* from_charset, char* to_charset, char* inbuf,
int inlen, char* outbuf, int outlen)
{
iconv_t cd;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if(cd == ) { return -; }
memset(outbuf,,outlen);
if(iconv(cd,(const char **)pin, (unsigned int *)&inlen, pout, (unsigned int*)&outlen) == -) {
return -;
} iconv_close(cd);
return ;
} //UNICODE码转为GB2312码
//成功则返回一个动态分配的char*变量,需要在使用完毕后手动free,失败返回NULL
char* u2g(char *inbuf)
{
int nOutLen = * strlen(inbuf) - ;
char *szOut = (char*)malloc(nOutLen);
if (- == code_convert("utf-8", "gb2312", inbuf, strlen(inbuf), szOut, nOutLen)) {
free(szOut);
szOut = NULL;
}
return szOut;
} //GB2312码转为UNICODE码
//成功则返回一个动态分配的char*变量,需要在使用完毕后手动free,失败返回NULL
char* g2u(char *inbuf)
{
int nOutLen = * strlen(inbuf) - ;
char *szOut = (char *)malloc(nOutLen);
if (- == code_convert("gb2312", "utf-8", inbuf, strlen(inbuf), szOut, nOutLen)) {
free(szOut);
szOut = NULL;
}
return szOut;
}

下面以UTF-8到GB2312转码流程说明上文中转码函数的使用,使用流程如下:

①    得到一个UTF-8的字符串szSrc。

②    定义一个char *的字符指针szDes,并不需要给它动态申请内存。

③    调用szDes = u2g(szSrc),这样szDes就指向转换后GB2312编码的字符串。

④    使用完这个字符串后使用free(szDes)来释放内存。

Linux系统下有个iconv命令,可以在shell命令行输入iconv  --help 来查看用法,在程序中可以采用system系统调用来进行文件转码。下文中f表示from,t表示to,其转码方法如下:

system("iconv –f 源格式 –t 目标格式 源文件 >目标文件")

system("iconv –f  GB18030 –t UTF-8  test_gb.txt > test_utf.txt")

shell命令行使用方法: iconv -f gb2312 -t utf-8 readme.txt -o readme.txt

  总结:会发现创建xml整个流程都很长,不适合放在函数中!公司去华为的一个大神,先用双向链表创建再返回,封装一个函数,这样就很方便了,我也在继续优化中...

  

XML的创建、解析-C语言的更多相关文章

  1. Android开发之XML的创建和解析

    参考:http://blog.csdn.net/pi9nc/article/details/9320413 XML文件的解析,代码: public void click(View v) { Input ...

  2. xml语法、DTD约束xml、Schema约束xml、DOM解析xml

    今日大纲 1.什么是xml.xml的作用 2.xml的语法 3.DTD约束xml 4.Schema约束xml 5.DOM解析xml 1.什么是xml.xml的作用 1.1.xml介绍 在前面学习的ht ...

  3. Android基础总结(12)——XML和JSON解析

    XML和JSON解析 在网络上传输数据时最常用的格式有两种:XML和JSON.本文主要就是学习如何对这两种常用的数据格式进行解析. 1.XML和JSON的定义 XML:扩展标记语言 (Extensib ...

  4. iOS开发网络篇—XML数据的解析

     iOS开发网络篇—XML数据的解析 iOS开发网络篇—XML介绍 一.XML简单介绍 XML:全称是Extensible Markup Language,译作“可扩展标记语言” 跟JSON一样,也是 ...

  5. Android XML文档解析(一)——SAX解析

    ---------------------------------------------------------------------------------------------------- ...

  6. [置顶] Android开发之XML文件的解析

    Android系统开发之XML文件的解析 我们知道Http在网络传输中的数据组织方式有三种分别为:XML方式.HTML方式.JSON方式.其中XML为可扩展标记语言,如下: <?xml vers ...

  7. (5)微信二次开发 之 XML格式数据解析

    1.首先理解一下html html的全名是:HyperText Transfer markup language 超级文本标记语言,html本质上是一门标记(符合)语言,在html里,这些标记是事先定 ...

  8. xml文件以及解析

    1.创建一个xml文件 <?xml version="1.0" encoding="UTF-8"?> <!-- xml:是一个可扩展的标记语言 ...

  9. XML基础+Java解析XML +几种解析方式的性能比较

    XML基础+Java解析XML 一:XML基础 XML是什么: 可扩展的标记语言 XML能干什么: 描述数据.存储数据.传输(交换)数据. XML与HTML区别: 目的不一样 XML 被设计用来描述数 ...

随机推荐

  1. MySQL 慢查询日志总结

    慢查询日志概念 MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志 ...

  2. 【莫比乌斯反演】BZOJ2154 Crash的数字表格

    Description 求sigma lcm(x,y),x<=n,y<=m.n,m<=1e7. Solution lcm没有什么直接做的好方法,用lcm=x*y/gcd转成gcd来做 ...

  3. bzoj1547 周末晚会

    我们要求方案数,还是旋转同构的,想burnside,如果我们能计算出转i位不变的满足条件的数量,那么这道题我们就解决了. 考虑转i位时,设tmp=gcd(i,n),那么就共有tmp个循环节. 当tmp ...

  4. BZOJ_3514_Codechef MARCH14 GERALD07加强版_主席树+LCT

    BZOJ_3514_Codechef MARCH14 GERALD07加强版_主席树+LCT Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. I ...

  5. appium 元素定位find_element_by_android_uiautomator方法使用

    若appium中给定的方法无法满足你的需求,刚好uiautomator中的方法可以满足你的需求时,你可使用find_element_by_android_uiautomator来调用uiautomat ...

  6. Random在高并发下的缺陷以及JUC对其的优化

    Random可以说是每个开发都知道,而且都用的很6的类,如果你说,你没有用过Random,也不知道Random是什么鬼,那么你也不会来到这个技术类型的社区,也看不到我的博客了.但并不是每个人都知道Ra ...

  7. ASP.NET Core在Azure Kubernetes Service中的部署和管理

    目录 ASP.NET Core在Azure Kubernetes Service中的部署和管理 目标 准备工作 注册 Azure 账户 AKS文档 进入Azure门户(控制台) 安装 Azure Cl ...

  8. 从壹开始前后端 [vue后台] 之二 || 完美实现 JWT 滑动授权刷新

    缘起 哈喽大家周一好!不知道小伙伴们有没有学习呀,近来发现各种俱乐部搞起来了,啥时候群里小伙伴也搞一次分享会吧,好歹也是半千了(时间真快,还记得5个月前只有20多人),之前在上个公司,虽然也参与组织过 ...

  9. Redis in .NET Core 入门:(3) Hash

    第1篇:https://www.cnblogs.com/cgzl/p/10294175.html 第2篇 String:https://www.cnblogs.com/cgzl/p/10297565. ...

  10. 腾讯云发布runC容器逃逸漏洞修复公告

    尊敬的腾讯云客户,您好:  近日,腾讯云安全中心监测发现轻量级容器运行环境runc被爆存在容器逃逸漏洞,攻击者可以在利用该漏洞覆盖Host上的runc文件,从而在Host上以root权限执行代码. 为 ...