#include "stdafx.h" #include <string> #include <map> #include <vector> #include <list> class HtmlNode { public: HtmlNode() { } const wchar_t* GetName() { return this->m_name.c_str(); } const wchar_t* GetAttribute(const wchar_t* attrName) { return this->m_attributes[attrName].c_str(); } const wchar_t* GetInnerText() { return this->m_innerText.c_str(); } int GetChildCount() { return (int)this->m_children.size(); } HtmlNode* GetChild(int index) { return this->m_children[index]; } void SetName(std::wstring& name) { this->m_name = name; } void SetName(const wchar_t* name) { this->m_name = name; } std::wstring& GetNameString() { return this->m_name; } void AddAttribute(std::wstring& name, std::wstring& value) { this->m_attributes.insert(std::make_pair(name, value)); } void AddChild(HtmlNode* child) { this->m_children.push_back(child); } void SetInnerText(std::wstring& innerText) { this->m_innerText = innerText; } public: std::wstring m_name; std::wstring m_innerText; std::map< std::wstring, std::wstring > m_attributes; std::vector< HtmlNode* > m_children; }; const int HTML_NONE = 0; const int HTML_TAG_S = 1; const int HTML_TAG_N = 2; const int HTML_TAG_N_E = 3; const int HTML_ATTR_N = 4; const int HTML_ATTR_N_E = 5; const int HTML_ATTR_V_S = 6; const int HTML_ATTR_V = 7; const int HTML_ATTR_V_E = 8; const int HTML_TAG_E = 9; const int HTML_INNER = 10; struct NODE { HtmlNode* htmlNode; std::wstring innerHtmlText; }; HtmlNode* ParseHtml(const wchar_t* htmlText, int len) { std::list< NODE > nodes; std::vector< NODE > tmpNodes; NODE root; root.htmlNode = new HtmlNode(); root.htmlNode->SetName(L"/"); root.innerHtmlText.assign(htmlText, htmlText + len); nodes.push_back(root); std::wstring name; std::wstring attrName; std::wstring attrValue; std::wstring innerText; std::wstring findTag; while ( !nodes.empty() ) { tmpNodes.resize(0); NODE& curNode = nodes.front(); std::wstring& innerHtmlText = curNode.innerHtmlText; const wchar_t* innerHtml = innerHtmlText.c_str(); const wchar_t* pInnerHtml = innerHtmlText.c_str(); const wchar_t* pCurHtml = pInnerHtml; int hitHtml = HTML_NONE; wchar_t ch = 0; size_t index = 0; size_t len = innerHtmlText.size(); while ( index < len ) { ch = *pInnerHtml; if ( ch == L'<' ) { switch(hitHtml) { case HTML_INNER: { innerText.assign(pCurHtml, pInnerHtml); HtmlNode* htmlNode = new HtmlNode(); htmlNode->SetName(L"#"); htmlNode->SetInnerText(innerText); curNode.htmlNode->AddChild(htmlNode); } case HTML_NONE: case HTML_TAG_E: { hitHtml = HTML_TAG_E; if ( index + 4 < len && pInnerHtml[1] == L'!' && pInnerHtml[2] == L'-' && pInnerHtml[3] == L'-' ) { size_t pos = innerHtmlText.find(L"-->", index + 4); if ( pos != std::wstring::npos ) { innerText.assign(innerHtml + index + 4, innerHtml + pos); index = pos + wcslen(L"-->"); pInnerHtml = innerHtml + index; pCurHtml = pInnerHtml; HtmlNode* htmlNode = new HtmlNode(); htmlNode->SetName(L"!--"); htmlNode->SetInnerText(innerText); curNode.htmlNode->AddChild(htmlNode); } else { hitHtml = HTML_INNER; pCurHtml = pInnerHtml; } } else if ( index + 9 < len && pInnerHtml[1] == L'!' && ( pInnerHtml[2] == L'D' || pInnerHtml[2] == L'd' ) && ( pInnerHtml[3] == L'O' || pInnerHtml[3] == L'o' ) && ( pInnerHtml[4] == L'C' || pInnerHtml[4] == L'c' ) && ( pInnerHtml[5] == L'T' || pInnerHtml[5] == L't' ) && ( pInnerHtml[6] == L'Y' || pInnerHtml[6] == L'y' ) && ( pInnerHtml[7] == L'P' || pInnerHtml[7] == L'p' ) && ( pInnerHtml[8] == L'E' || pInnerHtml[8] == L'E' ) ) { size_t pos = innerHtmlText.find(L'>', index + 9); if ( pos != std::wstring::npos ) { innerText.assign(innerHtml + index + 9, innerHtml + pos); index = pos + wcslen(L">"); pInnerHtml = innerHtml + index; pCurHtml = pInnerHtml; HtmlNode* htmlNode = new HtmlNode(); htmlNode->SetName(L"!DOCTYPE"); htmlNode->SetInnerText(innerText); curNode.htmlNode->AddChild(htmlNode); } else { hitHtml = HTML_INNER; pCurHtml = pInnerHtml; } } else { hitHtml = HTML_TAG_S; pCurHtml = pInnerHtml + 1; } } break; case HTML_TAG_S: {} break; case HTML_TAG_N: {} break; case HTML_TAG_N_E: {} break; case HTML_ATTR_N: {} break; case HTML_ATTR_N_E: {} break; case HTML_ATTR_V_S: {} break; case HTML_ATTR_V: {} break; case HTML_ATTR_V_E: {} break; } } else if ( ch == L'=' ) { switch(hitHtml) { case HTML_NONE: {} break; case HTML_TAG_S: {} break; case HTML_TAG_N: { } break; case HTML_TAG_N_E: { } break; case HTML_ATTR_N: { hitHtml = HTML_ATTR_N_E; attrName.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; } break; case HTML_ATTR_N_E: { } break; case HTML_ATTR_V_S: { } break; case HTML_ATTR_V: { } break; case HTML_ATTR_V_E: { } case HTML_TAG_E: {} break; } } else if ( ch == L'"' ) { switch(hitHtml) { case HTML_NONE: {} break; case HTML_TAG_S: {} break; case HTML_TAG_N: { } break; case HTML_TAG_N_E: { } break; case HTML_ATTR_N: { attrName.assign(pCurHtml, pInnerHtml); } case HTML_ATTR_N_E: { hitHtml = HTML_ATTR_V_S; pCurHtml = pInnerHtml + 1; } break; case HTML_ATTR_V_S: { hitHtml = HTML_ATTR_V_E; attrValue.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; NODE& newNode = tmpNodes.back(); newNode.htmlNode->AddAttribute(attrName, attrValue); } break; case HTML_ATTR_V: { } break; case HTML_ATTR_V_E: { } break; case HTML_TAG_E: {} break; } } else if ( ch == L'/' ) { switch(hitHtml) { case HTML_NONE: {} break; case HTML_TAG_S: {} break; case HTML_TAG_N: { hitHtml = HTML_TAG_E; name.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; tmpNodes.resize(tmpNodes.size() + 1); NODE& newNode = tmpNodes.back(); newNode.htmlNode = new HtmlNode(); newNode.htmlNode->SetName(name); curNode.htmlNode->AddChild(newNode.htmlNode); } case HTML_TAG_N_E: { } break; case HTML_ATTR_N: { } break; case HTML_ATTR_N_E: { } break; case HTML_ATTR_V_S: { } break; case HTML_ATTR_V: { if ( index + 1 < len && pInnerHtml[1] == L'>' ) { hitHtml = HTML_TAG_E; attrValue.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; NODE& newNode = tmpNodes.back(); newNode.htmlNode->AddAttribute(attrName, attrValue); } } break; case HTML_ATTR_V_E: { } case HTML_TAG_E: {} break; } } else if ( ch == L'>' ) { switch(hitHtml) { case HTML_NONE: {} break; case HTML_TAG_S: {} break; case HTML_ATTR_V_S: { } break; case HTML_TAG_N: { name.assign(pCurHtml, pInnerHtml); tmpNodes.resize(tmpNodes.size() + 1); NODE& newNode = tmpNodes.back(); newNode.htmlNode = new HtmlNode(); newNode.htmlNode->SetName(name); curNode.htmlNode->AddChild(newNode.htmlNode); } case HTML_ATTR_V: { if ( hitHtml == HTML_ATTR_V ) { attrValue.assign(pCurHtml, pInnerHtml); NODE& newNode = tmpNodes.back(); newNode.htmlNode->AddAttribute(attrName, attrValue); } } case HTML_TAG_N_E: case HTML_ATTR_N: case HTML_ATTR_N_E: case HTML_ATTR_V_E: { hitHtml = HTML_TAG_E; pCurHtml = pInnerHtml + 1; NODE& newNode = tmpNodes.back(); findTag = L"</"; findTag += newNode.htmlNode->GetNameString(); size_t pos = innerHtmlText.find(findTag, index); if ( pos != std::wstring::npos ) { newNode.innerHtmlText.assign(innerHtml + index + 1, innerHtml + pos); pos = innerHtmlText.find(L'>', pos); if ( pos != std::wstring::npos ) { index = pos; } else { index += findTag.size() - 1; } pInnerHtml = innerHtml + index; } } break; case HTML_TAG_E: { } break; } } else { if ( ch == 0x0020 || ch == 0x0009 || ch == 0x000A || ch == 0x000B || ch == 0x000C || ch == 0x000D || ch == 0x00A0 || ch == 0x2000 || ch == 0x2001 || ch == 0x2002 || ch == 0x2003 || ch == 0x2004 || ch == 0x2005 || ch == 0x2006 || ch == 0x2007 || ch == 0x2008 || ch == 0x2009 || ch == 0x200A || ch == 0x200B || ch == 0x3000 || ch == 0xFEFF ) { switch(hitHtml) { case HTML_NONE: {} break; case HTML_TAG_S: {} break; case HTML_TAG_N: { hitHtml = HTML_TAG_N_E; name.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; tmpNodes.resize(tmpNodes.size() + 1); NODE& newNode = tmpNodes.back(); newNode.htmlNode = new HtmlNode(); newNode.htmlNode->SetName(name); curNode.htmlNode->AddChild(newNode.htmlNode); } break; case HTML_TAG_N_E: {} break; case HTML_ATTR_N: {} break; case HTML_ATTR_N_E: {} break; case HTML_ATTR_V_S: {} break; case HTML_ATTR_V: { hitHtml = HTML_ATTR_V_E; attrValue.assign(pCurHtml, pInnerHtml); pCurHtml = pInnerHtml + 1; NODE& newNode = tmpNodes.back(); newNode.htmlNode->AddAttribute(attrName, attrValue); } break; case HTML_ATTR_V_E: {} break; case HTML_TAG_E: {} break; } } else { switch(hitHtml) { case HTML_NONE: case HTML_TAG_E: { hitHtml = HTML_INNER; pCurHtml = pInnerHtml; } break; case HTML_TAG_S: { hitHtml = HTML_TAG_N; pCurHtml = pInnerHtml; } break; case HTML_TAG_N: {} break; case HTML_TAG_N_E: { hitHtml = HTML_ATTR_N; pCurHtml = pInnerHtml; } break; case HTML_ATTR_N: { } break; case HTML_ATTR_N_E: { hitHtml = HTML_ATTR_V; pCurHtml = pInnerHtml; } break; case HTML_ATTR_V_S: {} break; case HTML_ATTR_V: {} break; case HTML_ATTR_V_E: {} break; } } } pInnerHtml++; index++; } if ( hitHtml == HTML_INNER ) { innerText.assign(pCurHtml, pInnerHtml); curNode.htmlNode->SetInnerText(innerText); } nodes.pop_front(); for(std::vector< NODE >::iterator iter = tmpNodes.begin(); iter != tmpNodes.end(); iter++ ) { NODE& newNode = *iter; nodes.push_back(newNode); } } return root.htmlNode; } int _tmain(int argc, _TCHAR* argv[]) { std::wstring htmlText; FILE* pFile = ::_wfopen(L"..//htmlfile.htm", L"r+"); wchar_t buffer[1024]; while (!feof(pFile) ) { wchar_t* ret = fgetws(buffer, 1024, pFile); if ( ret != NULL ) { htmlText += ret; } } HtmlNode* root = ParseHtml(htmlText.c_str(), htmlText.size()); std::list< HtmlNode* > nodes; nodes.push_back(root); while ( !nodes.empty() ) { HtmlNode* htmlNode = nodes.front(); nodes.pop_front(); for(int cnt = 0; cnt < htmlNode->GetChildCount(); cnt++) { HtmlNode* child = htmlNode->GetChild(cnt); std::wcout << " NAME:" << child->GetName() << L" INNERTEXT:" << child->GetInnerText(); for(std::map< std::wstring, std::wstring >::iterator iter = child->m_attributes.begin(); iter != child->m_attributes.end(); iter++ ) { std::wcout << " ATTRNAME:" << iter->first.c_str() << " ATTRVAL:" << iter->second.c_str(); } std::wcout<<std::endl; nodes.push_back(child); } } return 0; }