理解DOM树

 

理解DOM树能更好的理解libxml函数操作原理。只要理解的,才是深刻的,能做到知其然而知其所以然,使用函数时心里有底而且不易出错。为了大家更好理解DOM树在内存中的构造,我特地写了一个典型XML文件(dom.xml),并且画出其DOM树内存构造图。其后提供了一个不用XML库,查找XML节点和属性的通用程序(dom_xml.c),此程序具有较好的实用性。

1.dom.xml文件

dom.xml文件内容如下:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<Format FmtName="FMT_DXPT_DX0001_IN"

        FmtDesc="dxpt fmt"

        Fmttype="string">

        <meta>

                <hello>first</hello>

                <good>second</good>

                <gold>third</gold>

        </meta>

        <meta1>

                <what>why</what>

        </meta1>

</Format>

 

2.dom.xml形成的DOM树

xmlNode(Format)表示这片内存空间类型为xmlNode, 元素名称为Format。

xmlNodePtr为xmlNode *的重定义,即xmlNode的指针重定义。

下图20-1形象的说明dom.xml在内存中如何形成DOM树的。

图20-1 DOM树实例图

3.得到XML节点和属性的通用程序

dom_xml.c源代码如下:

#include <stdio.h>

#include <stddef.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

#include <assert.h>

#include <libxml/xmlmemory.h>

#include <libxml/parser.h>

#include <libxml/xpath.h>

/*项目中数字最好用宏代替*/

struct XML_attr {

    char attr_name[30+1] ;

    char attr_value[100+1] ;

} ;

struct XML_node{

    char node_name[30+1] ;

    char node_value[100+1] ;

} ;

/*------------------------------------------------------------------------

 * Function Name : get_xml_attr

 * Description   : 得到节点的所有属性

 * Input         : node_ptr   -- 当前节点

 *               : xml_attr   -- 存储属性名称和属性值

 *               : maxnum     -- 最大属性个数

 *Output         : xml_attr   -- 存储属性名称和属性值 

 * Return        : 0  --  Success

 *                 -1  --  Failure

 *------------------------------------------------------------------------*/

int get_xml_attr( xmlNodePtr node_ptr, struct XML_attr xml_attr[], int maxnum)

{

        xmlAttr       *attr;

        int  i = 0;

        attr = node_ptr->properties;

        while( attr != NULL ) {

                if ( attr->children == NULL ) {

                        attr = attr->next;

                        continue;

                }

                strncpy( xml_attr[i].attr_name, ( char * )attr->name, 30 );

                strncpy( xml_attr[i].attr_value, ( char * )attr->children->content, 100 );

                attr = attr->next;

                i++ ;

                if ( i > maxnum)

                {

                    printf("xml attr over limit num\n");

                    return -1 ;

                }

        }

    return 0 ;

}

/*------------------------------------------------------------------------

 * Function Name : get_xml_node

 * Description   : 得到节点的所有属性

 * Input         : node_ptr   -- 当前节点

 *               : xml_node   -- 存储元素名称和值

 *               : maxnum     -- 最大元素个数

 *Output         : xml_node   -- 存储元素名称和值 

 * Return        : 0  --  Success

 *                 -1  --  Failure

 *------------------------------------------------------------------------*/

int get_xml_node( xmlNodePtr node_ptr, struct XML_node xml_node[], int maxnum)

{

        xmlNodePtr        cur;

        int  i = 0;

        cur = node_ptr->children;

        while( cur != NULL ) {

                if ( cur->children == NULL ) {

                        cur = cur->next;

                        continue;

                }

strncpy( xml_node[i].node_name, ( char * )cur->name, 30 );

                strncpy( xml_node[i].node_value, ( char * )cur->children->content, 100 );

                cur = cur->next;

                i++ ;

                if ( i > maxnum)

                {

                    printf("xml node over limit num\n");

                    return -1 ;

                }

        }

    return 0 ;

}

/*

 *    Function Name: get_xml_node_ptr

 *    Description  : 获取子节点指针

 *    Input        : node_ptr -- 结点指针

 *                 : node_name -- 结点名 

 *    Output       : node_ptr -- 子节点指针 

 *    Return       : 0  --  Success

 *                   -1  --  Failure

 */

int get_xml_node_ptr( xmlNodePtr node_ptr , char *node_name )

{

    xmlNodePtr    cur;

    cur = node_ptr;

    while( cur != NULL ) {

        if( ( xmlStrcmp( cur->name, node_name ) ) == 0 )

        {

            break;

        }

        else

           cur = cur->next;

    }

    if( cur == NULL ) {

        return -1;

    }

    node_ptr = cur;

    return 0 ;

}

int main()

{

    char value[128];

    int ret;

    int i ;

    xmlDocPtr doc;

    xmlNodePtr cur;

    xmlNodePtr attr;

    xmlNodePtr node;

    struct XML_attr fmt_attr[3] ;

    struct XML_node meta_node[3] ;

    memset(fmt_attr, 0x00, sizeof(fmt_attr)) ;

    memset(meta_node, 0x00, sizeof(meta_node)) ;

    doc = xmlParseFile("dom.xml");

    if (doc == NULL ) {

            fprintf(stderr,"Document not parsed successfully. \n");

            return (-1);

    }

    cur = xmlDocGetRootElement(doc);

    if (cur == NULL) {

            fprintf(stderr,"empty document\n");

            xmlFreeDoc(doc);

            return (-1);

    }

    attr = cur ;

    ret=get_xml_attr(attr, fmt_attr, 3) ;

    assert(!ret);

    for(i=0; i<3; i++)

    {

        printf("attr_name[%d]=%s, attr_value[%d]=%s\n",i,fmt_attr[i].attr_name,i,fmt_attr[i].attr_value);

    }

   node=cur->children ;

   ret = get_xml_node_ptr( node , "meta" ) ;

   assert(!ret);

   node=cur->children->next ;

   ret =get_xml_node(node, meta_node, 3) ;

   assert(!ret);

    for(i=0; i<3; i++)

    {

        printf("node_name[%d]=%s, node_value[%d]=%s\n",i,meta_node[i].node_name,i,meta_node[i].node_value);

    }

    xmlFreeDoc(doc);

    return 0;

}

编译 gcc dom_xml.c -o dom_xml -I/usr/local/include/libxml2 -lxml2。

执行 ./dom_xml,执行结果如下:

attr_name[0]=FmtName, attr_value[0]=FMT_DXPT_DX0001_IN

attr_name[1]=FmtDesc, attr_value[1]=dxpt fmt

attr_name[2]=Fmttype, attr_value[2]=string

node_name[0]=hello, node_value[0]=first

node_name[1]=good, node_value[1]=second

node_name[2]=gold, node_value[2]=third

 

摘录自《深入浅出Linux工具与编程》

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值