首页 > 代码库 > DuiLib 源码分析之解析xml类CMarkup & CMarkupNode cpp文件
DuiLib 源码分析之解析xml类CMarkup & CMarkupNode cpp文件
时隔5个月才有时间接着写未完成的实现部分,也是惭愧呀
选几个关机的函数来解析,一些get方法就忽略掉吧
CMarkupNode 与 CMarkUp 互为友元类,CMarkUp 实现解析,CMarkupNode 用于存储读取节点数据
1 void CMarkupNode::_MapAttributes() 2 { 3 m_nAttributes = 0; 4 LPCTSTR pstr = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart; 5 LPCTSTR pstrEnd = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData; 6 pstr += _tcslen(pstr) + 1; 7 while( pstr < pstrEnd ) { 8 m_pOwner->_SkipWhitespace(pstr); 9 m_aAttributes[m_nAttributes].iName = pstr - m_pOwner->m_pstrXML;//位移10 pstr += _tcslen(pstr) + 1;11 m_pOwner->_SkipWhitespace(pstr);12 if( *pstr++ != _T(‘\"‘) ) return; // if( *pstr != _T(‘\"‘) ) { pstr = ::CharNext(pstr); return; }13 14 m_aAttributes[m_nAttributes++].iValue = http://www.mamicode.com/pstr - m_pOwner->m_pstrXML;//位移15 if( m_nAttributes >= MAX_XML_ATTRIBUTES ) return;16 pstr += _tcslen(pstr) + 1;17 }18 }
这个函数的主要作用是将已经处理过的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压缩包中
1 bool CMarkup::_Parse()//解析入口, 先拓展节点保证有足够的节点存储,然后解析2 {3 _ReserveElement(); // Reserve index 0 for errors4 ::ZeroMemory(m_szErrorMsg, sizeof(m_szErrorMsg));5 ::ZeroMemory(m_szErrorXML, sizeof(m_szErrorXML));6 LPTSTR pstrXML = m_pstrXML;7 return _Parse(pstrXML, 0);8 }
1 CMarkup::XMLELEMENT* CMarkup::_ReserveElement()//拓展节点数2 {3 if( m_nElements == 0 ) m_nReservedElements = 0;4 if( m_nElements >= m_nReservedElements ) {5 m_nReservedElements += (m_nReservedElements / 2) + 500;6 m_pElements = static_cast<XMLELEMENT*>(realloc(m_pElements, m_nReservedElements * sizeof(XMLELEMENT)));//这里的realloc函数会将原来的内容复制到新申请的内存中7 }8 return &m_pElements[m_nElements++];9 }
1 bool CMarkup::_Parse(LPTSTR& pstrText, ULONG iParent) 2 { 3 _SkipWhitespace(pstrText);//跳过空格 4 ULONG iPrevious = 0; 5 for( ; ; ) 6 { 7 if( *pstrText == _T(‘\0‘) && iParent <= 1 ) return true;//退出条件,到结尾,或者无父节点 8 _SkipWhitespace(pstrText); 9 if( *pstrText != _T(‘<‘) ) return _Failed(_T("Expected start tag"), pstrText);10 if( pstrText[1] == _T(‘/‘) ) return true;11 *pstrText++ = _T(‘\0‘);12 _SkipWhitespace(pstrText);13 // Skip comment or processing directive 跳过注释(<- ->)或指令(<? ?>)14 if( *pstrText == _T(‘!‘) || *pstrText == _T(‘?‘) ) {15 TCHAR ch = *pstrText;16 if( *pstrText == _T(‘!‘) ) ch = _T(‘-‘);17 while( *pstrText != _T(‘\0‘) && !(*pstrText == ch && *(pstrText + 1) == _T(‘>‘)) ) pstrText = ::CharNext(pstrText);18 if( *pstrText != _T(‘\0‘) ) pstrText += 2;19 _SkipWhitespace(pstrText);20 continue;21 }22 _SkipWhitespace(pstrText);23 // Fill out element structure24 XMLELEMENT* pEl = _ReserveElement();25 ULONG iPos = pEl - m_pElements;26 pEl->iStart = pstrText - m_pstrXML;27 pEl->iParent = iParent;28 pEl->iNext = pEl->iChild = 0;29 if( iPrevious != 0 ) m_pElements[iPrevious].iNext = iPos;30 else if( iParent > 0 ) m_pElements[iParent].iChild = iPos;31 iPrevious = iPos;32 // Parse name33 LPCTSTR pstrName = pstrText;34 _SkipIdentifier(pstrText);35 LPTSTR pstrNameEnd = pstrText;36 if( *pstrText == _T(‘\0‘) ) return _Failed(_T("Error parsing element name"), pstrText);37 // Parse attributes38 if( !_ParseAttributes(pstrText) ) return false; //解析属性39 _SkipWhitespace(pstrText);40 if( pstrText[0] == _T(‘/‘) && pstrText[1] == _T(‘>‘) ) //结尾是/>情况41 {42 pEl->iData = http://www.mamicode.com/pstrText - m_pstrXML; //保存节点的结尾位移43 *pstrText = _T(‘\0‘);44 pstrText += 2;45 } 46 else //结尾是>情况47 {48 if( *pstrText != _T(‘>‘) ) return _Failed(_T("Expected start-tag closing"), pstrText);49 // Parse node data50 pEl->iData = http://www.mamicode.com/++pstrText - m_pstrXML;51 LPTSTR pstrDest = pstrText;52 if( !_ParseData(pstrText, pstrDest, _T(‘<‘)) ) return false;//找到<符号53 // Determine type of next element54 if( *pstrText == _T(‘\0‘) && iParent <= 1 ) return true; //如果是结尾则返回55 if( *pstrText != _T(‘<‘) ) return _Failed(_T("Expected end-tag start"), pstrText);56 if( pstrText[0] == _T(‘<‘) && pstrText[1] != _T(‘/‘) ) 57 {58 if( !_Parse(pstrText, iPos) ) return false; //递归解析子节点59 }60 if( pstrText[0] == _T(‘<‘) && pstrText[1] == _T(‘/‘) ) //处理</>情况61 {62 *pstrDest = _T(‘\0‘);63 *pstrText = _T(‘\0‘);64 pstrText += 2;65 _SkipWhitespace(pstrText);66 SIZE_T cchName = pstrNameEnd - pstrName;67 if( _tcsncmp(pstrText, pstrName, cchName) != 0 ) return _Failed(_T("Unmatched closing tag"), pstrText);68 pstrText += cchName;69 _SkipWhitespace(pstrText);70 if( *pstrText++ != _T(‘>‘) ) return _Failed(_T("Unmatched closing tag"), pstrText);71 }72 }73 *pstrNameEnd = _T(‘\0‘);74 _SkipWhitespace(pstrText);75 }76 }
1 void CMarkup::_SkipWhitespace(LPCTSTR& pstr) const 2 { 3 while( *pstr > _T(‘\0‘) && *pstr <= _T(‘ ‘) ) pstr = ::CharNext(pstr); 4 } 5 6 void CMarkup::_SkipWhitespace(LPTSTR& pstr) const 7 { 8 while( *pstr > _T(‘\0‘) && *pstr <= _T(‘ ‘) ) pstr = ::CharNext(pstr); 9 } 10 11 void CMarkup::_SkipIdentifier(LPCTSTR& pstr) const 12 { 13 // 属性只能用英文,所以这样处理没有问题 14 while( *pstr != _T(‘\0‘) && (*pstr == _T(‘_‘) || *pstr == _T(‘:‘) || _istalnum(*pstr)) ) pstr = ::CharNext(pstr); 15 } 16 17 void CMarkup::_SkipIdentifier(LPTSTR& pstr) const 18 { 19 // 属性只能用英文,所以这样处理没有问题 20 while( *pstr != _T(‘\0‘) && (*pstr == _T(‘_‘) || *pstr == _T(‘:‘) || _istalnum(*pstr)) ) pstr = ::CharNext(pstr); 21 } 22 23 bool CMarkup::_ParseAttributes(LPTSTR& pstrText) 24 { 25 if( *pstrText == _T(‘>‘) ) return true; 26 *pstrText++ = _T(‘\0‘); 27 _SkipWhitespace(pstrText); 28 while( *pstrText != _T(‘\0‘) && *pstrText != _T(‘>‘) && *pstrText != _T(‘/‘) ) { 29 _SkipIdentifier(pstrText); //跳过属性名 30 LPTSTR pstrIdentifierEnd = pstrText; 31 _SkipWhitespace(pstrText); //跳过空白 32 if( *pstrText != _T(‘=‘) ) return _Failed(_T("Error while parsing attributes"), pstrText); 33 *pstrText++ = _T(‘ ‘); //‘=‘也赋值为空格 34 *pstrIdentifierEnd = _T(‘\0‘); 35 _SkipWhitespace(pstrText); 36 if( *pstrText++ != _T(‘\"‘) ) return _Failed(_T("Expected attribute value"), pstrText);//必须为双引号 37 LPTSTR pstrDest = pstrText; 38 if( !_ParseData(pstrText, pstrDest, _T(‘\"‘)) ) return false;//解析属性数据 39 if( *pstrText == _T(‘\0‘) ) return _Failed(_T("Error while parsing attribute string"), pstrText); 40 *pstrDest = _T(‘\0‘); 41 if( pstrText != pstrDest ) *pstrText = _T(‘ ‘); 42 pstrText++; 43 _SkipWhitespace(pstrText); 44 } 45 return true; 46 } 47 48 bool CMarkup::_ParseData(LPTSTR& pstrText, LPTSTR& pstrDest, char cEnd) 49 { 50 while( *pstrText != _T(‘\0‘) && *pstrText != cEnd ) { 51 if( *pstrText == _T(‘&‘) ) { 52 while( *pstrText == _T(‘&‘) ) { 53 _ParseMetaChar(++pstrText, pstrDest);//解析同义字符"等 54 } 55 if (*pstrText == cEnd) 56 break; 57 } 58 59 if( *pstrText == _T(‘ ‘) ) { 60 *pstrDest++ = *pstrText++; 61 if( !m_bPreserveWhitespace ) _SkipWhitespace(pstrText); 62 } 63 else { 64 LPTSTR pstrTemp = ::CharNext(pstrText); 65 while( pstrText < pstrTemp) { 66 *pstrDest++ = *pstrText++; 67 } 68 } 69 } 70 // Make sure that MapAttributes() works correctly when it parses 71 // over a value that has been transformed. 72 LPTSTR pstrFill = pstrDest + 1; 73 while( pstrFill < pstrText ) *pstrFill++ = _T(‘ ‘);//填充空格,比如存在"情况 74 return true; 75 } 76 77 void CMarkup::_ParseMetaChar(LPTSTR& pstrText, LPTSTR& pstrDest) 78 { 79 if( pstrText[0] == _T(‘a‘) && pstrText[1] == _T(‘m‘) && pstrText[2] == _T(‘p‘) && pstrText[3] == _T(‘;‘) ) { 80 *pstrDest++ = _T(‘&‘); 81 pstrText += 4; 82 } 83 else if( pstrText[0] == _T(‘l‘) && pstrText[1] == _T(‘t‘) && pstrText[2] == _T(‘;‘) ) { 84 *pstrDest++ = _T(‘<‘); 85 pstrText += 3; 86 } 87 else if( pstrText[0] == _T(‘g‘) && pstrText[1] == _T(‘t‘) && pstrText[2] == _T(‘;‘) ) { 88 *pstrDest++ = _T(‘>‘); 89 pstrText += 3; 90 } 91 else if( pstrText[0] == _T(‘q‘) && pstrText[1] == _T(‘u‘) && pstrText[2] == _T(‘o‘) && pstrText[3] == _T(‘t‘) && pstrText[4] == _T(‘;‘) ) { 92 *pstrDest++ = _T(‘\"‘); 93 pstrText += 5; 94 } 95 else if( pstrText[0] == _T(‘a‘) && pstrText[1] == _T(‘p‘) && pstrText[2] == _T(‘o‘) && pstrText[3] == _T(‘s‘) && pstrText[4] == _T(‘;‘) ) { 96 *pstrDest++ = _T(‘\‘‘); 97 pstrText += 5; 98 } 99 else {100 *pstrDest++ = _T(‘&‘);101 }102 }
解析xml的基本原理就是,将xml加载到内存中,顺序解析节点,首先对节点进行存储,对xml进行改写(将<、>、/、"、‘等改写为空格),获取节点
属性的时候进行分割存储。
简单举个例子会更清晰:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Window size="800,572" sizebox="4,4,6,6" roundcorner="5,5" caption="0,0,0,90" mininfo="800,570"> 3 <Font name="宋体" size="13" bold="true" /> 4 <VerticalLayout bkcolor="#FFD1E8F5" bkcolor2="#FFC6E0F1" bordercolor="#FF768D9B" bordersize="1" borderround="5,5" inset="1,0,1,0"> 5 <HorizontalLayout> 6 <Container width="22" height="22" bkimage="file=‘icon.png‘ source=‘0,0,16,16‘ dest=‘5,4,21,20‘ " /> 7 <Text text="360安全卫士7.3" pos="22, 5, 200, 24" float="true" textcolor="#FF447AA1" font="0" /> 8 </HorizontalLayout> 9 </VerticalLayout> 10 </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>
1 void CMarkupNode::_MapAttributes() 2 { 3 m_nAttributes = 0; 4 LPCTSTR pstr = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart; 5 LPCTSTR pstrEnd = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData; 6 pstr += _tcslen(pstr) + 1; 7 while( pstr < pstrEnd ) { 8 m_pOwner->_SkipWhitespace(pstr); 9 m_aAttributes[m_nAttributes].iName = pstr - m_pOwner->m_pstrXML;//位移10 pstr += _tcslen(pstr) + 1;11 m_pOwner->_SkipWhitespace(pstr);12 if( *pstr++ != _T(‘\"‘) ) return; // if( *pstr != _T(‘\"‘) ) { pstr = ::CharNext(pstr); return; }13 14 m_aAttributes[m_nAttributes++].iValue = http://www.mamicode.com/pstr - m_pOwner->m_pstrXML;//位移15 if( m_nAttributes >= MAX_XML_ATTRIBUTES ) return;16 pstr += _tcslen(pstr) + 1;17 }18 }
然后看获取属性的函数就一目了然了
DuiLib 源码分析之解析xml类CMarkup & CMarkupNode cpp文件
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。