上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup;

  CMarkup:xml解析器,目前内置支持三种编码格式:UTF8、UNICODE、ASNI,默认为UTF8;CMarkupNode:xml节点类

  先介绍CMarkup:

  XMLELEMENT: xml节点元素类型定义,iStart,节点元素在xml文件中的起始位置;iChild,节点元素子节点;iNext,节点元素的下一个节点(兄弟节点);iParent,节点元素的父节点;iData,

  节点元素的数据(事实上,这些值均为ULONG类似,即unsigned long;存储的值为当前数据在内存缓冲区m_pstrXML中指向的位置)。

  CMarkupNode作为CMarkup的友元类,意味着可以访问CMarkup的各成员函数和数据属性,事实上后期的遍历xml就是结合CMarkupNode的GetSibling和GetChild实现的。

  类成员数据:

    m_pstrXML:为CMarkup存储的以加载xml文件数据内容的指针缓冲区;

    m_pElements:保存XMLELEMENT类型的节点元素信息的缓冲区,事实上可能有部分未预料的存储空间;

    m_nElements:实际的保存m_pElements中有效的节点元素数;

    m_nReservedElements:预留的m_pElements缓冲区空间大小,具体策略为:m_nElements >= m_nReservedElements ) {m_nReservedElements += (m_nReservedElements / 2)

                 + 500;m_pElements = static_cast<XMLELEMENT*>(realloc(m_pElements, m_nReservedElements * sizeof(XMLELEMENT)));

    m_szErrorMsg:最近一次解析时的错误信息;

    m_szErrorXML:最近一次解析时的xml位置信息;

    m_bPreserveWhitespace:是否跳过忽略空格,默认是忽略;

  类成员函数:

    Load:通过参数pstrXML,传入xml文件内容的方式解析,内部主要是分配m_pstrXML缓冲区并拷贝pstrXML内容,后通过_Parse解析;

    LoadFromMem:通过加载内存资源方式解析,内部通过宏处理时限宽字节unicode和多字节编译时定义处理解析,最终也是分配m_pstrXML缓冲区并拷贝该内存数据内容,后通过_Parse解析;

    LoadFromFile:通过参数pstrFilename文件路径名,可以是xml文件或是压缩文件(内部为xml文件),对于xml文件或是压缩文件处理读取内部数据至临时内存缓冲区中(解压缩采用的是ZIP_INFO

    的cpp实现方式便于接口调用,参见duilib目录文件XUnzip.cpp)并再次通过调用LoadFromMem加载解析;

    Release:主要用以释放m_pstrXML和m_pElements缓冲区资源;

    IsValid:当前解析是否有效,通过m_pElements != NULL判断;

    SetPreserveWhitespace:设置m_bPreserveWhitespace是否忽略解析中字符串的空格,

    GetLastErrorMessage:获取m_szErrorMsg的最近一次解析时的错误信息;

    GetLastErrorLocation:获取m_szErrorXML的最近一次解析时的xml位置信息;

    GetRoot:获取根节点CMarkupNode,CMarkupNode(this, 1),以当前为第一个节点的节点对象;

    _ReserveElement:分配足够的预留空间;

    _Parse:分配预留空间、初始化m_szErrorMsg、m_szErrorXML,并调用重载函数_Parse,执行真正的解析过程;

    _SkipWhitespace:重载版本均处理、跳过字符串空格;

    _SkipIdentifier:重载版本均均处理、跳过标志符号如:‘_’, ‘:’ ;

    _ParseData:解析元素属性中数据;

    _ParseMetaChar:解析元字符,如:'&', '<','>','\"','\'','&'与'a', 'm', 'p', 't', ';'等相关组合字符串;

    _ParseAttributes:解析元素属性;

    _Failed:保存解析中产生最近一次的错误信息、位置,m_szErrorMsg、m_szErrorXML;

  接下来CMarkupNode:

  XMLATTRIBUTE:节点属性结构体定义,iName为属性名,iValue为属性值均为ULONG类型;

  MAX_XML_ATTRIBUTES:节点支持最多64个属性个数;

  类成员数据:

    m_aAttributes:节点属性列表(节点属性数组,保存数据类似于键值对的方式);

    m_iPos:指定该属性节点在所属拥有者(指CMarkup对象)中的节点元素中的当前位置(事实上其节点元素也为指针数组保存);

    m_nAttributes:节点中属性数;

    m_pOwner:该节点所属拥有者(指CMarkup对象);

  类成员函数:

    CMarkupNode:重载版构造函数,其中一个以CMarkup对象和当前所属节点所在位置初始化m_iPos;

    IsValid:当前节点是否有效,其通过m_pOwner != NULL判断;

    GetParent:获取当前节点的父节点node,事实上是通过创建一个CMarkupNode(m_pOwner, iPos),作为其父节点,iPos为当前节点的iParent值;

    GetSibling:获取当前节点的下一个节点(兄弟节点),同GetParent一样,iPos为当前节点的iNext值;

    GetChild:获取当前节点的子节点,iPos为当前节点的iChild值;另外重载版本GetChild,参数为pstrName,遍历当前节点所有子节点与pstrName匹配的节点;

    HasSiblings:是否有兄弟节点;

    HasChildren:是否有子节点;

    GetName:获取当前节点名字;

    GetValue:获取当前节点值;

    HasAttributes:当前节点是否有属性,通过m_nAttributes > 0判断;其重载版本HasAttribute,参数pstrName,判断遍历当前节点的所有属性有与pstrName匹配的;

    GetAttributeCount:同HasAttributes,通过m_nAttributes判断;

    GetAttributeName:获取属性名,参数iIndex为指定的属性索引;

    GetAttributeValue:获取属性值,有四个重载版本,其中一个版本为参数iIndex,属性索引;一个版本pstrName参数为属性名;另外两个版本差不多,只是返回值以输入输出参;

    _MapAttributes:最为核心的属性映射处理函数,内部主要遍历解析当前节点中各属性及值,并存入m_aAttributes中并更新m_nAttributes值;

  最后说明:

    1. 从代码中可以看出,CMarkup存储了一份整个文件的内容,另外也保存了各个元素节点,并未对各个元素节点的属性单独存储,即并未存储CMarkupNode;

     此外在源码中可以看出很多操作都会执行_MapAttributes,好在该遍历映射不会很大,控制在最多64个属性;

    2. 加载zip压缩资源文件时,可以使用CachedResourceZip缓存资源,也可以直接使用的是ZIP-INFO的CPP版本(一个文件),使用到被宏重定义的接口:OpenZip、FindZipItem、UnzipItem、

     CloseZip;具体使用可参考XUnzip.cpp接口;默认使用的是OpenZip加载压缩资源文件。

  还记得源码分析(一)一节中,HandleMessage处理函数中消息WM_CRAETE处理过程吗?

    1. CDialogBuilder构建各控件对象并形成控件树,并返回第一个控件对象pRoot;

    2. m_pm.AttachDialog(pRoot);m_pm.AddNotifier(this);将控件attach到CPaintManagerUI  m_pm中管理,此外INotifyUI子类对象被加入到m_pm;这样m_pm不仅管理控件对象

     也对消息监听接口Notify回调,这样用户可以在Notify中实现自己的感兴趣的消息映射处理,其Notify(TNotifyUI& msg)中的参数为通告消息msg;

  事实上我们主要需要弄清楚三点:一是如何绘制、二是数据如何处理、三是消息如何流转;接下来下一节将对控件绘制和消息流转进行分析。

  

    

    

    

    

Duilib源码分析(三)XML解析器—CMarkup的更多相关文章

  1. springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)

    之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...

  2. springMVC源码分析--ViewResolver视图解析器(一)

    SpringMVC用于处理视图最重要的两个接口是ViewResolver和View.ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对 ...

  3. springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)

    HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数,其实现类特别的多. HandlerMe ...

  4. Duilib源码分析(四)绘制管理器—CPaintManagerUI—(前期准备三)

    接下来,我们将继续分析UIlib.h文件中其他的文件, UIContainer.h, UIRender.h, WinImplBase.h, UIManager.h,以及其他布局.控件等: 1. UIR ...

  5. Duilib源码分析(四)绘制管理器—CPaintManagerUI—(前期准备二)

    接下来,我们继续分析UIlib.h文件中余下的文件,当然部分文件可能顺序错开分析,这样便于从简单到复杂的整个过程的里面,而避免一开始就出现各种不理解的地方. 1. UIManager.h:UI管理器, ...

  6. Duilib源码分析(四)绘制管理器—CPaintManagerUI—(前期准备四)

    接下来,分析uilib.h中的WinImplBase.h和UIManager.h: WinImplBase.h:窗口实现基类,已实现大部分的工作,基本上窗口类均可直接继承该类,可发现该类继承于多个类, ...

  7. Duilib源码分析(四)绘制管理器—CPaintManagerUI—(前期准备一)

    上节中提到在遍历创建控件树后,执行了以下操作:      1. CDialogBuilder构建各控件对象并形成控件树,并返回第一个控件对象pRoot:     2. m_pm.AttachDialo ...

  8. Duilib源码分析(四)绘制管理器—CPaintManagerUI

    接下来,分析uilib.h中的UIManager.h,在正式分析CPaintManagerUI前先了解前面的一些宏.结构: 枚举类型EVENTTYPE_UI:定义了UIManager.h中事件通告类型 ...

  9. Duilib源码分析(六)整体流程

    在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...

