首页 > 编程语言 >VC++ 2019 MFC TinyXML2使用教程/方法详解(转载)

VC++ 2019 MFC TinyXML2使用教程/方法详解(转载)

时间:2023-11-21 17:36:22浏览次数:45  
标签:xml MFC tinyxml2 TinyXML2 C++ messageNode docXml root 节点

转载地址:

VC++ 2019 MFC TinyXML2使用教程/方法详解_vc++2019_一笑的博客-CSDN博客

TinyXML2让VC++中操作XML,如鱼得水,就像一个小型的数据库,特别方便。

本篇主要介绍在VC++ 2019的MFC项目中,如何利用TinyXML2,创建、插入、查询、更新、删除节点或数据。

也顺便介绍下UNICODE转UTF8,因TinyXML2生成的XML文件是UTF-8编码,VS2019开发工具是UNICODE编码,所以,中文不转换会写入乱码。

一、创建MFC项目 MFCTinyXML2

  1. 应用程序类型选择“基于对话框”
  2. 主框架样式仅选择“粗框架”,其他样式无需选择
  3. 高级功能处全部全部不要选

二、下载源码并复制到MFC项目中

1、源码地址:https://github.com/leethomason/tinyxml2

 

2、将版本库中的tinyxml2.cpp和tinyxml2.h复制到项目中(源码中的文件很多,但,只需要这两个文件~,其他文件直接删掉就好了)

 


在Dialog界面增加几个按钮,最终项目目录结构如下

 


在主Dlg类中引用tinyxml2/tinyxml2.h

 


在项目中,选中tinyxml2.cpp文件,点击右键查看其属性,将“C/C++” - “预编译头” - 设置为“不使用预编译头”(如不设置,VS2019会“温馨”提示你没有使用pch.h这个预编译头文件)

 


OK,至此已可正常使用tinyxml2中的类和方法了。

三、创建XML,并保存到XML文件中

//使用以下内容建立XMLDocument
const char* xmlContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
tinyxml2::XMLDocument docXml;    
docXml.Parse(xmlContent);//添加root节点
tinyxml2::XMLElement* root = docXml.NewElement("root");
docXml.InsertEndChild(root);//添加message节点
tinyxml2::XMLElement* messageNode = docXml.NewElement("message");
messageNode->SetAttribute("username", "zhangsan");//属性
messageNode->SetText("hello");//内容
root->InsertEndChild(messageNode);//保存成XML文件
docXml.SaveFile("XMLFile.xml");

 

生成的XML文件,如下

<?xml version="1.0" encoding="utf-8"?>
<root><message username="zhangsan">hello</message>
</root>

 

四、读取XML

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");//读取上边生成的XML文件,如果还没有生成,会报错:load xml file failed.
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();

    //获取message节点
    tinyxml2::XMLElement* messageNode = root->FirstChildElement("message");

    //获取message->username属性的值
    const char* username = messageNode->FindAttribute("username")->Value();

    //获取message的内容
    const char* content = messageNode->GetText();
    
    //弹窗展示读取到的信息
    CString str;
    str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(username), Char2Wchar(content));
    AfxMessageBox(str);
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

Char2Wchar转宽字节方法代码

wchar_t* Char2Wchar(const char* str, UINT CodePage) {
    //先获取转换成宽字符后的长度
    int nLen = MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, NULL, 0);
    //声明一个宽字符类型变量,用于存放转换后的字符
    wchar_t* wstr = new wchar_t[nLen];
    //利用微软ANSI转宽字符的函数(name:ANSI字符,wname:宽字符)
    MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, wstr, nLen);

    return wstr;
}

 

效果:XML文件不存在时,会提示

 


效果:读取成功后

 

五、新增节点

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();

    //循环增加3次message节点
    const char* arrUsername[3] = {"lisi","wangwu","zhaoliu"};
    for (int i = 0; i < 3; i++)
    {
        //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement)
        tinyxml2::XMLElement* messageNode = docXml.NewElement("message");
        messageNode->SetAttribute("username", arrUsername[i]);//属性
        messageNode->SetText(i);//内容
        root->InsertEndChild(messageNode);
    }

    //不要忘记保存一下
    docXml.SaveFile("XMLFile.xml");
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:增加了0/1/2三条message节点记录

 

六、查询

1、根据属性值(如:username = wangwu)查找
方法

