【Xml】Linux 下C/C++解析XML文件【转】

系统环境

# uname -a
Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

安装编译libxml2库

libxml官网:http://xmlsoft.org/

下载源码包地址:http://xmlsoft.org/downloads.html

下载源码

本人下载的是libxml2-2.8.0版本的源码包,源码包文件名为:libxml2-2.8.0.tar.gz。获取源码包命令如下:

wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz

下载完成后,查看源码包文件的md5值和sha256值:

# md5sum libxml2-2.8.0.tar.gz
c62106f02ee00b6437f0fb9d370c1093  libxml2-2.8.0.tar.gz
# sha256sum libxml2-2.8.0.tar.gz
f2e2d0e322685193d1affec83b21dc05d599e17a7306d7b90de95bb5b9ac622a  libxml2-2.8.0.tar.gz

<注意> 安装需要有root权限,最好是在root用户下进行,如果不是root用户,执行编译安装操作时需要在命令前加上 sudo 。本人的所有操作是在root用户下进行的。

解压源码

tar -xzvf libxml2-2.8.0.tar.gz

安装编译

# 进入目录
cd libxml2-2.8.0
# 通过执行:./configure --help 命令,可以查看configure脚本的使用帮助。默认是安装在/usr/local路径下,对应的可执行文件、库文件、头文件等路径是:/usr/local/bin、/usr/local/lib、/usr/local/include下。
# 设置安装自定义路径
./configure --prefix=/usr/local/libxml2
# 安装编译
make && make install
#  <Tips> 要卸载glib库,命令为:make uninstall

安装成功后,可以看到/usr/local目录下多了一个libxml2目录,查看一下这个目录的树形结构。libxml2目录下有4个一级子目录:bin include lib share。

配置libxml2库的开发环境

一、配置PATH环境变量

PATH环境变量对应的可执行文件(一般设置的是Linux命令的路径)。这里我设置libxml2库的bin目录下的路径为对所有用户生效,因此需要在/etc/profile文件中配置PATH环境变量的值。

vim /etc/profile,添加内容如下:

#Add bin path
export PATH=$PATH:/usr/local/libxml2/bin

保存修改后,执行:source /etc/profile,令修改生效,下同。

尝试执行一个/usr/local/libxml2/bin目录下的Linux命令。例如,执行xml2-config命令,打印出libxml2三方库的版本信息:

xml2-config --version
二、配置libxml2三方库的C头文件搜索路径

C头文件搜索路径对应的环境变量是C_INCLUDE_PATH,这里我们只在当前用户的主目录下的.bash_profile文件中配置。执行命令:vim ~/.bash_profile,添加内容如下:

export C_INCLUDE_PATH=/usr/local/libxml2/include/libxml2:$C_INCLUDE_PATH

保存修改后,执行:source ~/.bash_profile,令修改生效,下同。

三、配置libxml2三方库的链接库文件搜索路径

执行命令:vim ~/.bash_profile,添加内容如下:

# Add third_lib path
export LD_LIBRARY_PATH=/usr/local/libxml2/lib:$LD_LIBRARY_PATH
export LIBRARY_PATH=/usr/local/libxml2/lib:$LIBRARY_PATH

至于,为什么要同时配置LIBRARY_PATH、LD_LIBRARY_PATH 这两个环境变量,请参考下面链接中的博客说明。https://www.cnblogs.com/lovychen/p/10911600.html

了解libxml2数据结构

在libxml2中比较重要的数据结构是xmlNodePtr,它在libxml/tree.h中定义为

/** 
 * xmlNode: 
 * 
 * A node in an XML tree. 
 */  
typedef struct _xmlNode xmlNode;  
typedef xmlNode *xmlNodePtr;  
struct _xmlNode {  
    void           *_private;   /* application data */  
    xmlElementType   type;  /* type number, must be second ! */  
    const xmlChar   *name;      /* the name of the node, or the entity */  
    struct _xmlNode *children;  /* parent->childs link */  
    struct _xmlNode *last;  /* last child link */  
    struct _xmlNode *parent;    /* child->parent link */  
    struct _xmlNode *next;  /* next sibling link  */  
    struct _xmlNode *prev;  /* previous sibling link  */  
    struct _xmlDoc  *doc;   /* the containing document */  

    /* End of common part */  
    xmlNs           *ns;        /* pointer to the associated namespace */  
    xmlChar         *content;   /* the content */  
    struct _xmlAttr *properties;/* properties list */  
    xmlNs           *nsDef;     /* namespace definitions on this node */  
    void            *psvi;  /* for type/PSVI informations */  
    unsigned short   line;  /* line number */  
    unsigned short   extra; /* extra data for XPath/XSLT */  
};  

C/C++ 读取XML文件代码示例

test.c

#include <stdio.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <string.h>

#include <libxml/parser.h>  
#include <libxml/xmlmemory.h>  

