C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)

这篇具有很好参考价值的文章主要介绍了C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

开发环境:Visual Studio 2010
运行环境:Windows XP SP3

第一节 读取XML文件(使用wchar_t[]字符数组)

读取XML文件可使用IXMLDOMDocument_load函数。

/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <MsXml6.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编码格式的字符串, 用wprintf的%ls输出
	  char *可以用来保存任意编码格式的字符串, 但只有ANSI格式才能使用printf的%s正确显示出来
	  在简体中文版操作系统下, ANSI就是GB2312编码
	  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
*/

// C语言自带的wprintf函数无法打印中文
// 所以这里重新实现一个能打印中文的my_wprintf函数
int my_wprintf(const wchar_t *format, ...)
{
	int n;
	va_list list;
	wchar_t str[1024];
	DWORD ret;
	HANDLE console;

	va_start(list, format);
	n = _vsnwprintf_s(str, _countof(str), _countof(str) - 1, format, list);
	va_end(list);

	console = GetStdHandle(STD_OUTPUT_HANDLE);
	WriteConsoleW(console, str, (DWORD)wcslen(str), &ret, NULL);
	return n;
}

// 显示元素节点的属性值 (元素节点是一种节点)
void display_attribute(IXMLDOMElement *elem, const wchar_t *name, int intval)
{
	int num;
	BSTR bstr; // 表示一个字符串
	VARIANT variant; // 表示一个弱类型的变量

	bstr = SysAllocString(name); // 必须用SysAllocString函数把wchar_t *字符串转换成BSTR字符串
	IXMLDOMElement_getAttribute(elem, bstr, &variant);
	SysFreeString(bstr); // 使用完字符串后必须释放

	if (variant.vt == VT_BSTR)
	{
		my_wprintf(L"[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");
	}
	VariantClear(&variant);
}

// 显示节点名称
void display_nodename(IXMLDOMNode *node)
{
	BSTR bstr;

	IXMLDOMNode_get_nodeName(node, &bstr);
	my_wprintf(L"[Node] name=%ls\n", bstr); // 使用%ls打印BSTR字符串内容
	SysFreeString(bstr); // 使用完字符串后必须释放
}

// 显示节点中的文本内容 (方法一)
void display_content(IXMLDOMNode *node)
{
	BSTR text;

	IXMLDOMNode_get_text(node, &text);
	my_wprintf(L"[Text] %ls\n", text);
	SysFreeString(text);
}

// 显示节点中的文本内容 (方法二)
// 文本内容是文本节点, 是node节点下的子节点
void display_content_2(IXMLDOMNode *node)
{
	IXMLDOMNode *child;
	VARIANT value;

	IXMLDOMNode_get_firstChild(node, &child); // 获取文本节点
	IXMLDOMNode_get_nodeValue(child, &value); // 得到文本节点的内容
	if (value.vt == VT_BSTR)
		my_wprintf(L"[Text] %ls\n", value.bstrVal);
	VariantClear(&value);
	IXMLDOMNode_Release(child);
}

// 获取节点中的XML文本内容
void display_inner_xml(IXMLDOMNode *node)
{
	BSTR bstr;

	IXMLDOMNode_get_xml(node, &bstr);
	my_wprintf(L"[InnerXML] %ls\n", bstr);
	SysFreeString(bstr);
}

void read_xml(IXMLDOMDocument *xmldoc)
{
	long i, len;
	IXMLDOMElement *root;
	IXMLDOMElement *elem;
	IXMLDOMNode *root_node;
	IXMLDOMNode *item;
	IXMLDOMNodeList *list;

	// 根节点
	IXMLDOMDocument_get_documentElement(xmldoc, &root);
	IXMLDOMNode_QueryInterface(root, &IID_IXMLDOMNode, &root_node); // 把element node变为node
	display_nodename(root_node);
	display_attribute(root, L"id", 1);
	display_inner_xml(root_node);
	printf("\n");

	// 根节点下的子节点
	IXMLDOMElement_get_childNodes(root, &list);
	IXMLDOMNodeList_get_length(list, &len);
	for (i = 0; i < len; i++)
	{
		IXMLDOMNodeList_get_item(list, i, &item);
		display_nodename(item);
		display_content(item);

		// 只有元素节点才有属性节点, 所以获取属性前要进行类型转换, 把node变为element node
		IXMLDOMNode_QueryInterface(item, &IID_IXMLDOMElement, &elem);
		display_attribute(elem, L"name", 0);
		IXMLDOMElement_Release(elem);

		IXMLDOMNode_Release(item);
	}
	IXMLDOMNodeList_Release(list);

	IXMLDOMNode_Release(root_node);
	IXMLDOMElement_Release(root);
}

