XML语言数据读写理解9
因为篇幅原因就不把上一节的XML文件粘贴上来了,大家可以返回去看。
现在,我们需要把所有的node都读出来,然后保存到一个容器里。要注意的一点是所有的数值都是根据NormalizedIntensity的大小进行排序的,我们存储也要按照顺序来存储,这样以后应用的时候也更方便一些。
我们使用QList来存储,首先再Node节点底下设置一个别名:typedef QList<NodeTS> NodeTsList; 这样会以后更方便。要注意的是,下一级的节点要读出的数据中,不但要有Nodes,还有三个变量:
<DensityScale Value="100"/>
<ShadingType Value="2"/>
<GradientFactor Value="3"/>
为了更完整性,把上一章实现的最基础文件再贴上来,这里已经进行了一些更好的修改:
#pragma once
#ifndef _COMMONXML_H__
#define _COMMONXML_H__
#include <QObject>
#include <qstring.h>
#include <QFile>
#include <QtXml\QtXml>
#include <QtXml\QDomDocument>
class CommonXML : public QObject {
Q_OBJECT
public:
CommonXML& operator = (const CommonXML& Other) {
Name = Other.Name;
return *this;
}
CommonXML(const CommonXML& Other)
{
Name = Other.Name;
*this = Other;
};
private:
QString Name;
public:
CommonXML(QObject * parent = Q_NULLPTR);
~CommonXML();
private:
};
#endif
#include "commonxml.hpp"
CommonXML::CommonXML(QObject * parent) : QObject(parent) {
}
CommonXML::~CommonXML() {
}
然后是派生类:
#pragma once
#ifndef _NODETS_H__
#define _NODETS_H__
#include <QObject>
#include <QColor.h>
#include <qlist.h>
#include "commonxml.hpp"
class NodeTS : public CommonXML {
Q_OBJECT
public:
NodeTS(QObject * parent = Q_NULLPTR);
~NodeTS();
NodeTS& operator = (const NodeTS& Other) {
return *this;
}
NodeTS(const NodeTS& Other)
{
*this = Other;
};
void readNode(QDomNodeList &node);
private:
double NormalizedIntensity;
double Opacity;
QColor Emission;
};
typedef QList<NodeTS> NodeTsList;
#endif
#include "nodets.hpp"
NodeTS::NodeTS(QObject * parent) : CommonXML(parent) {
}
NodeTS::~NodeTS() {
}
void NodeTS::readNode(QDomNodeList & nodelist)
{
for (int i = 0; i < nodelist.count(); i++)
{
QDomNode node = nodelist.at(i);
if (node.toElement().tagName() == "NormalizedIntensity") {
NormalizedIntensity = node.toElement().attribute("value").toDouble();
}
else if(node.toElement().tagName() == "Opacity") {
Opacity = node.toElement().attribute("value").toDouble();
}
else if (node.toElement().tagName() == "Emission") {
Emission.setRed(Opacity = node.toElement().attribute("R").toInt());
Emission.setGreen(Opacity = node.toElement().attribute("G").toInt());
Emission.setBlue(Opacity = node.toElement().attribute("B").toInt());
}
//realDatanode.toElement().attribute("param1") +
}
}
注意在每个文件里都加了运算符重载= ,以及拷贝构造函数。这是为了使用QList.append()函数的,因为QList加入子代码块里的新的对象需要对其进行复制,否则原对象消失了就没有了,所以需要定义拷贝构造函数。
然后我们现在的意义是先把所有的数据先都读出来,然后存储到我们需要的列表里,最后我们要直接从QList里面取数据,而不是直接从QDomdocument以及QDomElement里面读取。(注意我们的目的是拿出来并使用这些数据,而不是把它们存在xml文件结构里面!)
之后我们再派生一个类:
#pragma once
#ifndef __TSFUNITEM_H__
#define __TSCUNITEM_H__
#include <QObject>
#include "nodets.hpp"
class TsfunItem : public QObject {
Q_OBJECT
public:
TsfunItem(QObject * parent = Q_NULLPTR);
~TsfunItem();
TsfunItem& operator = (const TsfunItem& Other) {
return *this;
}
TsfunItem(const TsfunItem& Other)
{
*this = Other;
};
void readTsfunItem(QDomNodeList &nodes);
int returnNumOfNodes(void) {
return numOfNodes;
}
private:
int numOfNodes;
NodeTsList TsNodes;
double DensityScale;
double ShadingType;
double GradientFactor;
};
typedef QList<TsfunItem> TsfunItemList;
#endif
还有操作符重载和拷贝构造函数,原因同上。在私有成员里面有所有子节点的信息。我们就只先考虑这么多内容。
之后我们的目标就是把XML里面的两个TsfunItem中的任何一个都能读入。注意readTsfunItem接收的参数也是节点列表形式的。
之后我们完善函数:
#include "tsfunitem.hpp"
TsfunItem::TsfunItem(QObject * parent) : QObject(parent) {
}
TsfunItem::~TsfunItem() {
}
void TsfunItem::readTsfunItem(QDomNodeList & nodes)
{
for (int i = 0; i < nodes.count(); i++)
{
QDomNode childNode = nodes.at(i);
if (childNode.toElement().tagName() == "Nodes") {
QDomNodeList nodeData = childNode.childNodes();
for (int i = 0; i < nodeData.count(); i++)
{
NodeTS nodets;
nodets.readNode(nodeData.at(i).childNodes());
TsNodes.append(nodets);
}
numOfNodes = TsNodes.count();
}
else if (childNode.toElement().tagName() == "DensityScale") {
DensityScale = childNode.toElement().attribute("value").toDouble();
}
else if (childNode.toElement().tagName() == "ShadingType") {
ShadingType = childNode.toElement().attribute("value").toDouble();
}
else if (childNode.toElement().tagName() == "GradientFactor") {
GradientFactor = childNode.toElement().attribute("value").toDouble();
}
}
}
如果之前认真看我前面写的内容的话,这里一看就非常易懂:遍历节点,然后分别吧Nodes和其他数据量进行处理,用了if-else结构。
唯一的区别是for里面的三句话:
NodeTS nodets;
nodets.readNode(nodeData.at(i).childNodes());
TsNodes.append(nodets);
这三句话的目标就是为了把子节点的数据存储到Nodes的List里面。之后再通过赋值numOfNodes = TsNodes.count();得到节点数目。下一节就把整个文件都读进来然后显示一些信息。