• tinyxml 代码解读


    tinyxml 代码解读:

    tinyxml 是开源c++软件, 递归代码的特点: 易写易读难调.

    甲:分析一下Doc.Print() 函数

    Print()函数是一个重载函数,每个对象都有自己的Print() 函数.

    doc print, 就是把每个结点都print 一遍。
    void TiXmlDocument::Print( FILE# cfile, int depth ) const
    {
    for ( const TiXmlNode# node=FirstChild(); node; node=node->NextSibling() )
    {
    node->Print( cfile, depth );
    fprintf( cfile, “\n” );
    }
    }

    声明,注释,文本都是结点,这些结点打印很简单,打印出来就可以了。

    1. 声明的打印: 是一个virtual 虚函数,打印出保留的version,encoding,alone就可以了。

    2. 注释的打印: 是一个virtual 虚函数,打印出保留的text 就可以了, text 就保存在node 的 value 中

    3. 文本的打印: 是一个virtual 虚函数,打印出保留的text 就可以了, text 就保存在node 的 value 中

    4. 元素结点的打印

    这是关键,因为它牵扯到递归。也牵扯属性, 代码写的看起来很简单,因为是递归,调试起来比较复杂.
    分析:
    4.1. 首先根据depth 深度打印空格
    4.2. 然后打印元素开始<加value
    4.3. 如果有属性,再打印属性
    4.4. 如果没有child,则打印 /> 结束
    4.5. 如果有child, 如果child结点不包含文本,则先打印一个回车,再打印child 结点,深度会加1(这里是递归)
    4.6. 打印换行后再打印对齐空格,再打印尾巴来结束
    这里面对于只有一个child 的情况,有一个打印上的优化,少打一个回车使看起来更舒服.

    5. 属性的打印.

    属性不是一个node. 所以它不在上面doc.Print 的循环中,但它是元素的属性
    属性是键值对,打印它的name,value即可,value需要用双引号括起来, 如果value中包含双引号,那就用单引号括起来。

    乙:分析一下Doc.Parse() 函数

    while ( p && #p )
    	{
    		TiXmlNode# node = Identify( p, encoding );		// 先判断出是哪种类型的结点. 都用其基类TiXmlNode来指向具体的类型
    		if ( node )
    		{//Parse 是基类TiXmlBase的虚函数(接口函数),  TiXmlNode 并无Parse函数,但具体的Node类型实现了Pase函数
    			p = node->Parse( p, &data, encoding );  
    			LinkEndChild( node );			//把分析到的node 链接起来
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1. Identify() 是如何判定类型的.

    首先必需以< 开头, 然后以

    2. 各种类型的分析

    2.1 : 声明的分析. 它需要调用属性分析,分析出version,encoding,standalone的值
    2.2 : 注释的分析. 它把 为止所有的东西都保存到value中
    2.3 : 元素的分析.
    2.3.1: 首先它要读取名字到value中
    2.3.2: 如果后面跟的是/> ,则结束分析,返回
    2.3.3: 如果后面跟的是> ,则要读取value 到 data,然后后面应该是endtag及>否则格式错误
    2.3.4: 否则跟的是属性, 则读取属性,并把属性加到属性集中,再继续分析.

    3. 属性的读取:

    声明一个属性对象,然后进行分析.
    读取名字ReadName(),然后碰到一个’=',然后读取文本ReadText(), 分别存储到name 和 value

    4. value的读取 ReadValue()

    4.1 如果不是<开始,则说明是一个文本,
    	TiXmlText# textNode = new TiXmlText( "" ); 
    	p = textNode->Parse( p, data, encoding );
    	LinkEndChild( textNode );
    4.2 是< 开始, 递归调用. 得到一个结点表示,分析
    	TiXmlNode# node = Identify( p, encoding );
    	p = node->Parse( p, data, encoding );
    	LinkEndChild( node );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    参考代码:

    #include 
    #include 
    using namespace std;
    
    #include "tinyxml.h"
    
    int main()
    {
    	const char* demoStart =
    		"\n"
    		""
    		"\n"
    		"\n"
    		" 游香山   "
    		" 逛故宫 "
    		"长城 "
    		"";
    
    	//代码简单,跟踪调试才是硬道理!
    	TiXmlDocument doc( "demotest.xml" ); //创建一个文档,名称为demotest.xml
    	doc.Parse( demoStart ); //将字符串分析进该文档,成为一个个结点 (递归分析,比较麻烦!)
    
    	if ( doc.Error() )
    	{
    		printf( "Error in %s: %s\n", doc.Value(), doc.ErrorDesc() );
    		exit( 1 );
    	}
    	doc.Print();  //文档向屏幕输出, 递归打印!(比较麻烦)
    //	doc.SaveFile(); //保留文档到文件
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Go运行时hacking
    Tomcat知识点(深入剖析Tomcat学习笔记)
    presto框架【博学谷学习记录】
    【ELK使用指南 2】常用的 Logstash filter 插件详解(附应用实例)
    安装rsa依赖库出现ERROR: No matching distribution found for rsa
    初识深度学习
    【硬核】把一个MOS管制作成开关电路
    MySQL安装常见报错处理大全
    代码随想录算法训练营第二十八天|LeetCode93 复原IP地址、LeetCode78 子集
    Linux Makefile配置问题
  • 原文地址:https://blog.csdn.net/hejinjing_tom_com/article/details/127846914