// 打开XML文件
void open_xml(const wchar_t *name)
{
	HRESULT hr;
	IXMLDOMDocument *xmldoc;
	VARIANT filename;
	VARIANT_BOOL flag;

	hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);
	if (SUCCEEDED(hr))
	{
		filename.bstrVal = SysAllocString(name); // 将wchar_t *转换为BSTR
		filename.vt = VT_BSTR;
		IXMLDOMDocument_load(xmldoc, filename, &flag);
		// 注: IXMLDOMDocument_load是读XML文件
		//     IXMLDOMDocument_loadXML是读XML字符串
		VariantClear(&filename);
		if (flag == VARIANT_TRUE)
		{
			printf("读取XML文件成功\n");
			read_xml(xmldoc);
		}
		else
			printf("读取XML文件失败\n");

		IXMLDOMDocument_Release(xmldoc);
	}
}

int main()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型

	open_xml(L"data.xml");

	CoUninitialize();
	return 0;
}

 C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组),Win32,c语言,xml,msxml6,IXMLDOMDocument,COM

第二节 读取XML文件(使用char[]字符数组)

/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <MsXml6.h>

#pragma comment(lib, "msxml6.lib")

// char *转BSTR
// 用完后调用SysFreeString释放
BSTR convert_string_to_bstr(const char *s)
{
	int n;
	wchar_t *ws;
	BSTR bstr = NULL;

	n = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
	ws = malloc(n * sizeof(wchar_t));
	if (ws != NULL)
	{
		MultiByteToWideChar(CP_ACP, 0, s, -1, ws, n);
		bstr = SysAllocString(ws);
		free(ws);
	}
	return bstr;
}

// BSTR转char *
// 用完后调用free释放
char *convert_bstr_to_string(BSTR bstr)
{
	char *s;
	int n;

	n = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);
	s = malloc(n);
	if (s != NULL)
		WideCharToMultiByte(CP_ACP, 0, bstr, -1, s, n, NULL, NULL);
	return s;
}

// 显示元素节点的属性值 (元素节点是一种节点)
void display_attribute(IXMLDOMElement *elem, const char *name, int intval)
{
	char *value_str;
	int num;
	BSTR bstr; // 表示一个字符串
	VARIANT variant; // 表示一个弱类型的变量

	bstr = convert_string_to_bstr(name);
	IXMLDOMElement_getAttribute(elem, bstr, &variant);
	SysFreeString(bstr); // 使用完字符串后必须释放

	if (variant.vt == VT_BSTR)
	{
		value_str = convert_bstr_to_string(variant.bstrVal);
		printf("[Attribute] name=%s, value=%s", name, value_str);
		if (intval)
		{
			num = atoi(value_str); // 转换为整形
			printf(", 2*value=%d", 2 * num);
		}
		printf("\n");
		free(value_str);
	}
	VariantClear(&variant);
}

// 显示节点名称
void display_nodename(IXMLDOMNode *node)
{
	char *s;
	BSTR bstr;

	IXMLDOMNode_get_nodeName(node, &bstr);
	s = convert_bstr_to_string(bstr);
	printf("[Node] name=%s\n", s);
	free(s);
	SysFreeString(bstr); // 使用完字符串后必须释放
}

// 显示节点中的文本内容 (方法一)
void display_content(IXMLDOMNode *node)
{
	char *text_str;
	BSTR text;

	IXMLDOMNode_get_text(node, &text);
	text_str = convert_bstr_to_string(text);
	printf("[Text] %s\n", text_str);
	free(text_str);
	SysFreeString(text);
}

