设为首页 加入收藏

TOP

libmxml数据结构(源码分析)(一)
2019-04-05 22:08:16 】 浏览:170
Tags:libmxml 数据结构 源码 分析

  libmxml是一个开源、小巧的C语言xml库。这里简单分析一下它是用什么样的数据结构来保存分析过的xml文档。

  mxml关键的结构体mxml_node_t是这样的实现的:

struct mxml_node_s            /**** An XML node. @private@ ****/
{
  mxml_type_t        type;        /* Node type */
  struct mxml_node_s    *next;        /* Next node under same parent */
  struct mxml_node_s    *prev;        /* Previous node under same parent */
  struct mxml_node_s    *parent;    /* Parent node */
  struct mxml_node_s    *child;        /* First child node */
  struct mxml_node_s    *last_child;    /* Last child node */
  mxml_value_t        value;        /* Node value */
  int            ref_count;    /* Use count */
  void            *user_data;    /* User data */
};

typedef struct mxml_node_s mxml_node_t;    /**** An XML node. ****/

  

   它使用左孩子右兄弟的树形结构来描述xml报文:即下层节点登记在child链表,兄弟节点登记在next链表。 如果某个节点下面有N个子节点,则child指向第一个子节点,该子节点的next指向下一个同父节点的子节点。  比较特殊的是,mxml把xml节点值也认为是一个子节点。例如<group>value</group>, 其中value(type是MXML_OPAQUE)是一个独立的子节点,挂载在group节点(type是MXML_ELEMENT)下面。  另外,空白符(空格,回车换行,制表符)和注释,虽然对xml报文无实质意义,但mxml还是把它们做为一个节点存储起来。

  由于mxml只是使用简单的链表存储xml元素,所以元素节点个数比较多时,mxml查找元素效率是比较低的。所以libmxml提供了一个索引查找的函数,它需要先遍历xml元素树,生成一个排序过的数组,加快查找速度。

   为了方便大家理解,我写了一个函数打印xml结构体。

 

void printNode(mxml_node_t *node, int nNodeSn, int level)
{
    static int currNodeSn = 0;
    if (node == NULL)
    {
        return;
    }

    ++currNodeSn; //每遇到一个新节点 则将节点序号递增,做为本节点序号
    printf("[%- 3d -> %- 3d] ", currNodeSn, nNodeSn);

    switch (node->type)
    {
    case MXML_ELEMENT:
        {
            int i;
            printf("level %d MXML_ELEMENT [%s]", level, node->value.element.name);
            for (i = 0; i < node->value.element.num_attrs; ++i)
            {
                printf(" %s=%s", node->value.element.attrs[i].name, node->value.element.attrs[i].value);
            }
            printf("\n");
        }
        break;
    case MXML_INTEGER:
        printf("level %d MXML_INTEGER %d\n", level, node->value.integer);
        break;
    case MXML_OPAQUE:
        printf("level %d MXML_OPAQUE [%s]\n", level, node->value.opaque);
        break;
    case MXML_REAL:
        printf("level %d MXML_REAL %lf\n", level, node->value.real);
        break;
    case MXML_TEXT:
        printf("level %d MXML_TEXT [%s]\n", level, node->value.text.string);
        break;
    case MXML_CUSTOM:
        printf("level %d MXML_CUSTOM\n", level);
        break;
    default:
        printf("unknown node type %d\n", node->type);
    }

    //深度优先遍历
    if (node->child)
    {
        //访问子节点时把本节点序号做为父节点序号 层级加1
        printNode(node->child, currNodeSn, level + 1);
    }

    if (node->next)
    {
        //访问兄弟节点,直接传父节点序号即可 层级也不用加1
        printNode(node->next, nNodeSn, level);
    }
}

  运行示例如下:

  xml源如下:

<?xml version="1.0" encoding="GBK" ?>
<group>
    <option>122334 我们
        <string>我们</string>45677
        <keyword type="opaque">InputSlot</keyword>
        <default type="opaque">Auto</default>
        <text>Media Source</text>
        <order type="real">10.000000</order>
        <choice>
            <keyword type="opaque">Auto</keyword>
            <text>Auto Tray Selection</text>
            <code type="opaque" />
        </choice>
        <choice>
            <keyword type="opaque">Upper</keyword>
            <text>Tray 1</text>
            <code type=&q  
		
编程开发网
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇#leetcode刷题之路44-通配符匹配 下一篇Gym100025K