#if 0
int main(int argc, char* argv[])
{
    xmlDocPtr doc;           //定义解析文档指针
    xmlNodePtr curNode;      //定义结点指针(你需要它为了在各个结点间移动)
    xmlChar *szKey;          //临时字符串变量
    char *szDocName;

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

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

    //检查解析文档是否成功,如果不成功,libxml将指一个注册的错误并停止。
    //一个常见错误是不适当的编码。XML标准文档除了用UTF-8或UTF-16外还可用其它编码保存。
    //如果文档是这样,libxml将自动地为你转换到UTF-8。更多关于XML编码信息包含在XML标准中.

    if (NULL == doc)
    {  
       fprintf(stderr, "xmlParseFile Error in %s %d\n",__FUNCTION__, __LINE__);
       return -1;
    }

    curNode = xmlDocGetRootElement(doc); //确定文档根元素
    if (NULL == curNode)
    {
       fprintf(stderr, "xmlDocGetRootElement Error in %s %d\n", __FUNCTION__, __LINE__);
       xmlFreeDoc(doc);
       return -1;
    }

    printf("Node name is %s!\n", pRoot->name);

    if (xmlStrcmp(curNode->name, BAD_CAST "root"))
    {
       fprintf(stderr,"document of the wrong type, root node != root\n");
       xmlFreeDoc(doc);
       return -1;
    }

    curNode = curNode->xmlChildrenNode; //子节点集是链表
    xmlNodePtr propNodePtr = curNode;
    while(curNode != NULL)
    {
       //取出节点中的内容
       if ((!xmlStrcmp(curNode->name, (const xmlChar *)"monitor")))
       {
           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");
   //szAttr要调用函数xmlFree(szAttr)手动删除否则会发生内存泄露。
//           cout<<"get attribute = "<<szAttr<<endl;
           xmlFree(szAttr);
       }
       attrPtr = attrPtr->next;
    }

    xmlFreeDoc(doc);
    return 0;

}
#endif

int main(int argc, const char *argv[])
{
    if(2 != argc)
    {
        fprintf(stdout, "Please statrt this program with %s xmlfilepath!", argv[0]);
        return 1;
    }
    xmlDocPtr pDoc = xmlReadFile(argv[1], "UTF-8", XML_PARSE_RECOVER); //获取XML文档的指针
    if(NULL == pDoc)
    {
        fprintf(stderr, "xmlParseFile Error in %s %d\n",__FUNCTION__, __LINE__);
        return -1;
    }

    xmlNodePtr pRoot = xmlDocGetRootElement(pDoc);//获取根节点
    if(NULL == pRoot)
    {
        fprintf(stderr, "xmlDocGetRootElement Error in %s %d\n", __FUNCTION__, __LINE__);
        xmlFreeDoc(pDoc);
        return -1;
    }

    printf("Node name is %s!\n", pRoot->name);

    xmlNodePtr pFirst = pRoot->xmlChildrenNode;//获取子节点
    while(NULL != pFirst)
    {
        if(!xmlStrcmp(pFirst->name, (const xmlChar *)("monitor")))
        {
            xmlNodePtr pSecond = pFirst->xmlChildrenNode;
            while(NULL != pSecond)
            {
                xmlChar* value= NULL;

                if(!xmlStrcmp(pSecond->name, (const xmlChar *)("name")))
                {
                    value = xmlNodeGetContent(pSecond);
                    printf("\n%s-->%s\n", pSecond->name, value);
                    xmlFree(value);
                    value = NULL;
                }

                if(!xmlStrcmp(pSecond->name, (const xmlChar *)("path")))
                {
                    value = xmlNodeGetContent(pSecond);
                    printf("\n%s-->%s\n", pSecond->name, value);
                    xmlFree(value);
                    value = NULL;
                }

                if(!xmlStrcmp(pSecond->name, (const xmlChar *)("log")))
                {
                    xmlNodePtr pThird = pSecond->xmlChildrenNode;
                    while(NULL != pThird)
                    {
                        if(!xmlStrcmp(pThird->name, (const xmlChar *)("folderpath")))
                        {
                            value = xmlNodeGetContent(pThird);
                            printf("\n%s-->%s\n", pThird->name, value);
                            xmlFree(value);
                            value = NULL;
                        }

                        if(!xmlStrcmp(pThird->name, (const xmlChar *)("savedays")))
                        {
                            value = xmlNodeGetContent(pThird);
                            printf("\n%s-->%s\n", pThird->name, value);
                            xmlFree(value);
                            value = NULL;
                        }

                        pThird = pThird->next;
                    }
                }

                pSecond = pSecond->next;
            }
        }

        pFirst = pFirst->next;
    }
    xmlFreeDoc(pDoc);
    return 0;
}

config.xml

<?xml version="1.0" encoding="UTF-8"?>  
<root>  
    <monitor>  
        <name>ftp</name>   <!--监控的程序名称-->  
        <path>/usr/bin/</path>   <!--程序绝对路径-->  
        <interval>30</interval>  <!--间隔多久监控一次-->  
        <restartwait>30</restartwait>  <!--程序被重启后,等待多久再进行监控-->  
        <ip>127.0.0.1</ip>   <!--程序IP-->  
        <port>9878</port>    <!--程序端口-->  
        <request>1;monitor</request>    <!--发送给程序的报文-->  
        <response>The ftp is working ok.</response>   <!--程序给监控的反馈报文-->  
        <log>  
            <folderpath>log/</folderpath>  <!--程序日志保存目录-->  
            <savedays>2</savedays>     <!--程序日志保存时间-->  
        </log>  
    </monitor>  
</root> 

编译

#!/bin/sh
gcc test.c -o test -lxml2 -I/usr/include/libxml2

执行

./test config.xml
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值