libxml2解析xml总结

libxml2解析xml总结

  • 开发平台:linux
  • IDE:eclipse
  • 语言:c

使用libxml2对xml进行解析有两种方法,一种是纯使用libxml2提供的接口,另一种是使用xpath。只使用libxml2的接口需要进行多层的循环嵌套,比较麻烦,相对来说xpath封装的更好,使用起来更方便。下面具体来描述libxml2的函数以及使用xpath的方法。

代码块

下面是一个使用xpath的例子,其中tim_subtract.h是一个计算时间差的函数,方便统计程序的执行时间:

#include <stdio.h>
#include <stdlib.h>
#include <parser.h>
#include <tree.h>
#include <xpath.h>
#include <xpathInternals.h>
#include <xmlmemory.h>
#include <xpointer.h>
#include "tim_subtract.h"

//使用xpath来获得目标结点
xmlXPathObjectPtr getNodeset(xmlDocPtr pdoc, const xmlChar *xpath)
{
    xmlXPathContextPtr context = NULL; //定义XPath上下文指针
    context = xmlXPathNewContext(pdoc);//用xml文档指针来初始化context指针
    xmlXPathObjectPtr result = NULL; //定义XPath结果指针

    if (pdoc == NULL)
    {
        printf("pdoc is NULL\n");
        return NULL;
    }

    if (xpath)
    {
        if (context == NULL)
        {
            printf("context is NULL\n");
            return NULL;
        }

        result = xmlXPathEvalExpression(xpath, context);//计算xpath的查询结果,并存入result中
        if (result == NULL)
        {
            printf("xmlXPathEvalExpression return NULL\n");
            return NULL;
        }


        if (xmlXPathNodeSetIsEmpty(result->nodesetval))
        //使用result->nodesetval得到节点集合指针,其中包含了所有符合Xpath查询结果的节点
        {
            xmlXPathFreeObject(result);//使用释放Xpath对象指针;
            printf("nodeset is empty\n");
            return NULL;
        }
    }

    return result;
}

