时隔5个月才有时间接着写未完成的实现部分,也是惭愧呀

选几个关机的函数来解析,一些get方法就忽略掉吧

CMarkupNode 与 CMarkUp 互为友元类,CMarkUp 实现解析,CMarkupNode 用于存储读取节点数据

 void CMarkupNode::_MapAttributes()
{
m_nAttributes = ;
LPCTSTR pstr = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart;
LPCTSTR pstrEnd = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData;
pstr += _tcslen(pstr) + ;
while( pstr < pstrEnd ) {
m_pOwner->_SkipWhitespace(pstr);
m_aAttributes[m_nAttributes].iName = pstr - m_pOwner->m_pstrXML;//位移
pstr += _tcslen(pstr) + ;
m_pOwner->_SkipWhitespace(pstr);
if( *pstr++ != _T('\"') ) return; // if( *pstr != _T('\"') ) { pstr = ::CharNext(pstr); return; } m_aAttributes[m_nAttributes++].iValue = pstr - m_pOwner->m_pstrXML;//位移
if( m_nAttributes >= MAX_XML_ATTRIBUTES ) return;
pstr += _tcslen(pstr) + ;
}
}

这个函数的主要作用是将已经处理过的xml文件进行数据分割保存,这里保存的属性名和属性值都是xml在内存中的位移,最大属性支持64个

接下来详细说明CMarkUp类

有几个用于加载xml文件的函数:

bool CMarkup::Load(LPCTSTR pstrXML)//直接解析字符串

bool CMarkup::LoadFromMem(BYTE* pByte, DWORD dwSize, int encoding)//将二进制数据流转换为字符串再解析

