XML语言数据读写理解9

236 阅读2分钟

因为篇幅原因就不把上一节的XML文件粘贴上来了,大家可以返回去看。

现在,我们需要把所有的node都读出来,然后保存到一个容器里。要注意的一点是所有的数值都是根据NormalizedIntensity的大小进行排序的,我们存储也要按照顺序来存储,这样以后应用的时候也更方便一些。

我们使用QList来存储,首先再Node节点底下设置一个别名:typedef QList 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();得到节点数目。下一节就把整个文件都读进来然后显示一些信息。