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. 打印换行后再打印对齐空格,再打印尾巴</加value加>来结束
这里面对于只有一个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. Identify() 是如何判定类型的.

首先必需以< 开头, 然后以 <?xml 开始,表示是一个声明 <!-- 开始,表示是一个注释 <! 开始,表示是一个Dtd
头 <![CDATA[" 开始, 表示是一个cdata头 后两种不太常见, 其它类型alpha字母及下划线开始就是XML元素,例如:
<Item 非此类型就是unkown类型的

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 );

参考代码:

#include <iostream>
#include <sstream>
using namespace std;

#include "tinyxml.h"

int main()
{
	const char* demoStart =
		"<?xml version=\"1.0\"  standalone='no' >\n"
		"<!-- ToDo is the root element, it must be exist -->"
		"<ToDo>\n"
		"<!-- Do I need </Item to end element ? -->\n"
		"<Item priority=\"2\" distance='middle' time='星期1'> 游香山   </Item>"
		"<Item priority=\"1\" distance='short' time='星期2'> 逛故宫 </Item>"
		"<Item priority=\"1\" distance='far' time='星期3'> 去 <bold>长城</bold> </Item>"
		"</ToDo>";

	//代码简单,跟踪调试才是硬道理!
	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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值