码迷,mamicode.com
首页 > 其他好文 > 详细

DuiLib 源码分析之解析xml类CMarkup & CMarkupNode cpp文件

时间:2016-09-09 18:23:18      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

时隔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 = 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 errors
4     ::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 structure
24         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 name
33         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 attributes
38         if( !_ParseAttributes(pstrText) ) return false;            //解析属性
39         _SkipWhitespace(pstrText);
40         if( pstrText[0] == _T(/) && pstrText[1] == _T(>) )    //结尾是/>情况
41         {
42             pEl->iData = 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 data
50             pEl->iData = ++pstrText - m_pstrXML;
51             LPTSTR pstrDest = pstrText;
52             if( !_ParseData(pstrText, pstrDest, _T(<)) ) return false;//找到<符号
53             // Determine type of next element
54             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);//解析同义字符&quot;等
 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( );//填充空格,比如存在&quot;情况
 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 = 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文件

标签:

原文地址:http://www.cnblogs.com/george-cw/p/5857457.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!