【程序】C++使用MSXML6.0的IXMLDOMDocument接口解析XML文档

【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 . . .

猜你喜欢

转载自blog.csdn.net/ZLK1214/article/details/79978704
今日推荐