bool CMarkup::LoadFromFile(LPCTSTR pstrFilename, int encoding)//解析xml文件,根据文件名解析,先判断资源是否被打包到zip压缩包中

 bool CMarkup::_Parse()//解析入口, 先拓展节点保证有足够的节点存储,然后解析
{
_ReserveElement(); // Reserve index 0 for errors
::ZeroMemory(m_szErrorMsg, sizeof(m_szErrorMsg));
::ZeroMemory(m_szErrorXML, sizeof(m_szErrorXML));
LPTSTR pstrXML = m_pstrXML;
return _Parse(pstrXML, );
}
 CMarkup::XMLELEMENT* CMarkup::_ReserveElement()//拓展节点数
{
if( m_nElements == ) m_nReservedElements = ;
if( m_nElements >= m_nReservedElements ) {
m_nReservedElements += (m_nReservedElements / ) + ;
m_pElements = static_cast<XMLELEMENT*>(realloc(m_pElements, m_nReservedElements * sizeof(XMLELEMENT)));//这里的realloc函数会将原来的内容复制到新申请的内存中
}
return &m_pElements[m_nElements++];
}
 bool CMarkup::_Parse(LPTSTR& pstrText, ULONG iParent)
{
_SkipWhitespace(pstrText);//跳过空格
ULONG iPrevious = ;
for( ; ; )
{
if( *pstrText == _T('\0') && iParent <= ) return true;//退出条件,到结尾,或者无父节点
_SkipWhitespace(pstrText);
if( *pstrText != _T('<') ) return _Failed(_T("Expected start tag"), pstrText);
if( pstrText[] == _T('/') ) return true;
*pstrText++ = _T('\0');
_SkipWhitespace(pstrText);
// Skip comment or processing directive 跳过注释(<- ->)或指令(<? ?>)
if( *pstrText == _T('!') || *pstrText == _T('?') ) {
TCHAR ch = *pstrText;
if( *pstrText == _T('!') ) ch = _T('-');
while( *pstrText != _T('\0') && !(*pstrText == ch && *(pstrText + ) == _T('>')) ) pstrText = ::CharNext(pstrText);
if( *pstrText != _T('\0') ) pstrText += ;
_SkipWhitespace(pstrText);
continue;
}
_SkipWhitespace(pstrText);
// Fill out element structure
XMLELEMENT* pEl = _ReserveElement();
ULONG iPos = pEl - m_pElements;
pEl->iStart = pstrText - m_pstrXML;
pEl->iParent = iParent;
pEl->iNext = pEl->iChild = ;
if( iPrevious != ) m_pElements[iPrevious].iNext = iPos;
else if( iParent > ) m_pElements[iParent].iChild = iPos;
iPrevious = iPos;
// Parse name
LPCTSTR pstrName = pstrText;
_SkipIdentifier(pstrText);
LPTSTR pstrNameEnd = pstrText;
if( *pstrText == _T('\0') ) return _Failed(_T("Error parsing element name"), pstrText);
// Parse attributes
if( !_ParseAttributes(pstrText) ) return false; //解析属性
_SkipWhitespace(pstrText);
if( pstrText[] == _T('/') && pstrText[] == _T('>') ) //结尾是/>情况
{
pEl->iData = pstrText - m_pstrXML; //保存节点的结尾位移
*pstrText = _T('\0');
pstrText += ;
}
else //结尾是>情况
{
if( *pstrText != _T('>') ) return _Failed(_T("Expected start-tag closing"), pstrText);
// Parse node data
pEl->iData = ++pstrText - m_pstrXML;
LPTSTR pstrDest = pstrText;
if( !_ParseData(pstrText, pstrDest, _T('<')) ) return false;//找到<符号
// Determine type of next element
if( *pstrText == _T('\0') && iParent <= ) return true; //如果是结尾则返回
if( *pstrText != _T('<') ) return _Failed(_T("Expected end-tag start"), pstrText);
if( pstrText[] == _T('<') && pstrText[] != _T('/') )
{
if( !_Parse(pstrText, iPos) ) return false; //递归解析子节点
}
if( pstrText[] == _T('<') && pstrText[] == _T('/') ) //处理</>情况
{
*pstrDest = _T('\0');
*pstrText = _T('\0');
pstrText += ;
_SkipWhitespace(pstrText);
SIZE_T cchName = pstrNameEnd - pstrName;
if( _tcsncmp(pstrText, pstrName, cchName) != ) return _Failed(_T("Unmatched closing tag"), pstrText);
pstrText += cchName;
_SkipWhitespace(pstrText);
if( *pstrText++ != _T('>') ) return _Failed(_T("Unmatched closing tag"), pstrText);
}
}
*pstrNameEnd = _T('\0');
_SkipWhitespace(pstrText);
}
}
 void CMarkup::_SkipWhitespace(LPCTSTR& pstr) const
{
while( *pstr > _T('\0') && *pstr <= _T(' ') ) pstr = ::CharNext(pstr);
} void CMarkup::_SkipWhitespace(LPTSTR& pstr) const
{
while( *pstr > _T('\0') && *pstr <= _T(' ') ) pstr = ::CharNext(pstr);
} void CMarkup::_SkipIdentifier(LPCTSTR& pstr) const
{
// 属性只能用英文,所以这样处理没有问题
while( *pstr != _T('\0') && (*pstr == _T('_') || *pstr == _T(':') || _istalnum(*pstr)) ) pstr = ::CharNext(pstr);
} void CMarkup::_SkipIdentifier(LPTSTR& pstr) const
{
// 属性只能用英文,所以这样处理没有问题
while( *pstr != _T('\0') && (*pstr == _T('_') || *pstr == _T(':') || _istalnum(*pstr)) ) pstr = ::CharNext(pstr);
} bool CMarkup::_ParseAttributes(LPTSTR& pstrText)
{
if( *pstrText == _T('>') ) return true;
*pstrText++ = _T('\0');
_SkipWhitespace(pstrText);
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('/') ) {
_SkipIdentifier(pstrText); //跳过属性名
LPTSTR pstrIdentifierEnd = pstrText;
_SkipWhitespace(pstrText); //跳过空白
if( *pstrText != _T('=') ) return _Failed(_T("Error while parsing attributes"), pstrText);
*pstrText++ = _T(' '); //'='也赋值为空格
*pstrIdentifierEnd = _T('\0');
_SkipWhitespace(pstrText);
if( *pstrText++ != _T('\"') ) return _Failed(_T("Expected attribute value"), pstrText);//必须为双引号
LPTSTR pstrDest = pstrText;
if( !_ParseData(pstrText, pstrDest, _T('\"')) ) return false;//解析属性数据
if( *pstrText == _T('\0') ) return _Failed(_T("Error while parsing attribute string"), pstrText);
*pstrDest = _T('\0');
if( pstrText != pstrDest ) *pstrText = _T(' ');
pstrText++;
_SkipWhitespace(pstrText);
}
return true;
} bool CMarkup::_ParseData(LPTSTR& pstrText, LPTSTR& pstrDest, char cEnd)
{
while( *pstrText != _T('\0') && *pstrText != cEnd ) {
if( *pstrText == _T('&') ) {
while( *pstrText == _T('&') ) {
_ParseMetaChar(++pstrText, pstrDest);//解析同义字符&quot;等
}
if (*pstrText == cEnd)
break;
} if( *pstrText == _T(' ') ) {
*pstrDest++ = *pstrText++;
if( !m_bPreserveWhitespace ) _SkipWhitespace(pstrText);
}
else {
LPTSTR pstrTemp = ::CharNext(pstrText);
while( pstrText < pstrTemp) {
*pstrDest++ = *pstrText++;
}
}
}
// Make sure that MapAttributes() works correctly when it parses
// over a value that has been transformed.
LPTSTR pstrFill = pstrDest + ;
while( pstrFill < pstrText ) *pstrFill++ = _T(' ');//填充空格,比如存在&quot;情况
return true;
} void CMarkup::_ParseMetaChar(LPTSTR& pstrText, LPTSTR& pstrDest)
{
if( pstrText[] == _T('a') && pstrText[] == _T('m') && pstrText[] == _T('p') && pstrText[] == _T(';') ) {
*pstrDest++ = _T('&');
pstrText += ;
}
else if( pstrText[] == _T('l') && pstrText[] == _T('t') && pstrText[] == _T(';') ) {
*pstrDest++ = _T('<');
pstrText += ;
}
else if( pstrText[] == _T('g') && pstrText[] == _T('t') && pstrText[] == _T(';') ) {
*pstrDest++ = _T('>');
pstrText += ;
}
else if( pstrText[] == _T('q') && pstrText[] == _T('u') && pstrText[] == _T('o') && pstrText[] == _T('t') && pstrText[] == _T(';') ) {
*pstrDest++ = _T('\"');
pstrText += ;
}
else if( pstrText[] == _T('a') && pstrText[] == _T('p') && pstrText[] == _T('o') && pstrText[] == _T('s') && pstrText[] == _T(';') ) {
*pstrDest++ = _T('\'');
pstrText += ;
}
else {
*pstrDest++ = _T('&');
}
}