int main(int argc, char **argv)
{
    struct timeval t1,t2,diff;
    gettimeofday(&t1,0);
    xmlDocPtr pdoc = NULL;//文档指针
    xmlNodePtr proot = NULL;//节点指针

    /*****************打开xml文档********************/
    //参数为文件名、编码类型和枚举变量(下面一个或多个的组合)
    //XML_PARSE_RECOVER    = 1<<0,    recover on errors    尝试修复错误语法
    //XML_PARSE_NOERROR    = 1<<5,    suppress error reports    不输出错误日志
    //XML_PARSE_NOWARNING    = 1<<6,    suppress warning reports    不输出警告日志
   //XML_PARSE_PEDANTIC    = 1<<7,          pedantic error reporting */    输出详细的错误日志
   //XML_PARSE_NOERROR和XML_PARSE_NOWARNING的功能是“当运行命令行程序时不输出错误/警告日志”。
    pdoc = xmlReadFile("NewFile.xml", "UTF-8", XML_PARSE_RECOVER); 
    if (pdoc == NULL)
    {
        printf("error:can't open file!\n");
        exit(1);
    }

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

    if (proot == NULL) 
    {
        printf("error: file is empty!\n");
        exit(1);
    }

    /*****************查找书店中所有书籍的名称********************/
    xmlChar *xpath = BAD_CAST ("/producttype/product/*"); //xpath语句,路径为product的所有子元素
    xmlXPathObjectPtr result = getNodeset(pdoc, xpath); //调用函数,查询XPath表达式,得到一个查询结果
    if (result == NULL)
    {
        printf("result is NULL\n");
        exit(1);
    }

    if (result)
    {
        xmlNodeSetPtr nodeset = result->nodesetval; //获取查询到的节点指针集合,其中包含了所有符合Xpath查询结果的节点;
        xmlNodePtr cur;//声明一个临时的当前结点指针

        //nodeset->nodeNr是集合元素总数,for遍历每个符合结果的结点
        int i;
        for (i = 0; i < nodeset->nodeNr; i++)
        {
            cur = nodeset->nodeTab[i];//遍历

/**************接下来就是使用libxml2函数进行结点的操作**********/
            while (cur != NULL)
            {
             //查找名为write的结点,并输出其内容
                if (!xmlStrcmp(cur->name, BAD_CAST ("write")))//xmlStrcmp为对比,相同时返回值为0
                {
                    printf("write: %s\n",
                            ((char*) xmlNodeGetContent(cur)));//xmlNodeGetContent为获得某结点的内容
                    break;
                }

                //创建结点,结点名称为CHILD
                xmlNodePtr child=xmlNewNode(NULL,BAD_CAST"CHILD");
                //设置其内容和属性
                xmlNodeSetContent(child,BAD_CAST"子节点");
                xmlSetProp(child,BAD_CAST"属性名",BAD_CAST"属性内容");
                //移除属性,返回0成功,-1失败,每次只能移除一个属性
                int i;
                i=xmlRemoveProp(cur);
                //将child添加给cur为子结点
                xmlAddChidl(cur,child);

                //创建并直接添加子节点
                 xmlNewTextChild(cur, NULL, BAD_CAST "结点名称", BAD_CAST "结点内容");
                //删除newNode1
                  if (!xmlStrcmp(cur->name, BAD_CAST "newGrandSon"))
                       {
                            xmlNodePtr tempNode;
                           tempNode = cur->next; //使用一个临时变量来存储断链节点的后续节点
                           xmlUnlinkNode(cur); //将当前节点从文档中断链(unlink),这样本文档就不会再包含这个子节点
                           xmlFreeNode(cur); //手动删除断链节点的内存
                           cur = tempNode;
                          continue;
                      }
                cur = cur->next;
            }
        }

        xmlXPathFreeObject(result); //释放结果指针
    }
     gettimeofday(&t2,0);
     int ret=tim_subtract(&diff,&t1,&t2);
        if(ret>-1)
        {
           printf("%d\t%d",diff.tv_sec,diff.tv_usec);
        }
        //存储xml文档
            int nRel = xmlSaveFile("NewFile.xml", pdoc);
    /*****************释放资源********************/
    xmlFreeDoc(pdoc);
    xmlCleanupParser();
    xmlMemoryDump();

    return 0;
}
<!--xml文件-->
<?xml version="1.0" encoding="UTF-8"?>
<producttype>
    <product category="PHP">
        <id>1001</id>
        <no>NOC0001</no>
        <name>PHP高级设计教程</name>
        <price>88.99</price>
        <writer>
            <name>zhang</name>
            <sex></sex>
        </writer>
        <time>2015.12.30</time>
    </product>
    <product category="JAVA">
        <id>1002</id>
        <no>NOC0002</no>
        <name>Thinking inJava</name>
        <price>102.99</price>
        <writer>
            <name>zhang</name>
            <sex></sex>
        </writer>
        <time>2004.03.30</time>
    </product>
    <product category="WEB">
        <id>1003</id>
        <no>NOC0003</no>
        <name>WEB高级开发教程</name>
        <price>78.99</price>
        <writer>
            <name>zhang</name>
            <sex></sex>
        </writer>
        <time>2012.07.30</time>
    </product>
</producttype>

具体某些函数的用法可以参考该网站
Module tree from libxml2 http://xmlsoft.org/html/libxml-tree.html

附上求时间差的函数

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tim_subtract.h"

int tim_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
    //int nsec;
    if (x->tv_sec > y->tv_sec)
        return -1;
    if ((x->tv_sec == y->tv_sec) && (x->tv_usec > y->tv_usec))
        return -1;
    result->tv_sec = (y->tv_sec - x->tv_sec);
    result->tv_usec = (y->tv_usec - x->tv_usec);
    if (result->tv_usec < 0)
    {
        result->tv_sec--;
        result->tv_usec += 1000000;
    }
return 0;

其中tv_sec单位是秒,tv_usec单位是微秒

猜你喜欢

转载自blog.csdn.net/qq_27437671/article/details/78500598