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>

在这里插入图片描述

读取节点“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;
}

源码下载

源码下载地址

猜你喜欢

转载自blog.csdn.net/aoxuestudy/article/details/125522599