libxml -- 解析 XML 文档

来自:http://jianlee.ylinux.org/Computer/C/libxml.html

一、libxml

创建xml文件实例:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

int main (int argc, char **argv)
{
xmlDocPtr pdoc = NULL;
xmlNodePtr proot_node = NULL,pnode = NULL,pnode1 = NULL;

// 创建一个新文档并设置 root 节点
// 一个 XML 文件只有一个 root 节点
pdoc = xmlNewDoc (BAD_CAST "1.0"); proot_node = xmlNewNode (NULL, BAD_CAST "根节点");
xmlNewProp (proot_node, BAD_CAST "版本", BAD_CAST "1.0");
xmlDocSetRootElement (pdoc, proot_node);

pnode = xmlNewNode (NULL, BAD_CAST "子节点1");
// 创建上面 pnode 的子节点
xmlNewChild (pnode, NULL, BAD_CAST "子子节点1", BAD_CAST "信息");
// 添加子节点到 root 节点
xmlAddChild (proot_node, pnode);

pnode1 = xmlNewNode (NULL, BAD_CAST "子子节点1");
xmlAddChild (pnode, pnode1);
xmlAddChild (pnode1,xmlNewText (BAD_CAST "这是更低的节点,子子子节点1"));

// 还可以这样直接创建一个子节点到 root 节点上
xmlNewTextChild (proot_node, NULL, BAD_CAST "子节点2", BAD_CAST "子节点2的内容");
xmlNewTextChild (proot_node, NULL, BAD_CAST "子节点3", BAD_CAST "子节点3的内容");

// 保存 xml 为文件,如果没有给出文件名参数,就输出到标准输出
xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

// 释放资源
xmlFreeDoc (pdoc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

编译这个例子,先看看系统里面的 libxml2 库的 pkgconfig 信息:

root@jianlee:~/lab/xml# cat /usr/lib/pkgconfig/libxml-2.0.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=1

Name: libXML
Version: 2.6.32
Description: libXML library version2.
Requires:
Libs: -L${libdir} -lxml2
Libs.private:  -lz  -lm
Cflags: -I${includedir}/libxml2

root@jianlee:~/lab/xml# pkg-config libxml-2.0 --cflags --libs
-I/usr/include/libxml2  -lxml2

 

编译:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` create_xml.c

 输出结果:

root@jianlee:~/lab/xml# ./a.out
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
  <子节点1>
    <子子节点1>信息</子子节点1>
    <子子节点1>这是更低的节点,子子子节点1</子子节点1>
  </子节点1>
  <子节点2>子节点2的内容</子节点2>
  <子节点3>子节点3的内容</子节点3>
</根节点>

 补充:

输出的各节点不要在一行,上面使用下面方式保存 xml 文档,输出的文件各子节点间自动加入回车:
  // 保存 xml 为文件,如果没有给出文件名参数,就输出到标准输出
  xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

 二、解析xml文件实例

View Code
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>


int main (int argc , char **argv)
{
xmlDocPtr pdoc = NULL;
xmlNodePtr proot = NULL, curNode = NULL;
char *psfilename;

if (argc < 1)
{
printf ("用法: %s xml文件名\n", argv[0]);
exit (1);
}

psfilename = argv[1];
// 打开 xml 文档
//xmlKeepBlanksDefault(0);
pdoc = xmlReadFile (psfilename, "UTF-8", XML_PARSE_RECOVER);

if (pdoc == NULL)
{
printf ("打开文件 %s 出错!\n", psfilename);
exit (1);
}

// 获取 xml 文档对象的根节对象
proot = xmlDocGetRootElement (pdoc);

if (proot == NULL)
{
printf("错: %s 是空文档(没有root节点)!\n", psfilename);
exit (1);
}

/* 我使用上面程序创建的 xml 文档,它的根节点是“根节点”,这里比较是否
正确。
*/
if (xmlStrcmp (proot->name, BAD_CAST "根节点") != 0)
{
printf ("错误文档" );
exit (1);
}

/* 如果打开的 xml 对象有 version 属性,那么就输出它的值。 */
if (xmlHasProp (proot, BAD_CAST "版本"))
{
xmlChar *szAttr = xmlGetProp (proot, BAD_CAST "版本");
printf ("版本: %s \n根节点:%s\n" , szAttr, proot->name);
}
else
{
printf (" xml 文档没有版本信息\n");
}

curNode = proot->xmlChildrenNode;

char n=0;
while (curNode != NULL)
{
if (curNode->name != BAD_CAST "text")
{
printf ("子节点%d: %s\n", n++,curNode->name);
}
curNode = curNode->next;
}

/* 关闭和清理 */
xmlFreeDoc (pdoc);
xmlCleanupParser ();
return 0;
}

编译运行(使用上例创建的 my.xml 文件):

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
  <子节点1>
    <子子节点1>信息</子子节点1>
    <子子节点1>这是更低的节点,子子子节点1</子子节点1>
  </子节点1>
  <子节点2>子节点2的内容</子节点2>
  <子节点3>子节点3的内容</子节点3>
</根节点>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根节点:根节点
子节点0: text
子节点1: 子节点1
子节点2: text
子节点3: 子节点2
子节点4: text
子节点5: 子节点3
子节点6: text

 

在打开 xml 文档之前加上一句(取消上面程序中的此句注释就可以):

 xmlKeepBlanksDefault(0);

 

或者使用下面参数读取 xml 文档:

//读取xml文件时忽略空格
doc = xmlReadFile(docname, NULL, XML_PARSE_NOBLANKS);

 运行结果:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根节点:根节点
子节点0: 子节点1
子节点1: 子节点2
子节点2: 子节点3

 三、删除节点实例

View Code
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>

int main(int argc, char* argv[])
{
xmlDocPtr doc; //定义解析文档指针
xmlNodePtr curNode; //定义结点指针(你需要它为了在各个结点间移动)
char *szDocName;

if (argc <= 1)
{
printf("Usage: %s docname\n", argv[0]);
return(0);
}

szDocName = argv[1];
xmlKeepBlanksDefault(0);
doc = xmlReadFile(szDocName,"UTF-8",XML_PARSE_RECOVER); //解析文件

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

curNode = xmlDocGetRootElement(doc);

/*检查确认当前文档中包含内容*/
if (NULL == curNode)
{
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return -1;
}

curNode = curNode->children;
while (NULL != curNode)
{
//删除 "子节点1"
if (!xmlStrcmp(curNode->name, BAD_CAST "子节点1"))
{
xmlNodePtr tempNode;
tempNode = curNode->next;
xmlUnlinkNode(curNode);
xmlFreeNode(curNode);
curNode = tempNode;
continue;
}

//修改 "子节点2" 的属性值
if (!xmlStrcmp(curNode->name, BAD_CAST "子节点2"))
{
xmlSetProp(curNode,BAD_CAST "属性1", BAD_CAST "设置");
}

//修改 “子节点2” 的内容
if (!xmlStrcmp(curNode->name, BAD_CAST "子节点2"))
{
xmlNodeSetContent(curNode, BAD_CAST "内容变了");
}

//增加一个属性
if (!xmlStrcmp(curNode->name, BAD_CAST "子节点3"))
{
xmlNewProp(curNode, BAD_CAST "新属性", BAD_CAST "");
}

//增加 "子节点4"
if (!xmlStrcmp(curNode->name, BAD_CAST "子节点3"))
{
xmlNewTextChild(curNode, NULL, BAD_CAST "新子子节点1", BAD_CAST "新内容");
}

curNode = curNode->next;
}

// 保存文件
xmlSaveFormatFileEnc (szDocName, doc,"UTF-8",1);

xmlFreeDoc (doc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

编译运行:

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
  <子节点1>
    <子子节点1>信息</子子节点1>
    <子子节点1>这是更低的节点,子子子节点1</子子节点1>
  </子节点1>
  <子节点2>子节点2的内容</子节点2>
  <子节点3>子节点3的内容</子节点3>
</根节点>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` modify_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
  <子节点2 属性1="设置">内容变了</子节点2>
  <子节点3 新属性="有">子节点3的内容<新子子节点1>新内容</新子子节点1></子节点3>
</根节点>
root@jianlee:~/lab/xml# ./a.out my.xml  # 看看再运行一次的结果!
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根节点 版本="1.0">
  <子节点2 属性1="设置">内容变了</子节点2>
  <子节点3 新属性="有" 新属性="有">子节点3的内容<新子子节点1>新内容</新子子节点1><新子子节点1>新内容</新子子节点1></子节点3>
</根节点>

 就整理这么多吧,剩下的接口可以参考原来连接,本人就整理一些具体的使用实例。

posted @ 2012-01-10 16:42  北海石松  阅读(2123)  评论(0)    收藏  举报