// 显示节点中的文本内容 (方法二)
// 文本内容是文本节点, 是node节点下的子节点
void display_content_2(IXMLDOMNode *node)
{
	char *value_str;
	IXMLDOMNode *child;
	VARIANT value;

	IXMLDOMNode_get_firstChild(node, &child); // 获取文本节点
	IXMLDOMNode_get_nodeValue(child, &value); // 得到文本节点的内容
	if (value.vt == VT_BSTR)
	{
		value_str = convert_bstr_to_string(value.bstrVal);
		printf("[Text] %s\n", value_str);
		free(value_str);
	}
	VariantClear(&value);
	IXMLDOMNode_Release(child);
}

// 获取节点中的XML文本内容
void display_inner_xml(IXMLDOMNode *node)
{
	char *s;
	BSTR bstr;

	IXMLDOMNode_get_xml(node, &bstr);
	s = convert_bstr_to_string(bstr);
	printf("[InnerXML] %s\n", s);
	free(s);
	SysFreeString(bstr);
}

void read_xml(IXMLDOMDocument *xmldoc)
{
	long i, len;
	IXMLDOMElement *root;
	IXMLDOMElement *elem;
	IXMLDOMNode *root_node;
	IXMLDOMNode *item;
	IXMLDOMNodeList *list;

	// 根节点
	IXMLDOMDocument_get_documentElement(xmldoc, &root);
	IXMLDOMNode_QueryInterface(root, &IID_IXMLDOMNode, &root_node); // 把element node变为node
	display_nodename(root_node);
	display_attribute(root, "id", 1);
	display_inner_xml(root_node);
	printf("\n");

	// 根节点下的子节点
	IXMLDOMElement_get_childNodes(root, &list);
	IXMLDOMNodeList_get_length(list, &len);
	for (i = 0; i < len; i++)
	{
		IXMLDOMNodeList_get_item(list, i, &item);
		display_nodename(item);
		display_content(item);

		// 只有元素节点才有属性节点, 所以获取属性前要进行类型转换, 把node变为element node
		IXMLDOMNode_QueryInterface(item, &IID_IXMLDOMElement, &elem);
		display_attribute(elem, "name", 0);
		IXMLDOMElement_Release(elem);

		IXMLDOMNode_Release(item);
	}
	IXMLDOMNodeList_Release(list);

	IXMLDOMNode_Release(root_node);
	IXMLDOMElement_Release(root);
}

// 打开XML文件
void open_xml(const char *name)
{
	HRESULT hr;
	IXMLDOMDocument *xmldoc;
	VARIANT filename;
	VARIANT_BOOL flag;

	hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);
	if (SUCCEEDED(hr))
	{
		filename.bstrVal = convert_string_to_bstr(name); // 将char *转换为BSTR
		filename.vt = VT_BSTR;
		IXMLDOMDocument_load(xmldoc, filename, &flag);
		// 注: IXMLDOMDocument_load是读XML文件
		//     IXMLDOMDocument_loadXML是读XML字符串
		VariantClear(&filename);
		if (flag == VARIANT_TRUE)
		{
			printf("读取XML文件成功\n");
			read_xml(xmldoc);
		}
		else
			printf("读取XML文件失败\n");

		IXMLDOMDocument_Release(xmldoc);
	}
}

int main()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型

	open_xml("data.xml");

	CoUninitialize();
	return 0;
}

第三节 读取XML字符串(使用char[]字符数组)

读取XML字符串可使用IXMLDOMDocument_loadXML函数。

