vs2017、C++、读取XML文件,并获取里面的节点值

新手小白,不对的请各位前辈多多指教!

这篇文章是记录:使用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文件的行数或者一行的长度,程序会崩溃的。

上面代码参考文章:https://blog.csdn.net/wyf826459/article/details/89156670?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf

后来发现使用字符串分割的方法并不好,就去搜了一些资料,后来发现使用外部资源类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文件并获取节点信息时遇到的问题。在此做个记录。

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值