/// <summary>
/// 根据属性/值查询节点
/// </summary>
/// <param name="root">xml root节点</param>
/// <param name="elementName">要查询的节点,一般是多行的</param>
/// <param name="attributeName">节点的属性名</param>
/// <param name="attributeValue">节点的属性值</param>
/// <returns></returns>
tinyxml2::XMLElement* queryXMLElementByAttribute(tinyxml2::XMLElement* root, const char* elementName, const char* attributeName, const char* attributeValue) {
    tinyxml2::XMLElement* node = root->FirstChildElement(elementName);
    while (node != NULL)
    {
        const char* value = node->Attribute(attributeName);
        //比较两个字符串char*是否相等(const char*,不能直接使用等号比较)
        if (strcmp(value, attributeValue) == 0)
            break;

        node = node->NextSiblingElement();
    }

    return node;
}

 

调用

const char* whereUsername = "wangwu";

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();
    tinyxml2::XMLElement* messageNode = tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "wangwu");

    //最后保留下的这个节点就是查询到的节点
    //弹窗展示读取到的信息
    CString str;
    str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(messageNode->Attribute("username")), Char2Wchar(messageNode->GetText()));
    AfxMessageBox(str);
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:

 

2、根据值查找(同理)

七、更新

1、更新属性值

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();

    //查询
    tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "lisi");
    //更新
    messageNode->SetAttribute("username", "lisi1234");//改成lisi1234
    //不要忘记保存一下
    docXml.SaveFile("XMLFile.xml");
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:

 

2、更新内容(同理)

八、删除

1、删除指定节点

tinyxml2::XMLDocument docXml;
    tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
    if (xmlError == tinyxml2::XML_SUCCESS) {
        //获取root节点
        tinyxml2::XMLElement* root = docXml.RootElement();

        //查询
        tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "zhaoliu");
        //删除查询到的节点
        root->DeleteChild(messageNode);
        
        //不要忘记保存一下
        docXml.SaveFile("XMLFile.xml");
    }
    else {
        AfxMessageBox(_T("load xml file failed."));
    }

 

2、删除全部子节点
代码:

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();
    //删除查询到的节点
    root->DeleteChildren();

    //不要忘记保存一下
    docXml.SaveFile("XMLFile.xml");
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:

 

九、获取XML文件全部内容

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    tinyxml2::XMLPrinter printer;
    docXml.Print(&printer);

    AfxMessageBox(Char2Wchar(printer.CStr()));
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:

 

十、UTF-8编码的XML中,增加中文节点(中文乱码处理办法)

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();

    //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement)
    tinyxml2::XMLElement* messageNode = docXml.NewElement("message");

    messageNode->SetAttribute("username", "王二麻子");//属性
    messageNode->SetText("中文内容测试");//内容

    root->InsertEndChild(messageNode);

    //不要忘记保存一下
    docXml.SaveFile("XMLFile.xml");
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

使用以上代码,不做任何处理,会出现如下情况(乱码)

 


之所以中文会乱码,分析原因为:VS是使用UNICODE编码(UTF16),直接用写入UTF8编码的XML文件中,当然会乱码,因此,需要做如下转换:

  1. ASCII(char*)转宽字节(wchar_t*/UNICODE/CP_ACP,因为微软有提供函数MultiByteToWideChar)
  2. UNICODE以UTF8(CP_UTF8)编码转ASCII

转换成UTF8编码的代码:

char* Ascii2Unicode2Utf8(const char* str) {
    //ASCII to Unicode(CP_ACP)
    int nLen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[nLen];
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, nLen);

    //Unicode to UTF-8
    int nLenUTF8 = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* strUTF8 = new char[nLenUTF8];
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, strUTF8, nLenUTF8, NULL, NULL);

    return strUTF8;
}

 

使用了转UTF8编码的方法后,生成XML不再乱码了

tinyxml2::XMLDocument docXml;
tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
if (xmlError == tinyxml2::XML_SUCCESS) {
    //获取root节点
    tinyxml2::XMLElement* root = docXml.RootElement();

    //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement)
    tinyxml2::XMLElement* messageNode = docXml.NewElement("message");

    messageNode->SetAttribute("username", Ascii2Unicode2Utf8("王二麻子"));//属性
    messageNode->SetText(Ascii2Unicode2Utf8("中文内容测试"));//内容

    root->InsertEndChild(messageNode);

    //不要忘记保存一下
    docXml.SaveFile("XMLFile.xml");
}
else {
    AfxMessageBox(_T("load xml file failed."));
}

 