// 读取XML字符串
void load_xml_str()
{
	char *str = "<?xml version=\"1.0\" encoding=\"utf-8\"?><data id=\"20240117\"><post name=\"2023年人口统计数据发布了,大家怎么看?\">建档788W是主体,压哨建档出生的一部分,双胞胎三胞胎占一小部分,不建档生孩子的占一小部分,但是还是难凑出902,还是得预支一下。</post><post name=\"有什么是去了成都才知道的?\">不要跟团,也不要自驾游,成都每天都人满为患,人多车堵,还不好停车,景点大部分集中在1、2、3号线,坐地铁出行就能玩转成都。2、去鹤鸣茶社品一品茶,享受宁静时光感受成都的慢生活与惬意。3、成都火锅很辣,不是很能吃辣的朋友一定不要轻易尝试,不然会被辣的怀疑人生。</post><post name=\"能否找到一个f(x),使得当x取到全体正整数的时候,f(x)可以取到全体有理数?\">题主好像没有要求是单射啊……如果只要求满射的话,其实有个简单粗暴的做法,就是把正整数劈开……</post><post name=\"C++ 有什么好用的线程池?\">题主说的那两个thread pool其实都不错,但是2024年肯定是更推荐这一个,这个就是为进入标准的senders所实现的,学了也不会白学,当然它的使用非常简单。</post><post name=\"有什么适合大学生喝的性价比高的茶?\">虽然现代社会,买东西都在追求性价比,但茶叶这东西,我觉得还真不好说!</post></data>";
	BSTR bstr;
	HRESULT hr;
	IXMLDOMDocument *xmldoc;
	VARIANT_BOOL succeeded;

	hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);
	if (SUCCEEDED(hr))
	{
		bstr = convert_string_to_bstr(str);
		hr = IXMLDOMDocument_loadXML(xmldoc, bstr, &succeeded);
		// 注: IXMLDOMDocument_load是读XML文件
		//     IXMLDOMDocument_loadXML是读XML字符串
		SysFreeString(bstr);

		if (SUCCEEDED(hr))
		{
			if (hr == S_OK)
			{
				printf("读取XML字符串成功\n");
				read_xml(xmldoc);
			}
			else if (hr == S_FALSE)
				printf("读取XML字符串失败\n");
		}

		// 另一种判断是否成功的方式
		if (succeeded == VARIANT_TRUE)
			printf("succeeded=true\n");
		else if (succeeded == VARIANT_FALSE)
			printf("succeeded=false\n");

		IXMLDOMDocument_Release(xmldoc);
	}
}

int main()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型

	load_xml_str();

	CoUninitialize();
	return 0;
}

第四节 创建XML文件(使用char[]字符数组)

创建XML文件可使用IXMLDOMDocument_save函数。

/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <time.h>
#include <MsXml6.h>

#pragma comment(lib, "msxml6.lib")

// char *转BSTR
// 用完后调用SysFreeString释放
BSTR convert_string_to_bstr(const char *s)
{
	int n;
	wchar_t *ws;
	BSTR bstr = NULL;

	n = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
	ws = malloc(n * sizeof(wchar_t));
	if (ws != NULL)
	{
		MultiByteToWideChar(CP_ACP, 0, s, -1, ws, n);
		bstr = SysAllocString(ws);
		free(ws);
	}
	return bstr;
}

// BSTR转char *
// 用完后调用free释放
char *convert_bstr_to_string(BSTR bstr)
{
	char *s;
	int n;

	n = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);
	s = malloc(n);
	if (s != NULL)
		WideCharToMultiByte(CP_ACP, 0, bstr, -1, s, n, NULL, NULL);
	return s;
}

void create_header(IXMLDOMDocument *xmldoc)
{
	BSTR target, data;
	IXMLDOMNode *header_node;
	IXMLDOMProcessingInstruction *header;
	
	// 创建XML文档头节点
	target = convert_string_to_bstr("xml");
	data = convert_string_to_bstr("version=\"1.0\" encoding=\"utf-8\"");
	IXMLDOMDocument_createProcessingInstruction(xmldoc, target, data, &header);
	SysFreeString(target);
	SysFreeString(data);

	// header转换成node, 然后添加进文档
	// 注意旧的header对象和新产生的node对象都要释放
	IXMLDOMProcessingInstruction_QueryInterface(header, &IID_IXMLDOMNode, &header_node);
	IXMLDOMProcessingInstruction_Release(header);
	IXMLDOMDocument_appendChild(xmldoc, header_node, NULL); // 最后一个参数是输出参数, 没有用
	IXMLDOMNode_Release(header_node);
}

