vc中使用MSXML2的注意点

MSXML2能够很好地处理xml文件,不过也有些需要注意的点

1. MSXML2的加载和释放

   loadIndexXml(TCHAR * indexdir) {
if (NULL == indexdir){
return NULL;
}
::CoInitialize(NULL);
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(__uuidof(DOMDocument60));
if (VARIANT_FALSE == doc->load(indexdir)){
doc.Release();
return NULL;
}

 ......do smthing();

doc.Release();

CoUninitialize();

 2. 新建一个xml文件

CString setnameindex;
setnameindex.Format("./xxx/%s.xml", name);
//判断文件是否存在
HANDLE hOpenFile = (HANDLE)CreateFile(setnameindex, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
 
if (hOpenFile == INVALID_HANDLE_VALUE) {
::CoInitialize(NULL);
MSXML2::IXMLDOMDocumentPtr setnamedoc;
setnamedoc.CreateInstance(__uuidof(DOMDocument60));
char* dbfile = (LPSTR)(LPCSTR)setnameindex;
 
setnamedoc->preserveWhiteSpace = VARIANT_TRUE;//这个必须设置,不然不生效
MSXML2::IXMLDOMProcessingInstructionPtr pProInstruction = NULL;
pProInstruction = setnamedoc->createProcessingInstruction((_bstr_t)(char*)"xml", (_bstr_t)(char*)"version="1.0" encoding="utf-8"");
((MSXML2::IXMLDOMNodePtr)setnamedoc)->appendChild(pProInstruction);
MSXML2::IXMLDOMElementPtr pRootElement = NULL;
pRootElement = setnamedoc->createElement((_bstr_t)(char*)"db");
setnamedoc->PutRefdocumentElement(pRootElement);
((MSXML2::IXMLDOMNodePtr)setnamedoc->documentElement)->appendChild(setnamedoc->createTextNode(" "));
MSXML2::IXMLDOMCommentPtr pComment = setnamedoc->createComment((_bstr_t)(char*)"db");
((MSXML2::IXMLDOMNodePtr)pRootElement)->appendChild(pComment); // 注释
setnamedoc->save((LPSTR)(LPCSTR)setnameindex);
   setnamedoc.Release();
//CoUninitialize();
}

 3.获取某个节点列表,判断节点是否存在,并做处理

MSXML2::IXMLDOMNodeListPtr node_person_list = ((MSXML2::IXMLDOMNodePtr)doc)->selectNodes("register/person");

if (NULL == node_person_list || node_person_list->Getlength() == 0) {
........不存在的情况
}

else{

........存在的情况 

 xml文件:

<register>

<person name="xxxx" file="./a/b/c.png" date="0"/>

 <person name="xxxx" file="./a/b/c.png" date="0"/>

.... 

</register>

4. 获取节点属性 如name file data

MSXML2::IXMLDOMNodeListPtr node_person_list = ((MSXML2::IXMLDOMNodePtr)doc)->selectNodes("register/person");
for (int i = 0; i < node_person_list->Getlength(); i++)
{
MSXML2::IXMLDOMNodePtr node_item = node_person_list->Getitem(i);
_variant_t var_name = ((MSXML2::IXMLDOMElementPtr)node_item)->getAttribute("name");
_variant_t var_file = ((MSXML2::IXMLDOMElementPtr)node_item)->getAttribute("file");
_variant_t var_date = ((MSXML2::IXMLDOMElementPtr)node_item)->getAttribute("date");
_variant_t var_score = NULL;
var_score = ((MSXML2::IXMLDOMElementPtr)node_item)->getAttribute("score");
 
n->name = _tcsdup(CString(var_name.bstrVal));
//n->score = wcstol(var_score.bstrVal, NULL, 0);
TCHAR temp[1024];
//_tcscpy(temp, TEXT("facescore/woman/"));
_tcscpy(temp, TEXT(""));
_tcscat(temp, CString(var_file.bstrVal));
n->file = _tcsdup(temp);
//n->feature = (float *)malloc(sizeof(float) * 2048);
n->date = _ttoi((LPCTSTR)(_bstr_t)var_date);
if (var_score.vt != VT_NULL) {
n->score = _ttoi((LPCTSTR)(_bstr_t)var_score);
}
else {
n->score = -1;
}
}
lw->AddTail(n);
}

其中 var_score取出来后,不知道判断是不是取到了正确的值,不能直接使用,错误使用会导致崩溃,判断的方法如下:

if (var_score.vt != VT_NULL) {
n->score = _ttoi((LPCTSTR)(_bstr_t)var_score);
}

 5.删除某个节点,并保存

CString dbxml;
dbxml.Format("./xxx/%s.xml", name);
::CoInitialize(NULL);
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(__uuidof(DOMDocument60));
if (VARIANT_FALSE == doc->load(((LPSTR)(LPCSTR)dbxml))) {
doc.Release();
return 2;
}
time_t t = time(nullptr);
MSXML2::IXMLDOMNodePtr item;
CString str;
str.Format("db/item[@name='%s']", name);
//_variant_t var(str);
item = ((MSXML2::IXMLDOMNodePtr)doc)->selectSingleNode(_bstr_t(str));
if (item != NULL) {
item->GetparentNode()->removeChild(item);
}
doc->save((LPSTR)(LPCSTR)dbxml);
doc.Release();
CoUninitialize();

 6.更新xml里面某些节点的数据(先删除,再添加)

str.Format("db/item[@name='%s']/features/feature", duq.name);
//_variant_t var(str);
feature = ((MSXML2::IXMLDOMNodePtr)doc)->selectSingleNode(_bstr_t(str));
if (feature != NULL) {
((MSXML2::IXMLDOMElementPtr)feature)->setAttribute("date", t);
MSXML2::IXMLDOMNodeList *pNodeList = NULL;
feature->get_childNodes(&pNodeList);
Debug_TraceA("UpdataSingleItemToDbXML get_childNodes ");
if (pNodeList != NULL) {
for (int i = 0; i < pNodeList->Getlength(); i++) {
MSXML2::IXMLDOMNodePtr pNode;
pNodeList->get_item(i, &pNode);
feature->removeChild(pNode);
}
}
for (int i = 0; i < feature_size; i++) {
MSXML2::IXMLDOMNodePtr node_float = doc->createElement("f");
CString s;
s.Format("%.8f", userfeature[i]);
_variant_t var(s);
node_float->put_text(_bstr_t(s));
//node_float->nodeValue.fltVal = p->feature[i];// CComVariant(p->feature[i]);
feature->appendChild(node_float);
}
}
doc->save(dbxml);
doc.Release();
CoUninitialize();

 7.msxml在save的时候报错,如果路径没问题,很有可能在别的地方有xml文件的引用没有释放,必须提前释放

    try {
    doc->save((LPSTR)(LPCSTR)dbxml);
    }
    catch (_com_error errorObject){
    Debug_TraceA("Exception, HRESULT = %d  %s 
", errorObject.Error(), (LPCTSTR)errorObject.Description());
    }

可以通过上面代码查看异常

 
 
msxml坑多浪急
        MSXML2::IXMLDOMNodeList *pNodeList = NULL;
        feature->get_childNodes(&pNodeList);
        
        if (pNodeList != NULL) {
            
            //Debug_TraceA("pNodeList->Getlength() %d  %d 
", pNodeList->Getlength(), feature->GetchildNodes()->length);
            //MSXML2::IXMLDOMNodePtr pNode;
            //while (pNode = pNodeList->nextNode() != NULL) {
            //    feature->removeChild(pNode);
            //}
            for (int i = pNodeList->Getlength()-1; i >=0; i--) {
                MSXML2::IXMLDOMNodePtr pNode;
                pNodeList->get_item(i, &pNode);
                feature->removeChild(pNode);
            }
        }

这是正常的代码

这是错误的代码,因为pNodeListfeature是关联的,从前面removeChild,pNodeList->Getlength()的值在变小,每执行一次,任意一个子节点就向前移动一位,位置下标就减小1,而i是一直累加的所以会出问题

   MSXML2::IXMLDOMNodeList *pNodeList = NULL;
        feature->get_childNodes(&pNodeList);
        
        if (pNodeList != NULL) {
            
            //Debug_TraceA("pNodeList->Getlength() %d  %d 
", pNodeList->Getlength(), feature->GetchildNodes()->length);
      
            for (int i = 0; i <pNodeList->Getlength(); i++) {
                MSXML2::IXMLDOMNodePtr pNode;
                pNodeList->get_item(i, &pNode);
                feature->removeChild(pNode);
            }
        }

 同理这个也是错的

        MSXML2::IXMLDOMNodeList *pNodeList = NULL;
        feature->get_childNodes(&pNodeList);
        
        if (pNodeList != NULL) {
            
            //Debug_TraceA("pNodeList->Getlength() %d  %d 
", pNodeList->Getlength(), feature->GetchildNodes()->length);
            MSXML2::IXMLDOMNodePtr pNode;
            while (pNode = pNodeList->nextNode() != NULL) {
                feature->removeChild(pNode);
            }

        }