作者:孤魂地狱 | 来源:互联网 | 2023-09-18 11:08
1 #include
2 #include
3
4 #import
5
6 //节点处理函数
7 void ProcessNode(MSXML2::IXMLDOMNodePtr spNode)
8 {
9 std::cout <<"nodeName: " <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 spDoc; //DOM
3 spDoc.CoCreateInstance(CLSID_DOMDocument);
4 VARIANT_BOOL vb;
5 spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加载XML文件
6 CComPtr spRootEle;
7 spDoc->get_documentElement(&spRootEle); //根节点
8 CComPtr 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 spNode;
15 spNodeList->get_item(i, &spNode);
16 ProcessNode(spNode); //节点处理函数
17 }
18
19 //写入XML
20 CComPtr 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 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 spEle = spNewNode; //注意这里使用CComQIPtr
31 spEle->setAttribute(OLESTR("attrib1"), CComVariant(OLESTR("value1")));//给新节点添加属性
32 spDoc->save(CComVariant(OLESTR("stocks.xml")));
33
34 //节点处理函数
35 void ProcessNode(CComPtr& 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 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 spNodeAttrib; //注意属性也是一个IXMLDOMNode
56 spNameNodeMap->get_item(i, &spNodeAttrib);
57 ProcessNode(spNodeAttrib);
58 }
59
60 //递归遍历子节点
61 CComPtr spNodeList;
62 spNode->get_childNodes(&spNodeList);
63 spNodeList->get_length(&nLength);
64 for (long i = 0; i != nLength; ++i)
65 {
66 CComPtr spChildNode;
67 spNodeList->get_item(i, &spChildNode);
68 ProcessNode(spChildNode);
69 }
70 }
71 }对于text这样的节点,get_nodeValue会得到空,要得到"text"的话可以遍历子节点(只有一个子节点,它的nodeName为"#text",nodeType为NODE_TEXT,nodeValue就是"text");也可以用get_text直接得到"text",但是对于这样的节点textchildtext,get_text会同时得到"text"和"childtext",不过这样的节点应该是不允许的。
DOM里使用的字符串(BSTR)都是OLESTR类型,默认情况下OLESTR是Unicode字符,MFC里可以用COLE2CT把LPCOLESTR转换为LPCTSTR。
对于自己定义的XML,大多数时候不需要遍历,可以通过调用selectNodes、selectSingleNode指定XPath直接读取某个节点或属性:
1 CComPtr spDoc; //DOM
2 spDoc.CoCreateInstance(CLSID_DOMDocument);
3 VARIANT_BOOL vb;
4 spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加载XML文件
5 CComPtr spRootEle;
6 spDoc->get_documentElement(&spRootEle); //根节点
7
8 CComPtr spNodeList;
9 CComPtr 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>text1node1>
<node2>
<childnode1 attrib1="value1" attrib2="value2"/>
<childnode2 attrib1="value1" attrib2="value2">childtext1childnode2>
node2>
root>