windwos自带的 一个xml库 MSXML 兼容宽字符
1 #include <iostream> 2 #include <tchar.h> 3 4 #import <msxml3.dll> 5 6 //节点处理函数 7 void ProcessNode(MSXML2::IXMLDOMNodePtr spNode) 8 { 9 std::cout << "nodeName: " << spNode->nodeName; 10 if (spNode->nodeType == NODE_ATTRIBUTE || spNode->nodeType == NODE_TEXT) 11 std::cout << "\tnodeValue: " << _bstr_t(spNode->nodeValue); 12 std::cout << std::endl; 13 14 if (spNode->nodeType == NODE_ELEMENT) 15 { 16 MSXML2::IXMLDOMNamedNodeMapPtr spNameNodeMap = spNode->attributes; 17 for (long i = 0; i != spNameNodeMap->length; ++i) //遍历节点属性 18 ProcessNode(spNameNodeMap->item[i]); 19 20 MSXML2::IXMLDOMNodeListPtr spNodeList = spNode->childNodes; 21 for (long i = 0; i != spNodeList->length; ++i) //遍历子节点 22 ProcessNode(spNodeList->item[i]); 23 } 24 } 25 26 int _tmain(int argc, _TCHAR* argv[]) 27 { 28 CoInitialize(NULL); 29 //读取XML 30 MSXML2::IXMLDOMDocumentPtr spXMLDoc; 31 spXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30)); 32 spXMLDoc->load(L"stocks.xml"); 33 MSXML2::IXMLDOMElementPtr spRoot = spXMLDoc->documentElement; //根节点 34 MSXML2::IXMLDOMNodeListPtr spNodeList = spRoot->childNodes; 35 for (long i = 0; i != spNodeList->length; ++i) //遍历子节点 36 ProcessNode(spNodeList->item[i]); 37 38 //写入XML 39 spRoot->selectSingleNode(L"/root/node1")->text = L"newText"; 40 spRoot->selectSingleNode(L"/root/node2/childnode1/@attrib1")->nodeValue = L"newValue"; 41 MSXML2::IXMLDOMNodePtr spNewNode = spRoot->selectSingleNode(L"/root/node2")->appendChild( 42 spXMLDoc->createNode(_variant_t(NODE_ELEMENT), L"childnode3", L"") 43 ); //给node2创建新子节点childnode3 44 spNewNode->text = L"childtext2"; 45 MSXML2::IXMLDOMElementPtr spEle = spNewNode; 46 spEle->setAttribute(L"attrib1", _variant_t(L"value1")); //添加新属性 47 spXMLDoc->save(_variant_t(L"stocks.xml")); 48 49 spNewNode.Release(); 50 spEle.Release(); 51 spNodeList.Release(); 52 spRoot.Release(); 53 spXMLDoc.Release(); 54 CoUninitialize(); 55 56 system("pause"); 57 return 0; 58 }
MFC
MFC里可以直接使用DOM,不需要手动添加额外的头文件,只需要在CWinApp::InitInstance()里调用CoInitialize(NULL)初始化COM,在CWinApp::ExitInstance里调用CoUninitialize()释放COM就行了。
1 //读取XML 2 CComPtr<IXMLDOMDocument> spDoc; //DOM 3 spDoc.CoCreateInstance(CLSID_DOMDocument); 4 VARIANT_BOOL vb; 5 spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加载XML文件 6 CComPtr<IXMLDOMElement> spRootEle; 7 spDoc->get_documentElement(&spRootEle); //根节点 8 CComPtr<IXMLDOMNodeList> spNodeList; 9 spRootEle->get_childNodes(&spNodeList); //子节点列表 10 long nLen; 11 spNodeList->get_length(&nLen); //子节点数 12 for (long i = 0; i != nLen; ++i) //遍历子节点 13 { 14 CComPtr<IXMLDOMNode> spNode; 15 spNodeList->get_item(i, &spNode); 16 ProcessNode(spNode); //节点处理函数 17 } 18 19 //写入XML 20 CComPtr<IXMLDOMNode> spNode; 21 spRootEle->selectSingleNode(OLESTR("/root/node1"), &spNode); 22 spNode->put_text(OLESTR("newText")); //写入text 23 spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode); 24 spNode->put_nodeValue(CComVariant(OLESTR("newValue"))); //写入value 25 CComPtr<IXMLDOMNode> spNewNode; 26 spDoc->createNode(CComVariant(NODE_ELEMENT), OLESTR("childnode3"), OLESTR(""), &spNewNode); //创建新节点 27 spRootEle->selectSingleNode(OLESTR("/root/node2"), &spNode); 28 spNode->appendChild(spNewNode, &spNewNode); //将新节点加为node2的子节点 29 spNewNode->put_text(OLESTR("childtext2")); //写入新节点text 30 CComQIPtr<IXMLDOMElement> spEle = spNewNode; //注意这里使用CComQIPtr 31 spEle->setAttribute(OLESTR("attrib1"), CComVariant(OLESTR("value1")));//给新节点添加属性 32 spDoc->save(CComVariant(OLESTR("stocks.xml"))); 33 34 //节点处理函数 35 void ProcessNode(CComPtr<IXMLDOMNode>& spNode) 36 { 37 CComBSTR bsNodeName; 38 spNode->get_nodeName(&bsNodeName); //节点名 39 AfxMessageBox(COLE2CT(bsNodeName)); 40 CComVariant varVal; 41 spNode->get_nodeValue(&varVal); //节点值 42 AfxMessageBox(COLE2CT(varVal.bstrVal)); 43 44 DOMNodeType eNodeType; 45 spNode->get_nodeType(&eNodeType); 46 if (eNodeType == NODE_ELEMENT) //只有NODE_ELEMENT类型才能包含有属性和子节点 47 { 48 //递归遍历节点属性 49 CComPtr<IXMLDOMNamedNodeMap> spNameNodeMap; 50 spNode->get_attributes(&spNameNodeMap); 51 long nLength; 52 spNameNodeMap->get_length(&nLength); 53 for (long i = 0; i != nLength; ++i) 54 { 55 CComPtr<IXMLDOMNode> spNodeAttrib; //注意属性也是一个IXMLDOMNode 56 spNameNodeMap->get_item(i, &spNodeAttrib); 57 ProcessNode(spNodeAttrib); 58 } 59 60 //递归遍历子节点 61 CComPtr<IXMLDOMNodeList> spNodeList; 62 spNode->get_childNodes(&spNodeList); 63 spNodeList->get_length(&nLength); 64 for (long i = 0; i != nLength; ++i) 65 { 66 CComPtr<IXMLDOMNode> spChildNode; 67 spNodeList->get_item(i, &spChildNode); 68 ProcessNode(spChildNode); 69 } 70 } 71 }
对于<tag>text</tag>这样的节点,get_nodeValue会得到空,要得到"text"的话可以遍历子节点(只有一个子节点,它的nodeName为"#text",nodeType为NODE_TEXT,nodeValue就是"text");也可以用get_text直接得到"text",但是对于这样的节点<tag>text<childtag>childtext</childtag></tag>,get_text会同时得到"text"和"childtext",不过这样的节点应该是不允许的。
DOM里使用的字符串(BSTR)都是OLESTR类型,默认情况下OLESTR是Unicode字符,MFC里可以用COLE2CT把LPCOLESTR转换为LPCTSTR。
对于自己定义的XML,大多数时候不需要遍历,可以通过调用selectNodes、selectSingleNode指定XPath直接读取某个节点或属性:
1 CComPtr<IXMLDOMDocument> spDoc; //DOM 2 spDoc.CoCreateInstance(CLSID_DOMDocument); 3 VARIANT_BOOL vb; 4 spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加载XML文件 5 CComPtr<IXMLDOMElement> spRootEle; 6 spDoc->get_documentElement(&spRootEle); //根节点 7 8 CComPtr<IXMLDOMNodeList> spNodeList; 9 CComPtr<IXMLDOMNode> spNode; 10 spRootEle->selectNodes(OLESTR("/root/node2/*"), &spNodeList); //得到node2下的所有子节点 11 spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode); //得到childnode1的attrib1属性
XPath的语法可以参考XML文档或MSDN。
最后放上xml
<?xml version="1.0" encoding="utf-8"?> <root> <node1>text1</node1> <node2> <childnode1 attrib1="value1" attrib2="value2"/> <childnode2 attrib1="value1" attrib2="value2">childtext1</childnode2> </node2> </root>