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); } }
这是正常的代码
这是错误的代码,因为pNodeList和feature是关联的,从前面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); } }