解析xml的基本原理就是,将xml加载到内存中,顺序解析节点,首先对节点进行存储,对xml进行改写(将<、>、/、"、'等改写为空格),获取节点

属性的时候进行分割存储。

简单举个例子会更清晰:

 <?xml version="1.0" encoding="utf-8"?>
<Window size="800,572" sizebox="4,4,6,6" roundcorner="5,5" caption="0,0,0,90" mininfo="800,570">
<Font name="宋体" size="13" bold="true" />
<VerticalLayout bkcolor="#FFD1E8F5" bkcolor2="#FFC6E0F1" bordercolor="#FF768D9B" bordersize="1" borderround="5,5" inset="1,0,1,0">
<HorizontalLayout>
<Container width="22" height="22" bkimage="file='icon.png' source='0,0,16,16' dest='5,4,21,20' " />
<Text text="360安全卫士7.3" pos="22, 5, 200, 24" float="true" textcolor="#FF447AA1" font="0" />
</HorizontalLayout>
</VerticalLayout>
</Window>

比如解析上述xml文件

 \0Window\0size\0 800,572\0 sizebox\0 4,4,6,6\0 roundcorner\0 \05,5\0 caption\0 0,0,0,90\0 mininfo\0 800,570\0>
\0Font\0name\0 宋体\0 size\0 13\0 bold\0 true\0 \0>
\0VerticalLayout\0bkcolor\0 #FFD1E8F5\0 bkcolor2\0 #FFC6E0F1\0 bordercolor\0 #FF768D9B\0 bordersize\0 1\0 borderround\0 5,5\0 inset\0 1,0,1,0\0>
\0HorizontalLayout\0>
\0Container\0 width\0 22\0 height\0 22\0 bkimage\0 file\0' icon.png' source='0,0,16,16' dest='5,4,21,20' \0 \0>
\0Text\0 text\0 360安全卫士7.3\0 pos\0 22, 5, 200, 24\0 float\0 true\0 textcolor\0 #FF447AA1\0 font\0 0\0 \0>
\0\0HorizontalLayout>
\0\0VerticalLayout>
\0\0Window>
 void CMarkupNode::_MapAttributes()
{
m_nAttributes = ;
LPCTSTR pstr = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart;
LPCTSTR pstrEnd = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData;
pstr += _tcslen(pstr) + ;
while( pstr < pstrEnd ) {
m_pOwner->_SkipWhitespace(pstr);
m_aAttributes[m_nAttributes].iName = pstr - m_pOwner->m_pstrXML;//位移
pstr += _tcslen(pstr) + ;
m_pOwner->_SkipWhitespace(pstr);
if( *pstr++ != _T('\"') ) return; // if( *pstr != _T('\"') ) { pstr = ::CharNext(pstr); return; } m_aAttributes[m_nAttributes++].iValue = pstr - m_pOwner->m_pstrXML;//位移
if( m_nAttributes >= MAX_XML_ATTRIBUTES ) return;
pstr += _tcslen(pstr) + ;
}
}

然后看获取属性的函数就一目了然了

DuiLib 源码分析之解析xml类CMarkup & CMarkupNode cpp文件的更多相关文章

  1. DuiLib 源码分析之解析xml类CMarkup & CMarkupNode 头文件

    xml使用的还是比较多的,duilib界面也是通过xml配置实现的 duilib提供了CMarkkup和CMarkupNode类解析xml,使用起来也是比较方便的,比较好奇它是怎么实现的,如果自己来写 ...

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

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

  3. Duilib源码分析(一)整体框架

    Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...

  4. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  5. 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 百篇博客分析OpenHarmony源码 | v53.02

    百篇博客系列篇.本篇为: v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应 ...

  6. v72.01 鸿蒙内核源码分析(Shell解析) | 应用窥伺内核的窗口 | 百篇博客分析OpenHarmony源码

    子曰:"苟正其身矣,于从政乎何有?不能正其身,如正人何?" <论语>:子路篇 百篇博客系列篇.本篇为: v72.xx 鸿蒙内核源码分析(Shell解析篇) | 应用窥视 ...

  7. Duilib源码分析(三)XML解析器—CMarkup

    上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup: CMarkup:xml解析器,目前内置支持三种编码格式:UTF8.UNICODE.ASNI,默认为UTF ...

  8. Spring Developer Tools 源码分析:二、类路径监控

    在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...

  9. MyBatis框架的使用及源码分析(四) 解析Mapper接口映射xml文件

    在<MyBatis框架中Mapper映射配置的使用及原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder> 一文中,我们知道mybat ...

随机推荐

  1. MonkeyTest简单实用介绍

    什么是Monkeytest? monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕.滑动Trackball.按键灯操作来对设备上的程序进行压力测试,检测程序发 ...

  2. U家面试prepare: Serialize and Deserialize Tree With Uncertain Children Nodes

    Like Leetcode 297, Serialize and Deserialize Binary Tree, the only difference, this is not a binary ...

  3. Webform Session Cookies状态保持

    Request对象的五个集合: ①.QueryString:用以获取客户端附在url地址后的查询字符串中的信息. 例如:stra=Request.QueryString ["strUserl ...

  4. 关于使用FusionCharts生成图表时出现invalid xml data错误提示的解决方法

    FusionCharts的确功能是够强大的.收集的功能估计更强大.在初次使用时,对着手册,一步一步操作,就是生成图表工具不成功.一直报"Invalid xml data"错误.后面 ...

  5. My Env

    Font -- YaHei Consolas Hybrid YaHei ConsolasAsume that we put the font file in /usr/share/fonts/myfo ...

  6. app推送中的通知和消息区别

    最近在做mqtt及其他消息推送的功能,推送服务挺多的,小米推,极光推,华为推,个推等,当然还有苹果的apns.感觉都差不多,尝试了apns,小米推和个推,各个厂家都提供的有sdk,demo. 关于通知 ...

  7. Qt编译安装qwt错误moc/xxx Error:126

    最近搞设计,需要在上位机上绘制曲线,在网上找了找,发现python的matplotlib和Qt的qwt都不错,本着难度最小原则,选择了Qt下面的qwt,安装过程中遇到了编译错误:moc/xxx Err ...

  8. CentOS6配置国内yum源

    在安装完CentOS后为了加快安装.更新rpm包的速度.需要将yum源改为国内源,国内比较快的源有中科大.163.sohu源.下面修改为163源为例子: 首先进入源的配置目录:执行 cd /etc/y ...

  9. JavaScript随笔目录

    DOM DOM节点 浏览器环境 遍历节点 DOM的基本属性 Attribute和自定义Property 在DOM中搜索元素 对文档进行操作

  10. 常见UI布局之1-2-1单列变宽布局

    扩展前一篇“上中下三栏布局”,中间栏划分成两列,一列宽度固定,一列宽度随浏览器窗口宽度的变化而变化.固定宽度列定义为#side,可分为左侧布局和右侧布局,分别实现如下: 1-2-1左侧固定宽度布局 & ...