• Qt中使用QDomDocument和QDomnode来读取xml


    Qt系列文章目录

    前言

    Qt 提供了三种读取 XML 文档的方法
    Qt中使用QDomDocument和QDomnode来读取xml
    内容简介:一.对QDomDocument和QDomnode的理解QDom前缀的都是代表节点类型。所以有,QDomElement代表一个Element节点,而QDomText代表一个Text节点。QDomNode类可以存储任意类型的节点。如果想进一步处理一个节点,首先必须把它转化为正确的数据类型。QDomNode调用toElement()以把它转化成QDomElement,然后调用tagName()来获得元素的标签名称。如果节点不是Element类型,那么toElement()函数就返回一个空QDomElement对对QDomDocument和QDomnode的理解
    QDom前缀的都是代表节点类型。所以有,QDomElement代表一个Element节点,而QDomText代表一个Text节点。QDomNode类可以存储任意类型的节点。如果想进一步处理一个节点,首先必须把它转化为正确的数据类型。QDomNode调用toElement()以把它转化成QDomElement,然后调用tagName()来获得元素的标签名称。如果节点不是Element类型,那么toElement()函数就返回一个空QDomElement对象和一个空标签

    一、DOM(Document Object Model)

    DOM(Document Object Model):将整个 XML 文档读入内存,构建成一个树结构,允许程序在树结构上向前向后移动导航,这是与另外两种方式最大的区别,也就是允许实现多次解析器(对应于前面所说的一次解析器)。DOM 方式带来的问题是需要一次性将整个 XML 文档读入内存,因此会占用很大内存;

    二、QXmlStreamReader

    QXmlStreamReader:一种快速的基于流的方式访问良格式 XML 文档,特别适合于实现一次解析器(所谓“一次解析器”,可以理解成我们只需读取文档一次,然后像一个遍历器从头到尾一次性处理 XML 文档,期间不会有反复的情况,也就是不会读完第一个标签,然后读第二个,读完第二个又返回去读第一个,这是不允许的);

    三、SAX(Simple API for XML)

    SAX(Simple API for XML):提供大量虚函数,以事件的形式处理 XML 文档。这种解析办法主要是由于历史原因提出的,为了解决 DOM 的内存占用提出的(在现代计算机上,这个一般已经不是问题了)。

    在 Qt4 中,这三种方式都位于 QtXml 模块中。Qt5 则将QXmlStreamReader/QXmlStreamWriter移动到 QtCore 中,QtXml 则标记为“不再维护”,这已经充分表明了 Qt 的官方意向。

    至于生成 XML 文档,Qt 同样提供了三种方式:

    QXmlStreamWriter,与QXmlStreamReader相对应;
    DOM 方式,首先在内存中生成 DOM 树,然后将 DOM 树写入文件。不过,除非我们程序的数据结构中本来就维护着一个 DOM 树,否则,临时生成树再写入肯定比较麻烦;
    纯手工生成 XML 文档,显然,这是最复杂的一种方式。
    使用QXmlStreamReader是 Qt 中最快最方便的读取 XML 的方法。因为QXmlStreamReader使用了递增式的解析器,适合于在整个 XML 文档中查找给定的标签、读入无法放入内存的大文件以及处理 XML 的自定义数据。

    每次QXmlStreamReader的readNext()函数调用,解析器都会读取下一个元素,按照下表中展示的类型进行处理。我们通过表中所列的有关函数即可获得相应的数据值:

    xml例子

    <?xml version="1.0" encoding="GB2312" ?>
    <Project>
      <Earth>
        <Earth dom="true" dom_brightness="1.000000" />
        <ContourMap>
          <ColorMaps currentname="" />
        </ContourMap>
      </Earth>
      <Editable>
        <Editable editcoverpath="" editimagepath="" />
      </Editable>
      <Bim />
      <Meteorology />
      <Environment>
        <DateTime day="13" dst="false" hour="15" min="17" month="5" pass="false" sec="9" sync="false" year="2022" zone="8.000000" />
        <Atmos cloud_add_density="0.500000" cloud_height="1500.000000" cloudtype="0" fog="false" fogcolor="0.670000 0.790000 0.890000" fogrange="10000.000000" weatherrate="0.000000" weathertype="0" wind="true" winddirection="0.000000" windspeed="10.000000" />
        <Light ambient="1.000000" brightness="1.000000" diffuse="1.000000" high="1.000000" high_power="10.000000" night_power="1.000000" sea_power="1.000000" shadow_power="0.000000" space_color_x="0.500000" space_color_y="0.500000" space_color_z="0.500000" />
        <Ocean chop="1.300000" choppiness="1.300000" choppy_x="0.000000" choppy_y="0.310000" choppy_z="0.400000" model_visibility="200.000000" ocean_culling="true" reflect_model="false" reflect_terrain="false" reflect_visibility="30000.000000" sea_level="0.000000" sea_mask_x="0.070000" sea_mask_y="0.190000" sea_mask_z="0.300000" sea_visibility="200.000000" sea_x="0.040000" sea_y="0.120000" sea_z="0.200000" windspeed="10.000000" />
        <Ground bumpmaprange="6000.000000" cover_visible="true" detail_alpha="0.550000" detail_attenDist="130.000000" detail_maxRange="450.000000" detailrange="6000.000000" ground_visible="false" procedural_texture="false" splat_blend_rate="0.950000" splat_brightness="1.000000" splat_contrast="1.000000" splat_fade_altitude="4000.000000" splat_range="60000.000000" />
        <Splat splataltitudefade="4500" splatambientratio="1.000000" splatblendrate="0.850000" splatbrightness="1.000000" splatcontrast="1.000000" splatdiffuseratio="1.000000" splatvisible="false" splatvisiblealtitude="4000" />
        <SplatMaterial />
      </Environment>
      <Region>
        <Data dempath="" demtype="0" dompath="荆州热电厂.tif" domtype="0" maxlevel="18" minlevel="6" mode="0" name="荆州热电厂" visible="true" />
      </Region>
      <Mask />
      <Flatten />
      <Terrain />
      <Surface />
    <Path>
        <Data followterrain="true" height="0.000000" loop="1" mode="0" name="test" offsetheight="0.000000" speed="10.000000" type="1" visible="true">
          <Points count="7">
            <P1 pos="112.230563 31.037060 79.934634" />
            <P2 pos="112.229599 31.036415 79.796287" />
            <P3 pos="112.229602 31.035366 79.271138" />
            <P4 pos="112.231061 31.035135 79.400257" />
            <P5 pos="112.231983 31.035851 79.020596" />
            <P6 pos="112.231838 31.036912 79.874460" />
            <P7 pos="112.230563 31.037065 79.008552" />
          </Points>
        </Data>
      </Path>
      <Model>
        <Data ent_anisotropy="0" ent_bindname="" ent_bindtype="11" ent_blend="false" ent_castshadow="true" ent_color="1.000000 1.000000 1.000000 -1.000000" ent_density="20.000000" ent_linethick="-1.000000" ent_material="0" ent_offset_pos="0.000000 0.000000 0.000000" ent_ori="0.000000 0.000000 0.000000" ent_ori_type="0" ent_placement="4" ent_polyoffset_factor="0.000000" ent_polyoffset_unit="0.000000" ent_pos="112.232583 31.039165 76.170211" ent_randomheading="false" ent_randomscale="false" ent_randomscalemax="1.000000" ent_randomscalemin="1.000000" ent_reflected="false" ent_renderbin="-1" ent_scale="1.000000 1.000000 1.000000" ent_shape="0" http="false" modelid="0" name="热电厂" path="建筑/redianchang2.ive" range="10000.000000" static="true" type="0" visible="true" />
    	<Data ent_anisotropy="0" ent_bindname="test" ent_bindtype="0" ent_blend="false" ent_castshadow="true" ent_color="1.000000 1.000000 1.000000 -1.000000" ent_density="20.000000" ent_linethick="-1.000000" ent_material="0" ent_offset_pos="0.000000 0.000000 0.000000" ent_ori="0.000000 0.000000 0.000000" ent_ori_type="0" ent_placement="4" ent_polyoffset_factor="0.000000" ent_polyoffset_unit="0.000000" ent_pos="112.230563 31.037060 79.934634" ent_randomheading="false" ent_randomscale="false" ent_randomscalemax="1.000000" ent_randomscalemin="1.000000" ent_reflected="false" ent_renderbin="-1" ent_scale="1.000000 1.000000 1.000000" ent_shape="0" http="false" modelid="0" name="实体模型019010" path="车辆/T90.ive" range="10000.000000" static="true" type="0" visible="true" />
      </Model>
      <Road />
      <Polygon />
      <PolygonPrefab />
      <Geometric />
      <Vectogram />
      <Symbol />
      <Image />
      <Particle />
      <Sound />
      <Screen />
      <Viewpoint>
        <Data day="1" dst="false" heading="-0.000000" height="75.139096" home="false" hour="0" lat="31.037060" lon="112.230563" min="0" month="1" name="荆州热电厂" pitch="-85.500000" range="3446.635041" save_sea_level="false" save_time="false" sea_height="-1000.000000" sea_level="0.000000" sec="0" year="1970" zone="0.000000" />
      </Viewpoint>
      <Tools />
      <Control />
      <Effect />
      <EffectWater />
      <River />
      <Simulator />
      <ShipWake />
      <RotorWash />
      <MassiveSymbol />
      <Manipulator />
      <VehiclePhysx />
      <CompositeModel />
      <ObliqueModel />
      <Aviation />
      <Volume />
      <Field />
      <Decal />
    </Project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    在这里插入图片描述

    读取节点“Path”属性值

    核心代码

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <qfile.h>
    #include <qmessagebox.h>
    #include <qdebug.h>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        setWindowTitle(tr("XML DOM Reader"));
    
        treeWidget = new QTreeWidget(this);
        QStringList headers;
        headers << "Items" << "Pages";
        treeWidget->setHeaderLabels(headers);
        setCentralWidget(treeWidget);
    }
    bool MainWindow::readFile(const QString &fileName)
    {
        QFile file(fileName);
        if (!file.open(QFile::ReadOnly | QFile::Text))
        {
            QMessageBox::critical(this, tr("Error"),
                                  tr("Cannot read file %1").arg(fileName));
            return false;
        }
    
        QString errorStr;
        int errorLine;
        int errorColumn;
    
        QDomDocument doc;
        //填充dom树
        if (!doc.setContent(&file, false, &errorStr, &errorLine,
                            &errorColumn))//形参2,是否创建命名空间
        {
            QMessageBox::critical(this, tr("Error"),
                                  tr("Parse error at line %1, column %2: %3")
                                    .arg(errorLine).arg(errorColumn).arg(errorStr));
            return false;
        }
    
        QDomElement root = doc.documentElement();//获取dom树的根标签
        if (root.tagName() != "Project")
        {
            QMessageBox::critical(this, tr("Error"),
                                  tr("Not a bookindex file"));
            return false;
        }
        parseBookindexElement(root);
          return true;
     }
    void MainWindow::parseBookindexElement(const QDomElement &element)
    {
        QDomNode child = element.firstChild();//根标签下的子标签
        while (!child.isNull())
        {
            if (child.toElement().tagName() == "Path")//qdomnode ————》qdomelement的转换基类到子类的转换
            {
                parseEntryElement(child.toElement(),
                                  treeWidget->invisibleRootItem());
            }
    
            if (child.toElement().tagName() == "P1")//qdomnode ————》qdomelement的转换基类到子类的转换
            {
                parseEntryElement(child.toElement(),
                                  treeWidget->invisibleRootItem());
            }
    
            child = child.nextSibling();
        }
     }
    
    void MainWindow::parseEntryElement(const QDomElement &element,
                                       QTreeWidgetItem *parent)
    {
        QTreeWidgetItem *item = new QTreeWidgetItem(parent);
        QString followterrain = element.attribute("followterrain");
        item->setText(0, element.attribute("followterrain"));
    
        QDomNode child = element.firstChild();
        QDomNodeList childList = element.childNodes();
        while (!child.isNull())//遍历标签的子标签
        {
            if (child.toElement().tagName() == "Data")
            {
                parseEntryElement(child.toElement(), item);//递归调用本身
            }
            else if (child.toElement().tagName() == "height")
            {
                parsePageElement(child.toElement(), item);
            }
            else if(child.toElement().tagName() == "Points")
            {
                QString count = child.toElement().attribute("count");
                QDomNodeList childList = child.toElement().childNodes();
                int childCount = childList.count();
                parsePos(childList);
    //            parseEntryElement(child.toElement(), item);
    //            parsePageElement(child.toElement(), item);
            }
            else if(child.toElement().tagName() == "P1")
            {
                QString pos = child.toElement().attribute("pos");
    //            parsePos(child.toElement(), item);
            }
            child = child.nextSibling();//指针移动一个标签
        }
    }
    
    void MainWindow::parsePos(QDomNodeList posList)
    {
        QDomNode item;
        QString pos;
        QStringList strList;
        for(int i=0; i<posList.count(); i++)
        {
            QDomNode node = posList.at(i);
            QDomElement element = node.toElement();
            QString strItem = element.tagName();
            QString strItemPos = element.attribute("pos");
            strList.append(strItemPos);
        }
    //    foreach(posList, item)
    //    {
    //        pos = item
    //    }
    }
    
    void MainWindow::parsePageElement(const QDomElement &element,
                                      QTreeWidgetItem *parent)
    {
        QString page = element.text();
        QString allPages = parent->text(1);//最开始的一次为空
        qDebug()<<"allPages "<<allPages;
        if (!allPages.isEmpty())
        {
             allPages += ", ";
        }
        allPages += page;
        parent->setText(1, allPages);
    }
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150

    源码下载

    源码下载地址

  • 相关阅读:
    为游戏开发行业释放 Git
    【vim 学习系列文章 7-- vim vnormap nnoremap nmap map inoremap 区别】
    React高级用法
    技术分享 | 接口自动化实战演练及测试考察点
    线程安全问题以及其解决方法
    数据导入与预处理——实验2
    react中点击事件带参数会立即执行
    人大金仓数据库,可以外连SQL Server 、MySql 数据库吗?
    模糊坐标00
    m短波宽带通信系统的信道建模matlab仿真
  • 原文地址:https://blog.csdn.net/aoxuestudy/article/details/125522599