IXMLDOMElement *create_root(IXMLDOMDocument *xmldoc)
{
	char timestr[30];
	struct tm tm;
	time_t t;
	BSTR name;
	IXMLDOMElement *root;
	IXMLDOMNode *root_node;
	VARIANT value;

	// 创建根节点
	name = convert_string_to_bstr("data");
	IXMLDOMDocument_createElement(xmldoc, name, &root);
	SysFreeString(name);
	
	// 将创建的根节点添加到文档中
	IXMLDOMElement_QueryInterface(root, &IID_IXMLDOMNode, &root_node);
	IXMLDOMDocument_appendChild(xmldoc, root_node, NULL);
	IXMLDOMNode_Release(root_node);

	// 获取当前时间
	time(&t);
	localtime_s(&tm, &t);
	strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &tm);

	// 在根节点上添加一个属性
	name = convert_string_to_bstr("timestr");
	value.bstrVal = convert_string_to_bstr(timestr);
	value.vt = VT_BSTR;
	IXMLDOMElement_setAttribute(root, name, value);
	SysFreeString(name);
	VariantClear(&value);
	return root;
}

void add_post(IXMLDOMDocument *xmldoc, IXMLDOMElement *root, const char *name, const char *text)
{
	BSTR attrname_bstr;
	BSTR nodename_bstr;
	BSTR text_bstr;
	IXMLDOMElement *elem;
	IXMLDOMNode *node;
	VARIANT value;

	nodename_bstr = convert_string_to_bstr("post");
	IXMLDOMDocument_createElement(xmldoc, nodename_bstr, &elem); // 创建element
	SysFreeString(nodename_bstr);
	IXMLDOMElement_QueryInterface(elem, &IID_IXMLDOMNode, &node); // element转node
	IXMLDOMElement_appendChild(root, node, NULL);

	// 添加name属性
	attrname_bstr = convert_string_to_bstr("name");
	value.bstrVal = convert_string_to_bstr(name);
	value.vt = VT_BSTR;
	IXMLDOMElement_setAttribute(elem, attrname_bstr, value);
	SysFreeString(attrname_bstr);
	VariantClear(&value);

	// 添加节点内文本
	text_bstr = convert_string_to_bstr(text);
	IXMLDOMElement_put_text(elem, text_bstr);
	SysFreeString(text_bstr);

	// 释放element和node对象
	// 请注意element是node的子类, 换句话说element是一种node
	IXMLDOMElement_Release(elem);
	IXMLDOMNode_Release(node);
}

void write_xml(IXMLDOMDocument *xmldoc)
{
	IXMLDOMElement *root;

	create_header(xmldoc);
	root = create_root(xmldoc);
	add_post(xmldoc, root, "RPG Maker XP", "RPG Maker XP(RPGXP)是一款可让玩家自行制作在计算机游戏中相当受欢迎的角色扮演游戏,也就是 Role-Playing Game(RPG)的软件。制作完成的游戏,即使在没有安装 RPG Maker XP 的电脑上也能运行。");
	add_post(xmldoc, root, "高精度的画面", "支持 640×480 像素分辨率 32 色真彩色图像。完全对应 Alpha Channel(每个像素的透明度),光滑的透过处理,柔和的半透明表现。画面的合成方法也增加了通常的半透明合成、加算合成和减算合成。而且字型自动映射,粗体不再引人注目。");
	add_post(xmldoc, root, "使用软件的音乐播放", "作为 BGM,主要使用 DirectMusic Synthesizer 的 MIDI 播放。因为以软件播放,所以不能用其它格式代替,音乐素材的制造人没必需考虑对各种 MIDI 音乐的对应。在制作过程中能被正常播放的 MIDI 文件,同样可以在其它环境中正常播放。");
	add_post(xmldoc, root, "灵活且强大的脚本系统", "用 RPGXP 制作完成的游戏,脚本是以 Ruby 语言编写的。预先编写的脚本可以制作十分独特和有趣的游戏,它是为了更高级的游戏制作需求准备的,使用它可以进行画面设计、编写战斗系统,以及一切的游戏要素。运用脚本制作 RPG 以外类型的游戏也是可能的。");
	add_post(xmldoc, root, "魔塔样板", "魔塔样板是一个用RPG Maker XP、RPG Maker VX、RPG Maker Vx Ace或者VB制作的一个用来制作魔塔的样板,里面有魔塔里一些基本的地图和怪物和各种宝物。制作者只需改动怪物属性和地图,其他的都可以利用复制进行制作,制作起来方便。并且制作者还可以在魔塔样板中进行更高级的操作,做出一些特别的动画或者机关,总之,魔塔样版可以制作一切类型的魔塔。但是,有些质量较差的魔塔样板会有脚本错误。最常用版本是7630。");
	add_post(xmldoc, root, "房贷利息", "房贷利息是指每个月支付给银行的利息款,计算公式为:剩余未还房款×贷款利率%÷12。若贷款100万元,利率为5.88%,则第一个月要付的利息钱是100万×5.88%÷12=4900元。也就是说“钱价”为4900元/(百万元·月)。");

	IXMLDOMElement_Release(root);
}

