XMLParser.cpp
上传用户:hysujiao87
上传日期:2007-12-02
资源大小:156k
文件大小:9k
源码类别:

ICQ/即时通讯

开发平台:

C/C++

  1. // XMLParser.cpp: implementation of the CXMLParser class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "XMLParser.h"
  6. //////////////////////////////////////////////////////////////////////
  7. // Construction/Destruction
  8. //////////////////////////////////////////////////////////////////////
  9. #define TEMP_BUF_LEN 1024
  10. CXMLParser::CXMLParser() :
  11. m_pos(0),
  12. m_root(NULL)
  13. {
  14. m_version = "xml version="1.0"";
  15. }
  16. CXMLParser::~CXMLParser()
  17. {
  18. FreeXML();
  19. FreeTree();
  20. }
  21. int CXMLParser::LoadXML(BYTE* pBuf, DWORD nSize)
  22. {
  23. _ASSERTE(pBuf != NULL);
  24. if (pBuf == NULL)
  25. return -1;
  26. FreeTree();
  27. LPTSTR xmlBuffer = m_xml.GetBuffer(nSize + 1);
  28. memcpy((void*)xmlBuffer, pBuf, nSize);
  29. xmlBuffer[nSize] = '';
  30. m_xml.ReleaseBuffer();
  31. int result = ParseVersion();
  32. if (result != 0)
  33. return result;
  34. return ParseRoot();
  35. }
  36. int CXMLParser::LoadXML(LPCTSTR pathXML)
  37. {
  38. CByteArray xmlBuffer;
  39. try{
  40. CFile file(pathXML, CFile::modeRead | CFile::typeBinary);
  41. int length = (int)file.GetLength();
  42. if (length < 0)
  43. {
  44. TRACE("ERROR: Try to load a too big XML file.");
  45. file.Close();
  46. return -1;
  47. }
  48. xmlBuffer.SetSize(length);
  49. BYTE *xmlData = xmlBuffer.GetData();
  50. _ASSERTE(xmlData != NULL);
  51. if (xmlData == NULL)
  52. {
  53. TRACE("ERROR: Memory not enought.");
  54. file.Close();
  55. return -1;
  56. }
  57. file.Read(xmlData, length);
  58. file.Close();
  59. }
  60. catch (CFileException *fe) {
  61. fe->ReportError();
  62. fe->Delete();
  63. }
  64. return LoadXML(xmlBuffer.GetData(), (DWORD)xmlBuffer.GetSize());
  65. }
  66. int CXMLParser::ParseVersion()
  67. {
  68. //Try to find the start of the version tag.
  69. int version_start = m_xml.Find(_T("<?"), 0);
  70. if (version_start == -1)
  71. return -1;
  72. m_pos = version_start + 2;
  73. int version_finish = m_xml.Find(_T("?>"), m_pos);
  74. if (version_finish == -1)
  75. return -1;
  76. m_version = m_xml.Mid(m_pos, version_finish - m_pos);
  77. m_pos = version_finish + 2;
  78. return 0;
  79. }
  80. int CXMLParser::BuildVersion()
  81. {
  82. CString version_str = "<?" + m_version + "?>rn";
  83. m_xml += version_str;
  84. return 0;
  85. }
  86. int CXMLParser::BuildXML()
  87. {
  88. FreeXML();
  89. int ret = 0;
  90. if ( (ret = BuildVersion()) != 0)
  91. return ret;
  92. return m_root->BuildElement(m_xml);
  93. }
  94. /*BOOL CXMLParser::ParseEntities(CCString& value)
  95. {
  96. static TCHAR AMP_REF[] = _T("&amp;");
  97. static TCHAR LT_REF[] = _T("&lt;");
  98. static TCHAR GT_REF[] = _T("&gt;");
  99. static TCHAR QUOT_REF[] = _T("&quot;");
  100. static TCHAR APOS_REF[] = _T("&apos;");
  101. static TCHAR AMP[] = _T("&");
  102. static TCHAR LT[] = _T("<");
  103. static TCHAR GT[] = _T(">");
  104. static TCHAR QUOT[] = _T(""");
  105. static TCHAR APOS[] = _T("");
  106. static LPCTSTR szEntitiesRef[] = {AMP_REF, LT_REF, GT_REF, QUOT_REF, APOS_REF};
  107. static LPCTSTR szEntities[] = {AMP, LT, GT, QUOT, APOS};
  108. for(int i = 0; i < sizeof(szEntitiesRef) / sizeof(LPCTSTR); i++)
  109. {
  110. int nPos = 0;
  111. do
  112. {
  113. // Try to find the entities reference.
  114. nPos = value.Find(szEntitiesRef[i], nPos);
  115. if (nPos != -1)
  116. {
  117. // Replace the reference with the entities.
  118. value.Delete(nPos, _tcslen(szEntitiesRef[i]));
  119. value.Insert(nPos, szEntities[i]);
  120. nPos += _tcslen(szEntities[i]);
  121. }
  122. }while(nPos != -1);
  123. }
  124. return TRUE;
  125. }
  126. */
  127. int CXMLParser::FreeTree()
  128. {
  129. if (m_root)
  130. delete m_root;
  131. m_root = NULL;
  132. m_version = "xml version="1.0"";
  133. m_pos = 0;
  134. return 0;
  135. }
  136. int CXMLParser::FreeXML()
  137. {
  138. m_xml.Empty();
  139. m_pos = 0;
  140. return 0;
  141. }
  142. int CXMLParser::findNextTag(CString &tagName, CString &beforeTag)
  143. {
  144. tagName.Empty(); beforeTag.Empty();
  145. int beforeTagStart = findFirstNotOf(m_xml, _T("trn "), m_pos, 4);
  146. if (beforeTagStart == -1)
  147. return -1;
  148. int beforeTagFinish = m_xml.Find("<", beforeTagStart);
  149. if (beforeTagFinish == -1)
  150. return -1;
  151. if (beforeTagFinish - beforeTagStart > 0)
  152. {
  153. beforeTag = m_xml.Mid(beforeTagStart, 
  154.   beforeTagFinish - beforeTagStart);
  155. beforeTag.TrimRight();
  156. }
  157. // Find the tag finish position.
  158. int tag_start = beforeTagFinish;
  159. int tag_finish = m_xml.Find(">", tag_start);
  160. if (tag_finish == -1)
  161. return -1;
  162. tagName = m_xml.Mid(tag_start + 1, tag_finish - tag_start - 1);
  163. m_pos = tag_finish + 1;
  164. return 0;
  165. }
  166. int CXMLParser::ParseElement(CElement* element)
  167. {
  168. _ASSERTE(element != NULL);
  169. if (element == NULL)
  170. return -1;
  171. while(m_pos < m_xml.GetLength())
  172. {
  173. CString tagName;
  174. CString beforeTag;
  175. if (findNextTag(tagName, beforeTag) == -1)
  176. {
  177. TRACE("Error: without a finish tag for <%s>.n", element->get_tag());
  178. return -1;
  179. }
  180. if (element->get_content().IsEmpty())
  181. element->set_content(beforeTag);
  182. // Is a end-tag?
  183. if (tagName[0] == '/')
  184. {
  185. // Remove the '/' character.
  186. CString end_tagName;
  187. end_tagName = tagName;
  188. end_tagName.Delete(0, 1);
  189. if (element->get_tag() != end_tagName)
  190. {
  191. TRACE("Can't find a end tag for <%s>.n", element->get_tag());
  192. return -1;
  193. }
  194. return 0;
  195. }
  196. CElement* sub_element = new CElement(element);
  197. if (!sub_element)
  198. return -1;
  199. // Is it a empty tag?
  200. if (tagName[tagName.GetLength() - 1] == '/')
  201. {
  202. tagName.Delete(tagName.GetLength() - 1, 1);
  203. CString actualTagName;
  204. CMapStringToString attribute;
  205. if (ParseAttribute(tagName, actualTagName, sub_element->_attribute) != 0)
  206. return -1;
  207. sub_element->set_tag(actualTagName);
  208. continue ;
  209. }
  210. CString actualTagName;
  211. CMapStringToString attribute;
  212. if (ParseAttribute(tagName, actualTagName, sub_element->_attribute) != 0)
  213. return -1;
  214. sub_element->set_tag(actualTagName);
  215. if (ParseElement(sub_element) != 0)
  216. return -1;
  217. }
  218. TRACE("Error: without a finish tag for <%s>.n", element->get_tag());
  219. return -1;
  220. }
  221. int CXMLParser::EnumerateElements(LPENUM_CALLBACK_FUNC pFunc)
  222. {
  223. _ASSERTE(pFunc != NULL);
  224. if (!pFunc)
  225. return -1;
  226. return m_root->Enumerate(pFunc);
  227. }
  228. int CXMLParser::findFirstNotOf(CString &str, LPCTSTR array, int start, int arraySize)
  229. {
  230. int result = start;
  231. while(result < str.GetLength())
  232. {
  233. BOOL bEqual = FALSE;
  234. for (int i = 0; i < arraySize; i++)
  235. {
  236. if (str[result] == array[i])
  237. bEqual = TRUE;
  238. }
  239. if (bEqual == FALSE)
  240. return result;
  241. result++;
  242. }
  243. return -1;
  244. }
  245. int CXMLParser::ParseRoot()
  246. {
  247. // Find the root start tag.
  248. int tag_start = findFirstNotOf(m_xml, _T("trn "), m_pos, 4);
  249. // Find the next tag start position (it is the content part finish also).
  250. char temp = m_xml[tag_start];
  251. if (m_xml[tag_start] != _T('<'))
  252. {
  253. TRACE("Invalid XML format.n");
  254. return -1;
  255. }
  256. int tag_finish = m_xml.Find(_T('>'), tag_start);
  257. if (tag_finish == -1 || tag_finish - tag_start <= 1)
  258. {
  259. TRACE("Invalid root tag name.n");
  260. return -1;
  261. }
  262. CString tagName = m_xml.Mid(tag_start + 1, tag_finish - tag_start - 1);
  263. set_root(new CElement(NULL));
  264. get_root()->set_tag(tagName);
  265. m_pos = tag_finish + 1;
  266. return ParseElement(m_root);
  267. }
  268. int CXMLParser::ParseAttribute(LPCTSTR tagString, CString &tagName, CMapStringToString &attribute)
  269. {
  270. _ASSERTE(tagString != NULL);
  271. if (tagString == NULL)
  272. return -1;
  273. attribute.RemoveAll();
  274. CString tempSting = tagString;
  275. tempSting.TrimLeft(); tempSting.TrimRight();
  276. int firstSpacePos = tempSting.FindOneOf(_T(" trn"));
  277. if (firstSpacePos == -1)
  278. {
  279. tagName = tempSting;
  280. return 0;
  281. }
  282. tagName = tempSting.Left(firstSpacePos);
  283. int startPos = firstSpacePos + 1;
  284. int equalPos = tempSting.Find(_T('='), startPos);
  285. while (equalPos != -1)
  286. {
  287. CString attributeName = tempSting.Mid(startPos, equalPos - startPos);
  288. attributeName.TrimLeft(); attributeName.TrimRight();
  289. int leftInvertedCommasPos = tempSting.Find(_T('"'), equalPos + 1);
  290. if (leftInvertedCommasPos == -1)
  291. return -1;
  292. int rightInvertedCommasPos = tempSting.Find(_T('"'), leftInvertedCommasPos + 1);
  293. if (rightInvertedCommasPos == -1)
  294. return -1;
  295. CString attributeValue = tempSting.Mid(leftInvertedCommasPos + 1, rightInvertedCommasPos - leftInvertedCommasPos - 1);
  296. attributeValue.TrimLeft(); attributeValue.TrimRight();
  297. attribute.SetAt(attributeName, attributeValue);
  298. startPos = rightInvertedCommasPos + 1;
  299. equalPos = tempSting.Find(_T('='), startPos);
  300. }
  301. if (startPos <= tempSting.GetLength() - 1)
  302. return -1;
  303. return 0;
  304. }
  305. CElement *CXMLParser::createElement(LPCTSTR tag, LPCTSTR content)
  306. {
  307. _ASSERTE(tag != NULL && content != NULL);
  308. if (tag == NULL || content == NULL)
  309. return NULL;
  310. CElement *element = new CElement(NULL);
  311. if (element == NULL)
  312. return NULL;
  313. element->set_tag(tag);
  314. element->set_content(content);
  315. return element;
  316. }