随机推荐

  1. thinkphp3.2.3中U()方法和redirect()方法区别

    今天博主看3.1的教程,学着3.2,就遇到了这个坑,怎么就是不跳转呢,很纳闷!! 在thinkphp3.1 中 U()方法是可以执行跳转的(看视频教程里面是可以的,博主没有测试过). 但是在think ...

  2. layer弹出框小结

    1.layer.open() // 1.打开弹出层 layer.open({ type:1, //基本层类型 icon:, //图标 content:'请核对信息!', //内容 shade:0.3, ...

  3. HTTP 基础知识

    HTTP是一种协议.HTTP使用流程,一般情况下, 第一:由HTTP客户端发出请求,创建端口. 第二:HTTP服务器在端口监听客户端的请求. 第三:一旦收到请求,HTTP服务器向客户端返回状态和内容. ...

  4. video.js-H5视频播放库

    video.js是一款很流行的html5视频播放插件.很适合在移动端播放视频(比如微信网页),功能强大,且支持降级到flash,兼容ie8.官网:http://videojs.com/    git& ...

  5. pip 与pip3

    pip 3用于python3 版本 pip2 用于python2版本 pip好像可以通用 "pip2" is for Python2, "pip3″ is for Pyt ...

  6. 分享公司Basecode的用法

    主题 公司在basecode的用法上是比较有新意的,所以准备记录分享下公司的用法. 说明 basecode公司的一个主要用途就是用于一些基础的代码表,参数表的前台操作.这些表有很多,用spring d ...

  7. lcov和gcov的使用错误

    编译使用的gcc版本和gcov的版本对不上的话,使用lcov和gcov的时候会报错 lcov的错误: [xx@localhost XXX]$ lcov --capture --directory co ...

  8. 思考JavaScript异常如何转为知识库?

    线上 js 报错会变成一个邮件,发给前端开发 team,每个人自己认领.解决.其实这是一个不错的选择,也解决了最基本的问题:立即响应,修掉.不过也存在着一个问题,如何避免同样的错误?我的初步想法是这样 ...

  9. HTTP 错误 500.21 - Internal Server Error 解决方案

    不久前重新安装了Windows7,在安装了VS2010 开发平台之后,将网站发布到IIS,访问发生如下错误: HTTP 错误 500.21 - Internal Server Error处理程序“Ni ...

  10. FTP下载文件失败

    这几天的定时任务下载文件的脚本失败了. 于是手工执行测试,发现报550 Permission denied. Passive mode refused. 意思就是被动模式下,没有权限获取文件. 解决方 ...