xml解析器实现过程
一、解析
1)控制台实现:仅支持英文&节点显示;
2)识别中文;
媒体共享里面共享中文名称的文件
空字符串 ASCII 9 10 nl
二、显示
树形控件 点一个显示子节点
文件共享点开文件夹
应用敏捷的思想
要求:解析xml文件,并在树形控件中进行显示,效果图如下:
实现过程:
运用敏捷的思想,提交多个版本:
- 实现解析功能
- MFC制作显示界
- 实现解析功能
在控制台下实现了xml文件的解析,获取节点数据。
使用expat解析库对xml进行解析,截取cyberlink库中xml相关文件。将整个xml解析成一个Node节点,通过getNNodes获取当前节点的子节点个数,getNode(i)获取第i个子节点,以及getValue(),getName()等一系列函数获取节点相关信息。
主要遇到的问题:
1)如上图所示,不识别中文,是编码方式UTF-8和GB2312的问题
void UTF_8ToGB2312(char * pOut, const char *pText, int &pLen);解决该问题,读出数据后在显示的时候进行转码。
- MFC制作显示界面
控制台显示不够直观,决定采用MFC的Tree Ctrl来实现。
遇到的问题:
1)数据怎样以树形结构显示?解析出来的是叶子节点上的数据,必须要显示父节点。
解决思路:父节点显示名称,叶子节点显示节点名称和节点数据
2)获取要解析的xml文件路径
i)按钮加载图标
m_search.LoadBitmaps(IDB_SEARCH, 0, 0, 0);
m_search.SubclassDlgItem(IDC_BROWSEXML, this);
m_search.SizeToContent();
m_search为按钮控件对应的CBitmapButton类型的变量(此变量必须手动添加,不能用IDE添加,否则出错),按钮的OWERDROW属性设置为TRUE. IDB_SEARCH是要显示在按钮上的图片的ID,IDC_BROWSEXML是按钮的ID。
ii)打开文件对话框,仅显示xml格式文件以供选择
m_path 为编辑控件对应的CString类型的变量
CFileDialog hFileDlg(TRUE,NULL,NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_READONLY,
TEXT("仅支持xml格式(*.xml;...)|*.xml"),NULL);
if(IDOK == hFileDlg.DoModal())
{
m_path =_T("");
m_path = hFileDlg.GetPathName();
UpdateData(FALSE);
}
3)树形控件的使用及数据的显示
//*****************************************************
// \brief 初始化树形控件
//
// version: 普通版本
//
// \author huyp
//
// \param 无
//
// \return 无
//*****************************************************
void CHYPXmlParserDlg::InitXmlTree(void)
{
DWORD dwStyles = GetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE);//获取树控制原风格
dwStyles|=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT;
SetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE,dwStyles);//设置风格
}
//*****************************************************
// \brief 显示XML数据
//
// version: 普通版本
//
// \author huyp
//
// \param xmlNode 节点指针
//
// \return -1显示失败,1显示成功
//*****************************************************
int CHYPXmlParserDlg::ShowXmlData(Node* xmlNode)
{
/*string buf;
xmlNode->toString(buf);*/
int nNodes = 0;
if(NULL == xmlNode)//当前要显示的节点为空
{
return -1;
}
nNodes = xmlNode->getNNodes();//获取当前节点的子节点个数
if(0 == nNodes)//无子节点,是叶子节点
{
const char * value = xmlNode->getValue();
const char * name = xmlNode->getName();
char svalue[1024];
char eleValue[1024];
int lvalue = strlen(value);
memset(svalue,0,sizeof(svalue));
memset(eleValue,0,sizeof(eleValue));
XML::UTF_8ToGB2312(svalue, value, lvalue);//编码转换
sprintf(eleValue, "%s--%s",name, svalue);//拼接叶子节点的节点名称和节点数据
m_TreeCtrl.InsertItem(eleValue,hCur,TVI_LAST);//返回根项句柄
}
else//有子节点
{
if(hCur != NULL)
{
hRoot = hCur;//父节点狭义
}
const char* name = xmlNode->getName();
if(NULL == hRoot)
{
hRoot = m_TreeCtrl.InsertItem(name,TVI_ROOT);//返回根项句柄
hSave = hRoot;
}
else
{
hCur = m_TreeCtrl.InsertItem(name,hRoot, TVI_LAST);
}
for(int i = 0; i<nNodes; i++)
{
Node* childNode = xmlNode->getNode(i);
ShowXmlData(childNode);
if ((i == (nNodes - 1))&&(hSave != hRoot))//当解析到叶子节点且父节点不是根节点
{
hCur = m_TreeCtrl.GetParentItem(hCur);
}
}
}
return 1;
}
树形控件的基本操作:
HTREEITEM hRoot,hCur,hSave;//树控制项目句柄
m_TreeCtrl.InsertItem(eleValue,hCur,TVI_LAST);//返回根项句柄最重要的就是要确定父节点是谁,也就是第二个参数,五个参数的InsertItem是可以插入图表,如果不插入图表省略两个参数。
要注意的问题:树形控件风格的设定,各项代表的含义是不同的,错误的设置会导致节点数据无法显示的问题
DWORD dwStyles = GetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE);//获取树控制原风格dwStyles|=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT;SetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE,dwStyles);//设置风格