欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

xml解析器实现过程

程序员文章站 2022-07-13 12:08:33
...

一、解析

1)控制台实现:仅支持英文&节点显示;

2)识别中文;

媒体共享里面共享中文名称的文件

空字符串 ASCII 9 10 nl

二、显示

树形控件 点一个显示子节点

文件共享点开文件夹

应用敏捷的思想

要求:解析xml文件,并在树形控件中进行显示,效果图如下:

xml解析器实现过程

实现过程:

运用敏捷的思想,提交多个版本:

  1. 实现解析功能
  2. MFC制作显示界
  • 实现解析功能

在控制台下实现了xml文件的解析,获取节点数据。

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);//设置风格