Posted on 2009-08-25 15:29
天之骄子 阅读(5099)
评论(0) 编辑 收藏 引用
好久没有在VC++里面解析XML了,昨天遇到一个问题,从昨天下午一直到今天上午,差不多搞了一天,才终于把问题解决了。
使用MSXML在VC++中解析XML文件时候,只需要做到下面几点:
1、初始化COM库,CoInitialize(NULL);可以放在InitInstance()函数里面。释放COM库,CoUninitialize();可以放在ExitInstance()函数里面。
2、在头文件里面加入如下代码
#import "MSXML6.dll" rename_namespace("MSXML6") named_guids
using namespace MSXML6;
因为解析的时候要用到CComVariant类,所以还要加上
#include <atlbase.h>
3、解析XML文件。
需要解析的XML文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns="http://www.iec.ch/61850/2003/SCL">
<Address type="MAC-Address" xsi:type="tP_MAC-Address">
01-0C-CD-01-00-08
</Address>
</SCL>
首先要加载XML文件,代码如下:
HRESULT hr;
IXMLDOMDocument *pDoc=NULL;
CString strFileName;
CFileDialog fileDlg(TRUE);
fileDlg.m_ofn.lpstrTitle="打开XML文件";
fileDlg.m_ofn.lpstrFilter="XML Files(*.xml)\0*.xml\0All Files(*.*)\0*.*\0\0";
fileDlg.m_ofn.lpstrDefExt="xml";
if(fileDlg.DoModal() != IDOK)
return;
strFileName=fileDlg.GetPathName(); //获得要解析的XML文件的路径名
ASSERT(!strFileName.IsEmpty());
if(SUCCEEDED(CoCreateInstance(CLSID_DOMDocument,NULL,
CLSCTX_INPROC_SERVER,IID_IXMLDOMDocument,(void**)&pDoc))) //创建Document对象
{
CComVariant vPath(strFileName);
VARIANT_BOOL isSuccessful;
pDoc->raw_load(vPath,&isSuccessful); //加载要解析的XML文件
if(isSuccessful!=VARIANT_TRUE)
{
AfxMessageBox("wrong!");
return;
}
}
我当时在加载XML文件的时候老是报错,本来以为是代码的问题,找了半天都没问题呀。后来发现XML文件的问题,问题出在xsi:type上,如果将xsi:type改成别的(比如ype就可以了);或者是在根元素里面定义好xsi的意义,修改后的XML文件如下
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns="http://www.iec.ch/61850/2003/SCL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Address type="MAC-Address" xsi:type="tP_MAC-Address">
01-0C-CD-01-00-08
</Address>
</SCL>
现在加载XML文件已经没有问题了,下面就是解析XML文件了。我所做的工作是得到元素Address的两个属性的名称type和xsi:type,以及它们的属性值。
我原来的解析代码是:
IXMLDOMElement *pRootElement=NULL;
IXMLDOMNode *pRootNode=NULL;
IXMLDOMNamedNodeMap *pAttrMap=NULL;
IXMLDOMNode *pAttrNode=NULL;
IXMLDOMNode *pAddrNode=NULL;
CString strName,strText;
BSTR bsName,bsText;
hr=pDoc->get_documentElement(&pRootElement);
if(SUCCEEDED(hr) && (pRootElement!=NULL))
{
hr=pRootElement->QueryInterface(IID_IXMLDOMNode,(void**)&pRootNode);
if(SUCCEEDED(hr))
{
hr=pRootNode->get_firstChild(&pAddrNode);
if(SUCCEEDED(hr) && (pAddrNode!=NULL))
{
pAddrNode->get_attributes(&pAttrMap);
long length=0;
pAttrMap->get_length(&length);
for(int i=0;i<length;i++)
{
hr=pAttrMap->get_item(i,&pAttrNode);
if(SUCCEEDED(hr) && (pAttrNode!=NULL))
{
pAttrNode->get_baseName(&bsName);
pAttrNode->get_text(&bsText);
strName=bsName;
strText=bsText;
SysFreeString(bsName);
SysFreeString(bsText);
}
}
}
}
}
后来调试的时候发现,对xsi:type属性节点调用get_basename()方法,得到的是type,而不是xsi:type;当然对type属性节点调用get_basename()方法,得到的是type,这个正常。后来我改用IXMLDOMNode的get_nodeName()方法,才把问题解决了。对xsi:type属性节点调用get_nodename()方法,得到的是xsi:type;对type属性节点调用get_nodename()方法,得到的是type。
修改后的VC++代码如下
IXMLDOMElement *pRootElement=NULL;
IXMLDOMNode *pRootNode=NULL;
IXMLDOMNamedNodeMap *pAttrMap=NULL;
IXMLDOMNode *pAttrNode=NULL;
IXMLDOMNode *pAddrNode=NULL;
CString strName,strText;
BSTR bsName,bsText;
hr=pDoc->get_documentElement(&pRootElement);
if(SUCCEEDED(hr) && (pRootElement!=NULL))
{
hr=pRootElement->QueryInterface(IID_IXMLDOMNode,(void**)&pRootNode);
if(SUCCEEDED(hr))
{
hr=pRootNode->get_firstChild(&pAddrNode);
if(SUCCEEDED(hr) && (pAddrNode!=NULL))
{
pAddrNode->get_attributes(&pAttrMap);
long length=0;
pAttrMap->get_length(&length);
for(int i=0;i<length;i++)
{
hr=pAttrMap->get_item(i,&pAttrNode);
if(SUCCEEDED(hr) && (pAttrNode!=NULL))
{
pAttrNode->get_nodeName(&bsName);
pAttrNode->get_text(&bsText);
strName=bsName;
strText=bsText;
SysFreeString(bsName);
SysFreeString(bsText);
}
}
}
}
}