【C++程序】
#include <MsXml6.h> #include <stdio.h> #pragma comment(lib, "msxml6.lib") /* 参考资料: (1) VARIANT结构体: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373687(v=vs.85).aspx VARIANT用于表示一个弱类型的变量 (2) BSTR字符串: https://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspx BSTR字符串是用于COM组件对象模型的字符串格式, 字符串以表示字符串长度的4字节整数开始, 然后跟上UTF-16编码的wchar_t字符串(包括\0结束标志)。BSTR类型的变量是一个指针, 指向字符串的第一个字符处 例如, 一段起始地址为1000的内存空间, 则1000~1003这四个字节存放字符串的长度, 1004开始才是字符串的真正内容, BSTR变量应指向1004而不是1000 wchar_t *用于保存UTF-16编码格式的字符串, printf用%ls输出(不能有中文, 否则会出错) 要输出含有中文的wchar_t *字符串, 请使用WriteConsoleW函数 char *可以用来保存任意编码格式的字符串, 但只有ANSI格式才能使用printf的%s正确显示出来 在简体中文版操作系统下, ANSI就是GBK编码 MultiByteToWideChar函数可以将char *字符串转换为wchar_t *字符串 WideCharToMultiByte函数可以将wchar_t *字符串转换为char *t字符串 SysAllocString函数可以将wchar_t *字符串转换为BSTR字符串 (3) IXMLDOMDocument接口: https://msdn.microsoft.com/en-us/library/windows/desktop/dd892951(v=vs.85).aspx (4) 组件对象模型COM: https://msdn.microsoft.com/en-us/library/windows/desktop/ff485848(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/windows/desktop/ms680573(v=vs.85).aspx (5) Windows窗口程序: https://msdn.microsoft.com/en-us/library/windows/desktop/ff381409(v=vs.85).aspx */ // 显示元素节点的属性值 (元素节点是一种节点) void display_attribute(IXMLDOMElement *elem, const wchar_t *name, bool intval = false) { BSTR bstr; // 表示一个字符串 int num; VARIANT variant; // 表示一个弱类型的变量 bstr = SysAllocString(name); // 必须用SysAllocString函数把wchar_t *字符串转换成BSTR字符串 elem->getAttribute(bstr, &variant); SysFreeString(bstr); // 使用完字符串后必须释放 printf("[Attribute] name=%ls, value=%ls", name, variant.bstrVal); // BSTR和wchar_t *字符串都用%ls输出 if (intval) { num = _wtoi(variant.bstrVal); // 转换为整形 printf(", 2*value=%d", 2 * num); } printf("\n"); SysFreeString(variant.bstrVal); // 保存在Variant中的BSTR也必须释放掉 } // 显示节点名称 void display_nodename(IXMLDOMNode *node) { BSTR bstr; node->get_nodeName(&bstr); printf("[Node] name=%ls\n", bstr); // 使用%ls打印BSTR字符串内容 SysFreeString(bstr); // 使用完字符串后必须释放 } // 显示节点中的文本内容 (方法一) /* void display_content(IXMLDOMNode *node) { BSTR text; node->get_text(&text); printf("[Text] %ls\n", text); SysFreeString(text); } */ // 显示节点中的文本内容 (方法二) // 文本内容是文本节点, 是node节点下的子节点 void display_content(IXMLDOMNode *node) { IXMLDOMNode *child; VARIANT value; node->get_firstChild(&child); // 获取文本节点 child->get_nodeValue(&value); // 得到文本节点的内容 printf("[Text] %ls\n", value.bstrVal); SysFreeString(value.bstrVal); child->Release(); } // 获取节点中的XML文本内容 void display_inner_xml(IXMLDOMNode *node) { BSTR bstr; node->get_xml(&bstr); printf("[InnerXML] %ls\n", bstr); SysFreeString(bstr); } void read_xml(IXMLDOMDocument *pDoc) { // 根节点 IXMLDOMElement *root; pDoc->get_documentElement(&root); display_nodename(root); display_attribute(root, L"id", true); display_inner_xml(root); printf("\n"); // 根节点下的子节点 IXMLDOMNodeList *list; long i, len; root->get_childNodes(&list); list->get_length(&len); for (i = 0; i < len; i++) { IXMLDOMNode *item; list->get_item(i, &item); display_nodename(item); display_content(item); // 只有元素节点才有属性节点, 所以获取属性前要进行类型转换, 把node变为element node IXMLDOMElement *elem; item->QueryInterface(&elem); display_attribute(elem, L"name"); elem->Release(); item->Release(); printf("\n"); } list->Release(); root->Release(); } // 打开XML文件 void open_xml(const wchar_t *name) { HRESULT hr; IXMLDOMDocument *pDoc; hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDoc)); if (SUCCEEDED(hr)) { VARIANT filename; VARIANT_BOOL flag; filename.bstrVal = SysAllocString(name); // 将wchar_t *转换为BSTR filename.vt = VT_BSTR; pDoc->load(filename, &flag); SysFreeString(filename.bstrVal); if (flag == VARIANT_TRUE) { printf("Load succeeded!\n"); read_xml(pDoc); } else printf("Load failed!\n"); pDoc->Release(); } } int main(void) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型 open_xml(L"data.xml"); CoUninitialize(); return 0; }
【XML文档】
文档的标签之间最好不要用回车换行和空格,否则很容易被误识别为文本节点。
<?xml version="1.0" encoding="utf-8"?><data id="105"><book name="haha">abcd</book><book name="hoho">efgh</book></data>
【程序运行结果】
Load succeeded! [Node] name=data [Attribute] name=id, value=105, 2*value=210 [InnerXML] <data id="105"><book name="haha">abcd</book><book name="hoho">efgh</b ook></data> [Node] name=book [Text] abcd [Attribute] name=name, value=haha [Node] name=book [Text] efgh [Attribute] name=name, value=hoho Press any key to continue . . .