效果:中文字内容写入正常

 

十一、本篇文章项目源码

https://gitee.com/kefong/MFCTinyxml2.git

 

标签:xml,MFC,tinyxml2,TinyXML2,C++,messageNode,docXml,root,节点
From: https://www.cnblogs.com/ckrgd/p/17846779.html

相关文章

  • c++文件的操作
    文件操作:c++对文件的操作需要包含头文件<fstream>文件的类型,主要分为文本文件(ASCII形式存在电脑) 和二进制文件。文件操作方式:1.写文件(ofstream)2.读文件(ifstream)3.读写文件(fstream) 写文件步骤:1.包含头文件》2.创建流对象》3.打开文件》4.写数据》5.关闭流#inc......
  • c++总结
    const在不同位置时的不同意义指针类型前:声明一个指向常量的指针,程序中不能通过指针来改变它所指向的值,但指针本身的值可以改变,即指针可以指向其他数据;"*"号和指针名之间,声明一个指针常量(常指针),指针本身的值不可改变,即不能指向其他数据,但指向的数据的值可以改变两个地方都加,声明......
  • 医院影像归档和通信系统源码(C++pacs系统源码)
    PACS系统,意为影像归档和通信系统。它是应用在医院影像科室的系统,主要的任务就是把日常产生的各种医学影像(包括核磁,CT,超声,各种X光机,各种红外仪、显微仪等设备产生的图像)通过各种接口(模拟,DICOM,网络)以数字化的方式海量保存起来,当需要的时候在一定的授权下能够很快的调回使用,同时增加一......
  • C++ LibCurl实现Web隐藏目录扫描
    LibCurl是一个开源的免费的多协议数据传输开源库,该框架具备跨平台性,开源免费,并提供了包括HTTP、FTP、SMTP、POP3等协议的功能,使用libcurl可以方便地进行网络数据传输操作,如发送HTTP请求、下载文件、发送电子邮件等。它被广泛应用于各种网络应用开发中,特别是涉及到数据传输的场景。......
  • C++ 20 编译期类型名获取
    编译期类型名获取C++20标准,使用库std::source_location。#include<source_location>C++20之前在C++20前有两种方法__PRETTY_FUNCTION____FUNCSIG__通过截取函数签名中的T=...获取函数类型。template<typenameT>constexprautotype_name()->std::stri......
  • 【尝试逆向】零基础尝试寻找某个C++游戏的文件读取方法
    前言本游戏在国内知名度非常一般,而且在游戏领域也算是非常少见的厂商完全不考虑国际化的游戏系列,距今已有近30年的历史。这次为了尝试对此游戏的贴图进行提取,我尝试下载了本游戏系列的大概所有版本,并尝试通过脱壳等手段找到贴图的提取函数,并想办法写出来提取用的脚本。不过目前......
  • 【C++】【OpenCV】【NumPy】图像数据的访问
    接上一随笔,这次学习针对图像数据的访问(Numpy.array)在OpenCV中,使用imread()方法可以访问图像,其返回值是一个数组,而根据传入的不同图像,将会返回不同维度的数组。针对返回的图像数据,即数组,我们是可以进行操作的:1importcv223#MyPic.png图像自行随意创建一个原始字符转换......
  • 新版Testwell CTC++带来哪些新变化?
    TestwellCTC++在版本10中引入了新的工具ctcreport来直接从符号和数据文件生成HTML报告。详细的特性描述可以在测试井CTC++帮助中找到。在本文档中,描述了与前一代报告相比的改进和变化。 AdaptableLayout可调整布局您可以选择一个适合于项目结构的布局。布局决定了报告的详细......
  • C++与Lua交互之配置&交互原理&示例
    Lua简介Lua是一种轻量小巧的脚本语言,也是号称性能最高的脚本语言,它用C语言编写并以源代码形式开放。某些程序常常需要修改内容,而修改的内容不仅仅是数据,更要修改很多函数的行为。而修改函数行为这种事,很难用简单的更改数据的方式来实现,若在源代码层面上改又得重新编译生成,导......
  • C++U5-06-广度优先搜索3
    广搜逻辑  广搜代码核心思路 广搜伪代码前面讲解的广度优先搜索案例都类似迷宫类的问题,但有些非迷宫类问题也可以使用广搜的思路解决[【广搜】转弯]【算法分析】可以以转弯次数为依据进行广搜,这样就是每一个方向都走到尽头。特别要注意的是当这个位置访问过,还......