// 创建XML文件
void create_xml(const char *name)
{
	HRESULT hr;
	IXMLDOMDocument *xmldoc;
	VARIANT filename;

	hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);
	if (SUCCEEDED(hr))
	{
		write_xml(xmldoc);
		
		filename.bstrVal = convert_string_to_bstr(name); // 将char *转换为BSTR
		filename.vt = VT_BSTR;
		hr = IXMLDOMDocument_save(xmldoc, filename);
		VariantClear(&filename);
		if (SUCCEEDED(hr))
			printf("写入XML文件成功\n");
		else
			printf("写入XML文件失败\n");

		IXMLDOMDocument_Release(xmldoc);
	}
}

int main()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型

	create_xml("myxmlfile.xml");

	CoUninitialize();
	return 0;
}

C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组),Win32,c语言,xml,msxml6,IXMLDOMDocument,COM

C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组),Win32,c语言,xml,msxml6,IXMLDOMDocument,COM

第五节 创建XML字符串(使用char[]字符数组) 

使用IXMLDOMNode_get_xml函数获取的是单个节点的XML字符串(不包括XML头部声明)。使用IXMLDOMDocument_get_xml函数可获取整个XML文档的字符串(包括XML头部声明)。
两个函数获取到的都是UTF-16编码的BSTR字符串,可使用convert_bstr_to_string函数转换成GB2312编码的char *字符串。

void write_xml(IXMLDOMDocument *xmldoc)
{
	IXMLDOMElement *root;

	create_header(xmldoc);
	root = create_root(xmldoc);
	add_post(xmldoc, root, "配置“Debug|Win32”", "将平台工具集更改为“v143”(之前为“v100”)。");
	add_post(xmldoc, root, "配置“Debug|x64”", "将平台工具集更改为“v143”(之前为“v100”)。");
	add_post(xmldoc, root, "配置“Release|Win32”", "将平台工具集更改为“v143”(之前为“v100”)。");
	add_post(xmldoc, root, "配置“Release|x64”", "将平台工具集更改为“v143”(之前为“v100”)。");
	add_post(xmldoc, root, "正在升级项目“xmltest”...", "重定目标结束: 1 个已完成,0 个未通过,0 个已跳过");

	IXMLDOMElement_Release(root);
}

// 创建XML字符串
void create_xml_str()
{
	char *xmlstr;
	BSTR bstr;
	HRESULT hr;
	IXMLDOMDocument *xmldoc;

	hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);
	if (SUCCEEDED(hr))
	{
		write_xml(xmldoc);
		
		IXMLDOMDocument_get_xml(xmldoc, &bstr);
		xmlstr = convert_bstr_to_string(bstr);
		SysFreeString(bstr);
		printf("%s\n", xmlstr);
		free(xmlstr);

		IXMLDOMDocument_Release(xmldoc);
	}
}

