新手小白,不对的请各位前辈多多指教!
这篇文章是记录:使用vs2017,C++语言,实现读取xml文本文件并保存XML节点信息时遇到的小问题。
前提:本文读取XML文件,将XML文件中的节点信息存储为数组,在使用节点信息的时候,遍历存储好的数组就可以了。
查看完整程序点击此连接:https://blog.csdn.net/qq_43688065/article/details/109601207
1.思考如何获取XML文件的属性值。
最开始我思考使用字符串分隔的方式去获取xml文件的节点信息,思路是这样的:先按行读取XML文件,获取文件的每行字符串,对字符串使用分割字符的方式进行处理。再将得到的字符串保存起来。但是用功能实现了一下,没成功,下面是我的代码以及结果。
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
#include <cassert>
using namespace std;
void txt_to_vectordouble(vector<vector<string>>& res, string pathname)
{
//此方法是读取文本文件,按行读取文本文件,并将每一行的内容存储在vector里面,最后存储在一个大vector里面
ifstream infile;
int lineIndex=0;
infile.open(pathname.data());//将文件流对象与文件连接起来
assert(infile.is_open());//assert断言,符合条件则继续执行,不满足条件程序将终止
vector<string> suanz;
string s;
while (getline(infile, s)) {//按行读取
istringstream is(s);//将读出的一行转成数据流进行操作
string d;
while (!is.eof()) {//如果不是文件尾
is >> d;
suanz.push_back(d);//存储
}
lineIndex++;
res.push_back(suanz);//存储
suanz.clear();
s.clear();
}
cout << lineIndex << endl;
infile.close();
}
int main() {
vector<vector<string>> data;
txt_to_vectordouble(data, "Config.xml");
for (int i = 0; i < data.size();i++) {
for (int j = 0; j < data[i].size();j++) {
cout << data[i][j];
}
cout << endl;
}
system("chcp 65001");//处理中文乱码的
system("pause");
return 0;
}
读取的XML:
<?xml version="1.0" encoding="gb2312"?>
<ROOT>
<FeatruePoints>
<FeatruePoint name="A-MQ1-1" recognize="1"/>
<FeatruePoint name="B-MQ1-2" recognize="1"/>
<FeatruePoint name="B-MH10-2" recognize="1"/>
<FeatruePoint name="B-MH10-3" recognize="1"/>
<FeatruePoint name="B-MH10-4" recognize="1"/>
<FeatruePoint name="B-MH10-5" recognize="1"/>
</FeatruePoints>
<WeldPoints>
<WeldPoint name="A-0-1" calculate="1" FeaturPoint1="A-MH-01"/>
<WeldPoint name="A-0-2" calculate="1" FeaturPoint1="A-MH-02"/>
<WeldPoint name="A-0-3" calculate="1" FeaturPoint1="A-MH-03"/>
<WeldPoint name="A-1-1" calculate="2" FeaturPoint1="A-MQ1-1" FeaturPoint2="A-MQ1-2" FeaturPoint3="A-MH8-1" FeaturPoint4="A-MH3-1"/>
<WeldPoint name="A-1-2" calculate="2" FeaturPoint1="A-MQ1-1" FeaturPoint2="A-MQ1-2" FeaturPoint3="A-MH8-2" FeaturPoint4="A-MH10-4"/>
<WeldPoint name="A-1-3" calculate="2" FeaturPoint1="A-MQ1-3" FeaturPoint2="A-MQ1-4" FeaturPoint3="A-MH8-3" FeaturPoint4="A-MH10-5"/>
<WeldPoint name="A-2-1" calculate="2" FeaturPoint1="A-MQ2-1" FeaturPoint2="A-MQ2-2" FeaturPoint3="A-MH8-1" FeaturPoint4="A-MH3-1"/>
<WeldPoint name="A-2-2" calculate="2" FeaturPoint1="A-MQ2-1" FeaturPoint2="A-MQ2-2" FeaturPoint3="A-MH8-2" FeaturPoint4="A-MH10-4"/>
<WeldPoint name="A-2-3" calculate="2" FeaturPoint1="A-MQ2-3" FeaturPoint2="A-MQ2-4" FeaturPoint3="A-MH8-3" FeaturPoint4="A-MH10-5"/>
</WeldPoints>
<Roads>
<Road name="路径0,三点点焊">
<Point name="A-0-1"/>
<Point name="A-0-2"/>
<Point name="A-0-3"/>
</Road>
<Road name="路径1">
<Point name="A-1-1"/>
<Point name="A-1-2"/>
<Point name="A-1-3"/>
</Road>
<Road name="路径2">
<Point name="A-2-1"/>
<Point name="A-2-2"/>
<Point name="A-2-3"/>
</Road>
</Roads>
<Schemes>
<Scheme name="点固">
<WRoad name="路径0"/>
<WRoad name="路径1"/>
<WRoad name="路径2"/>
</Scheme>
<Scheme name="划线">
<WRoad name="路径1"/>
<WRoad name="路径2"/>
</Scheme>
<Scheme name="点焊">
<WRoad name="路径1"/>
<WRoad name="路径2"/>
</Scheme>
<Scheme name="连续">
<WRoad name="路径1"/>
<WRoad name="路径2"/>
</Scheme>
</Schemes>
</ROOT>
运行结果:
中文乱码一直是心头病啊,没找到合适的处理方法。但是XML文件的内容都获取到了。
但是要使用字符串分隔就很麻烦了,因为XML里面的数据是随时变化的,如果使用字符串分隔,移植效果不好,而且如果后期要增加XML文件的行数或者一行的长度,程序会崩溃的。
后来发现使用字符串分割的方法并不好,就去搜了一些资料,后来发现使用外部资源类tinyXML处理XML更为合适,果断更换了实现思路。
tinyxml的下载:http://grinninglizard.com/tinyxml2docs/index.html
下载后将tinystr.h、tinystr.cpp、tinyxml.h、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp这6个复制到工程里面。如图。别忘了程序的根目录里面也要加,我将这6个文件存放在readXML文件夹里,所以引入头文件的时候也要加上这个文件夹的名字。
#include "readXML/tinystr.h"
#include "readXML/tinyxml.h"
此时读取XML文件的思路就有啦。按照这个思路继续往下写。
2.第二个问题是:我存储数据的时候有的使用了两层结构体嵌套,两个结构体嵌套的时候不知道怎么向里面那层结构体赋值。后来去百度了以下,找到如下解决办法:
struct WeldPoints {//计算点结构体
string weldPointName;
int calculate;
struct FeaturePoint {//这里使用结构体嵌套
vector<string> featurePoint;
}featpoint;//必须声明一个结构体变量,不然下面程序没法访问到FeaturePoint里面的属性
};
struct Roads {
struct Road {//结构体嵌套
string roadName;
vector<string> pointName;
}road;//必须声明。解释同上
};
赋值:
struct WeldPoints welds;//创建结构体变量
welds.featpoint.featurePoint.push_back (pWeld_FeaturPoint->Value());//赋值
struct Roads roads;//创建结构体变量
roads.road.pointName.push_back(pPoint->Value());//赋值
这样就赋值成功啦。
3.在使用tinyXML获取节点属性时,不知道如何获取兄弟节点,以及节点中的第二个属性。解决方法如下:
兄弟节点:NextSiblingElement();
TiXmlElement *WeldPoints = FeatruePoints->NextSiblingElement();//得到FeaturePoints的兄弟节点WeldPoints
cout << "文件中第二个要遍历的节点" << WeldPoints->Value() << endl;//输出WeldPoints
获取第二个属性:Next();
TiXmlAttribute *pWeldPoint = WeldPoint->FirstAttribute();//得到WeldPoint的第一个属性name
TiXmlAttribute *pcalculate = pWeldPoint->Next();//得到WeldPoint的第二个属性recognize
4.这个问题我自己也有点懵,如果有大神明白,求赐教!
我在存储如下图这个节点信息的时候
<WeldPoints>
<WeldPoint name="A-0-1" calculate="1" FeaturPoint1="A-MH-01"/>
<WeldPoint name="A-0-2" calculate="1" FeaturPoint1="A-MH-02"/>
<WeldPoint name="A-0-3" calculate="1" FeaturPoint1="A-MH-03"/>
<WeldPoint name="A-1-1" calculate="2" FeaturPoint1="A-MQ1-1" FeaturPoint2="A-MQ1-2" FeaturPoint3="A-MH8-1" FeaturPoint4="A-MH3-1"/>
<WeldPoint name="A-1-2" calculate="2" FeaturPoint1="A-MQ1-1" FeaturPoint2="A-MQ1-2" FeaturPoint3="A-MH8-2" FeaturPoint4="A-MH10-4"/>
<WeldPoint name="A-1-3" calculate="2" FeaturPoint1="A-MQ1-3" FeaturPoint2="A-MQ1-4" FeaturPoint3="A-MH8-3" FeaturPoint4="A-MH10-5"/>
<WeldPoint name="A-2-1" calculate="2" FeaturPoint1="A-MQ2-1" FeaturPoint2="A-MQ2-2" FeaturPoint3="A-MH8-1" FeaturPoint4="A-MH3-1"/>
<WeldPoint name="A-2-2" calculate="2" FeaturPoint1="A-MQ2-1" FeaturPoint2="A-MQ2-2" FeaturPoint3="A-MH8-2" FeaturPoint4="A-MH10-4"/>
<WeldPoint name="A-2-3" calculate="2" FeaturPoint1="A-MQ2-3" FeaturPoint2="A-MQ2-4" FeaturPoint3="A-MH8-3" FeaturPoint4="A-MH10-5"/>
</WeldPoints>
最开始结构体我是这样定义的:
struct WeldPoints {//计算点结构体
string weldPointName;
int calculate;
vector<string> featurePoint;
};
将所有点信息存储在string类型的vector里面,刚开始没觉得有什么问题,后来输出的时候,发现有的name里面包含一个点信息,有的name里面包含四个点信息,没办法和name对应输出。我想的解决办法是将整个WeldPoints信息存储在vector里面,再将featurePoint清空,但是按照这种方法我测试了一下发现并不对。因为清空后featurePoint里面什么都没有了。输出的时候也是空值。
后来改变了结构体的形式,变成如下形式:
struct WeldPoints {//计算点结构体
string weldPointName;
int calculate;
struct FeaturePoint {//这里使用结构体嵌套
vector<string> featurePoint;
}featpoint;//必须声明一个结构体变量,不然下面程序没法访问到FeaturePoint里面的属性
};
结构体里面嵌套一个结构体,就可以将FeaturPoint的个数和name对应输出。而且将整个WeldPoints存储在vector后,将featurePoint使用clear()函数清空后,程序也不报错,也可以正常输出。迷惑行为!
这就是我在实现vs2017读取XML文件并获取节点信息时遇到的问题。在此做个记录。