int main()
{
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型

	create_xml_str();

	CoUninitialize();
	return 0;
}

C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组),Win32,c语言,xml,msxml6,IXMLDOMDocument,COM文章来源地址https://www.toymoban.com/news/detail-813754.html

到了这里,关于C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity中的文件读写TXT 与XML

    在游戏开发中,有的单机游戏会用到保存数据到本地,或者根据本地的数据来进行下次的设置。这里,鄙人介绍TXT与xml 的读写。 首先是txt: 新建一个unity工程,创建一个cube,新建一个脚本:CreatTxt挂载到cube上。然后打开脚本。输入一下的代码: 然后保存运行: 运行后的截

    2024年02月04日
    浏览(44)
  • 探索ClickHouse——同时支持导入导出功能的文件格式

    在 《探索ClickHouse——安装和测试》中,我们使用clickhouse直接从文件中读取数据。clickhouse支持多种格式文件的导入导出,本节我们对此进行分类介绍。 原始的JSON格式只支持导入,不支持导入。同时支持导入和导出的是其他几种类型: JSONEachRow JSONStringsEachRow JSONCompactEachRow

    2024年02月07日
    浏览(47)
  • Pyspark读写csv,txt,json,xlsx,xml,avro等文件

    读: 读: 写: 读: 写: 读: 写: 读: 写: 读: 写: 读: 写: 读: 写: 读: 写:

    2024年02月07日
    浏览(44)
  • Go 语言为什么不支持并发读写 map?

    大家好,我是 frank ,「 Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言项目开发中,我们经常会使用哈希表 map ,它的时间复杂度是 O(1) ,Go 语言中的 map 使用开放寻址法避免哈希碰撞。 Go 语言中的 map 并非原子操作,不支持并发读写操作。 Go 官方认为 map 在大多数情况下

    2024年02月02日
    浏览(60)
  • Java文件导入接口多参数写法 (POST方法同时支持接收文件流和其他参数)

    使用表单方式进行传输,需要注意其他参数需要使用 @RequestPart 注解进行接收,因为在 post 方法中表单传输使用@RequestParam 接收 json 格式默认视为字符串类型,接口无法映射对应实体类 @RequestParam 依赖Converter or PropertyEditor进行数据解析, @RequestPart参考’Content-Type’ header,依赖

    2024年02月16日
    浏览(52)
  • 安装Microsoft Office Home and Student 2010 时出现问题此产品要求安装 Microsoft Core XML Services(MSXML) 6.0 SP1.

    1.首先确保电脑上已经有MSXML版本6.10.1129.0。 2.在桌面创建一个记事本然后把下面这段复制进去保存退出,然后把后缀.txt改成.reg,双击运行。然后在尝试安装office2010

    2024年02月03日
    浏览(49)
  • 用go语言实现一个构建有向图的函数,同时图结构的点和边上都支持添加属性

    当然可以。下面是一个简单的用Go语言实现的有向图构建函数的示例。这个图结构使用map来存储,每个节点都由一个唯一的标识符(id)表示,并且节点和边都可以附加属性。 go 这个示例代码创建了一个有向图,并添加了两个节点(A和B)和一个从A到B的边。每个节点和边都有

    2024年01月20日
    浏览(34)
  • EPOLL单线程版本 基于reactor 的 httpserver文件下载 支持多个客户端同时处理

    之前写了一个httpserver的问价下载服务器    如果有多个客户端请求过来只能串行处理必须得等当前的操作完成之后才会处理    另外还存在 文件大的时候 会出错 处理不了  原因就是 sendfile是在一个while循环中处理的   当调用send失败返回-1之后 就  结束了   而一般来讲 

    2024年02月07日
    浏览(57)
  • C语言文件操作(文件读写)

    本文主要介绍C语言中文件操作的相关内容(例:文件读、写等相关函数)。 在对计算机的使用中我们几乎离不开文件。例如常见的有word 文档,txt文本文件,图片文件、音频文件等。 文件是以计算机硬盘为载体存储在计算机上的信息集合。是数据源的一种,最主要的作用是保

    2024年02月02日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包