• Qt之xml文件解析


    Qt之XML文件解析SAX

    XML简介

    ​ 和HTML的语法很相似,但不同之处在于: HTML 被设计用来显示数据,其关注的是数据的外观,XML 被设计用来传输和存储数据,其关注的是数据的内容,因此,XML主要用来作为数据的存储和共享。

    ​ XML文档是一种树的结构,从根部扩展到枝叶。以下是一个XML示例

    
    <root>
    	
    	<class name="Rect">
    		<object name="obj1">
    			<x1>10x1>
    			<y1>10y1>
    			<x2>50x2>
    			<y1>50y1>
    			<linewidth>2linewidth>
    			<scale>0scale>
    			<rotate>0rotate>
    		object>
    	class>
    root>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其中第一行 是XML 声明。它定义 XML 的版本和所使用的编码格式 为根节点的起始(在XML中可以自定义节点名称), 为子元素,其中name为其属性,值为Rect;每一个子元素都可以拥有子元素,故class的子元素为object,依次类推; 所有的元素都可以有文本内容和属性,如x1的文本为10,x2的文本为50。

    写XML文件

    ​ 使用QT自带的模块QXmlStreamWriter

    1. 构造函数

    ​ QXmlStreamWriter有三种构造方式,分别是

    QXmlStreamWriter::QXmlStreamWriter([QString](qstring.html) **string*);
    QXmlStreamWriter::QXmlStreamWriter([QByteArray](qbytearray.html) **array*);
    QXmlStreamWriter::QXmlStreamWriter([QIODevice](qiodevice.html) **device*)
    
    • 1
    • 2
    • 3

    第一种和第二种分别是创建一个QString和QByteArray对象,然后将xml流写入到其中,第三种则是创建一个文件设备将xml流写入其中,一般来说,第三种常用。

    2. 属性

    autoFormatting:bool量,表示是否自动格式化文档,其相关读写函数为:

    void setAutoFormatting(bool enable)
    bool autoFormatting() const
    
    • 1
    • 2

    autoFormattingIndent:int变量,当自动格式化为真时,它表示缩进的空格或者制表符的数量,相关读写函数为:

    int autoFormattingIndent() const
    void setAutoFormattingIndent(int spacesOrTabs)
    
    • 1
    • 2

    一般4个空格等于一个制表符,也就是说setAutoFormattingIndent(4)的效果与setAutoFormattingIndent(-1)的效果是一样的。

    3. 方法

    ​ 这里只介绍常用的一些方法。

    1、自动格式化代码

    void QXmlStreamWriter::setAutoFormatting(bool enable)
    
    • 1

    2、 设置文档编码

    void QXmlStreamWriter::setCodec(QTextCodec *codec);
    void QXmlStreamWriter::setCodec(const char *codecName)
    
    • 1
    • 2

    ​ 默认是utf-8,其它支持的编码格式如下:

    Big5
    Big5-HKSCS
    CP949
    EUC-JP
    EUC-KR
    GB18030
    HP-ROMAN8
    IBM 850
    IBM 866
    IBM 874
    ISO 2022-JP
    ISO 8859-1 to 10
    ISO 8859-13 to 16
    Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
    KOI8-R
    KOI8-U
    Macintosh
    Shift-JIS
    TIS-620
    TSCII
    UTF-8
    UTF-16
    UTF-16BE
    UTF-16LE
    UTF-32
    UTF-32BE
    UTF-32LE
    Windows-1250 to 1258
    
    • 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

    3、设置自动缩进值

    void setAutoFormattingIndent(int spacesOrTabs)
    
    • 1

    4、开始写xml文档时,需要先设置xml的版本和所使用的编码,一般为1.0版本,编码为utf-8,相关函数为:

    void QXmlStreamWriter::writeStartDocument();
    void QXmlStreamWriter::writeStartDocument(const QString &version);
    void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)
    
    
    • 1
    • 2
    • 3
    • 4

    与其相对应的,关闭文档写入需要调用函数

    void QXmlStreamWriter::writeEndDocument();
    
    
    • 1
    • 2

    5、xml文档为树结构,其有一个根节点,根节点下面都挂在着许多元素,节点元素设置都为以下函数

    void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name);
    void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
    
    
    • 1
    • 2
    • 3

    与其相对应的,关闭节点或元素需要调用函数

    void QXmlStreamWriter::writeEndElement()
    
    
    • 1
    • 2

    6、每一个元素都可以有若干个属性,写入带有名称和值的属性

    void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value);
    void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value);
    void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute &attribute);
    void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes &attributes);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7、写文本

    void QXmlStreamWriter::writeCharacters(const QString &text);
    
    
    • 1
    • 2

    8、写入带有名称和文本的元素

    void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text);
    void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text);
    
    
    • 1
    • 2
    • 3

    9、写注释

    void QXmlStreamWriter::writeComment(const QString &text);
    
    
    • 1
    • 2

    还有一些方法就不一一介绍了,以上已经可以写出一个完整的xml文档。

    4. 示例

    ​ 将一些图元的信息写入到xml文件中。

    void MainWindow::on_btnWrite_clicked()
    {
        QString fileName = QFileDialog::getSaveFileName(this, "Save File",
                                                        "./untitled.xml","Xml(*.xml)");
        qDebug() << fileName;
    
        QFile file(fileName);
    
        if (!file.open(QIODevice::WriteOnly))
        {
            qDebug() << "Save failed";
            return;
        }
    
        /* 打开文件成功,开始写入 */
        QXmlStreamWriter writer(&file);
    
        writer.setCodec("utf-8");
        writer.writeStartDocument("1.0");
        writer.setAutoFormatting(true);
        writer.setAutoFormattingIndent(-1);
    
        writer.writeStartElement("root");
            writer.writeComment("写入矩形图元的信息");
            writer.writeStartElement("class");
            writer.writeAttribute("name", "Rect");
                writer.writeStartElement("object");
                writer.writeAttribute("name", "obj1");
                    writer.writeTextElement("x1", QString::number(10));
                    writer.writeTextElement("y1", QString::number(10));
                    writer.writeTextElement("x2", QString::number(50));
                    writer.writeTextElement("y1", QString::number(50));
                    writer.writeTextElement("linewidth", QString::number(2));
                    writer.writeTextElement("scale", QString::number(0));
                    writer.writeTextElement("rotate", QString::number(0));
                writer.writeEndElement();
    
                writer.writeStartElement("object");
                writer.writeAttribute("name", "obj2");
                    writer.writeTextElement("x1", QString::number(20));
                    writer.writeTextElement("y1", QString::number(30));
                    writer.writeTextElement("x2", QString::number(50));
                    writer.writeTextElement("y1", QString::number(60));
                    writer.writeTextElement("linewidth", QString::number(2));
                    writer.writeTextElement("scale", QString::number(0));
                    writer.writeTextElement("rotate", QString::number(90));
    
                writer.writeEndElement();
            writer.writeEndElement();
    
            writer.writeComment("写入线图元的信息");
            writer.writeStartElement("class");
            writer.writeAttribute("name", "Line");
                writer.writeStartElement("object");
                writer.writeAttribute("name", "obj1");
                    writer.writeTextElement("x1", QString::number(10));
                    writer.writeTextElement("y1", QString::number(10));
                    writer.writeTextElement("x2", QString::number(50));
                    writer.writeTextElement("y1", QString::number(50));
                    writer.writeTextElement("linewidth", QString::number(2));
                    writer.writeTextElement("scale", QString::number(0));
                    writer.writeTextElement("rotate", QString::number(0));
                writer.writeEndElement();
    
                writer.writeStartElement("object");
                writer.writeAttribute("name", "obj2");
                    writer.writeTextElement("x1", QString::number(10));
                    writer.writeTextElement("y1", QString::number(10));
                    writer.writeTextElement("x2", QString::number(50));
                    writer.writeTextElement("y1", QString::number(50));
                    writer.writeTextElement("linewidth", QString::number(2));
                    writer.writeTextElement("scale", QString::number(0));
                    writer.writeTextElement("rotate", QString::number(0));
                writer.writeEndElement();
            writer.writeEndElement();
    
            writer.writeComment("写入椭圆图元信息");
            writer.writeStartElement("class");
            writer.writeAttribute("name", "Ellipse");
            writer.writeCharacters("无椭圆图元");
            writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndDocument();
        file.close();
    }
    
    
    • 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

    最后构成的xml文档如下:

    
    <root>
    	
    	<class name="Rect">
    		<object name="obj1">
    			<x1>10x1>
    			<y1>10y1>
    			<x2>50x2>
    			<y1>50y1>
    			<linewidth>2linewidth>
    			<scale>0scale>
    			<rotate>0rotate>
    		object>
    		<object name="obj2">
    			<x1>20x1>
    			<y1>30y1>
    			<x2>50x2>
    			<y1>60y1>
    			<linewidth>2linewidth>
    			<scale>0scale>
    			<rotate>90rotate>
    		object>
    	class>
    	
    	<class name="Line">
    		<object name="obj1">
    			<x1>10x1>
    			<y1>10y1>
    			<x2>50x2>
    			<y1>50y1>
    			<linewidth>2linewidth>
    			<scale>0scale>
    			<rotate>0rotate>
    		object>
    		<object name="obj2">
    			<x1>10x1>
    			<y1>10y1>
    			<x2>50x2>
    			<y1>50y1>
    			<linewidth>2linewidth>
    			<scale>0scale>
    			<rotate>0rotate>
    		object>
    	class>
    	
    	<class name="Ellipse">无椭圆图元class>
    root>
    
    
    • 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

    读XML文件

    ​ 使用QT自带的模块QXmlStreamReader

    1. 构造函数

    可以通过

    QXmlStreamReader(const char *data)
    QXmlStreamReader(const QString &data)
    QXmlStreamReader(const QByteArray &data)
    QXmlStreamReader(QIODevice *device)
    QXmlStreamReader()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. 属性

    namespaceProcessing:bool变量,指是否处理命名空间,相关读写函数为

    bool namespaceProcessing() const
    void setNamespaceProcessing(bool)
    
    
    • 1
    • 2
    • 3

    3. 方法

    1、设置文件设备,如果你使用了无参的构造,则可以通过下面这个函数来设置要读取的文件

    void setDevice(QIODevice *device)
    
    
    • 1
    • 2

    2、读取下一个下一个标记

    QXmlStreamReader::TokenType QXmlStreamReader::readNext();
    
    
    • 1
    • 2

    读取xml文档主要就用这一个函数,通过其返回值 QXmlStreamReader::TokenType来判断读取的是什么元素,枚举TokenType如下

        enum TokenType {
            NoToken = 0,
            Invalid,
            StartDocument,
            EndDocument,
            StartElement,
            EndElement,
            Characters,
            Comment,
            DTD,
            EntityReference,
            ProcessingInstruction
        };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • NoToken:没有读取到任何信息
    • Invalid:读取失败,错误信息保存在error()errorString()
    • StartDocument:读取到的为xml文档版本号documentVersion()和编码格式documentEncoding()
    • EndDocument:读取到文档结束的位置
    • StartElement:读取到的为一个节点,节点命名空间和名字分别保存在namespaceUri()name()中,其属性值保存在attribute()中。
    • EndElement:读取到该节点的结束位置
    • Characters:读取的内容为字符,保存在text()
    • Comment:读取的内容为注释,保存在text()
    • DTD:读取的内容为DTD,保存在text()
    • EntityReference:无法解析的实体引用
    • ProcessingInstruction

    3、读取开始节点中的文本

    QString QXmlStreamReader::readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour = ErrorOnUnexpectedElement)
    
    
    • 1
    • 2

    这个函数用在当读取的标记为StartElement之后,直接调用这个函数可以更方便的获取其内容

    示例

    ​ 读取上面写入的文档,示例代码为:

    void MainWindow::on_btnRead_clicked()
    {
        QString fileName = QFileDialog::getOpenFileName(this, "Save this file As"
                                                        , "./", "Xml(*.xml)");
        qDebug() << fileName;
    
        QFile file(fileName);
    
        if (!file.open(QIODevice::ReadOnly))
        {
            qDebug() << "Save failed";
            return;
        }
    
        QXmlStreamReader reader(&file);
        QXmlStreamReader::TokenType token;
        QXmlStreamAttributes attribute;
        QString str, attrStr;
        while (!reader.atEnd()) {
              token = reader.readNext();
              if(token == QXmlStreamReader::StartElement)
              {
                  str =  reader.name().toString();
                  if(QString::compare(str, "root") == 0)
                  {
                      qDebug() << "这是根节点:"<< str;
                      qDebug() << "----------------";
                  }
                  else if(QString::compare(str, "class") == 0)
                  {
    
                      attribute = reader.attributes();
                      if(attribute.hasAttribute("name"))
                      {
                          attrStr.clear();
                          attrStr = attribute.value("name").toString();
                      }
                      qDebug() << "************************************************";
                      qDebug() << "这是元素:"<< str << ", 属性为" << attrStr;
                  }
                  else if(!QString::compare(str, "object"))
                  {
                      attribute = reader.attributes();
                      if(attribute.hasAttribute("name"))
                      {
                          attrStr.clear();
                          attrStr = attribute.value("name").toString();
                      }
                      qDebug() << "这是元素:" << str << ", 属性为" << attrStr;
    
                  }
                  else if(QString::compare(str, "x1") == 0)
                  {
    
                      qDebug() << attrStr << "对象的x1值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "x2") == 0)
                  {
                      qDebug() << attrStr << "对象的x2值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "y1") == 0)
                  {
                      qDebug() << attrStr << "对象的y1值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "y2") == 0)
                  {
                      qDebug() << attrStr << "对象的y2值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "linewidth") == 0)
                  {
                      qDebug() << attrStr << "对象的linewidth值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "scale") == 0)
                  {
                      qDebug() << attrStr << "对象的scale值为:" << reader.readElementText();
                  }
                  else if(QString::compare(str, "rotate") == 0)
                  {
                      qDebug() << attrStr << "对象的rotate值为:" << reader.readElementText();
                      qDebug() << "----------------";
                  }
              }
              else if(token == QXmlStreamReader::Characters)
              {
    //              qDebug() << reader.text().toString(); /* 会把换行符和制表符也给读出来 */
              }
              else if(token == QXmlStreamReader::Comment)
              {
                  qDebug() << reader.text().toString(); /* xml注释 */
              }
              else if(token == QXmlStreamReader::Invalid)
              {
                  qDebug() << "读取失败:" << reader.errorString();
              }
        }
    }
    
    
    • 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

    打印输出结果如下:

    "H:/robot_plus/tests/Xml/XML/bin/untitled1.xml"
    这是根节点: "root"
    ----------------
    "写入矩形图元的信息"
    ************************************************
    这是元素: "class" , 属性为 "Rect"
    这是元素: "object" , 属性为 "obj1"
    "obj1" 对象的x1值为: "10"
    "obj1" 对象的y1值为: "10"
    "obj1" 对象的x2值为: "50"
    "obj1" 对象的y1值为: "50"
    "obj1" 对象的linewidth值为: "2"
    "obj1" 对象的scale值为: "0"
    "obj1" 对象的rotate值为: "0"
    ----------------
    这是元素: "object" , 属性为 "obj2"
    "obj2" 对象的x1值为: "20"
    "obj2" 对象的y1值为: "30"
    "obj2" 对象的x2值为: "50"
    "obj2" 对象的y1值为: "60"
    "obj2" 对象的linewidth值为: "2"
    "obj2" 对象的scale值为: "0"
    "obj2" 对象的rotate值为: "90"
    ----------------
    "写入线图元的信息"
    ************************************************
    这是元素: "class" , 属性为 "Line"
    这是元素: "object" , 属性为 "obj1"
    "obj1" 对象的x1值为: "10"
    "obj1" 对象的y1值为: "10"
    "obj1" 对象的x2值为: "50"
    "obj1" 对象的y1值为: "50"
    "obj1" 对象的linewidth值为: "2"
    "obj1" 对象的scale值为: "0"
    "obj1" 对象的rotate值为: "0"
    ----------------
    这是元素: "object" , 属性为 "obj2"
    "obj2" 对象的x1值为: "10"
    "obj2" 对象的y1值为: "10"
    "obj2" 对象的x2值为: "50"
    "obj2" 对象的y1值为: "50"
    "obj2" 对象的linewidth值为: "2"
    "obj2" 对象的scale值为: "0"
    "obj2" 对象的rotate值为: "0"
    ----------------
    "写入椭圆图元信息"
    ************************************************
    这是元素: "class" , 属性为 "Ellipse"
    
    
    • 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

    总结

    ​ 使用SAX方式进行读写XML文档更易上手,也更符合XML标准,不足之处在于仅支持迭代读写,如果你想要更改某个属性,只能重新开始写入。使用DOM方式进行解析则可以达到增删改查的操作。但是两者各有利弊。

  • 相关阅读:
    Nacos技术学习与总结待续
    NOA市占率超50%+影子模式,这家中国车企走出一条不寻常道路
    如何为开源项目和社区做贡献 -- 你应该知道的十件事
    通过IDEA解决spring配置文件
    【秋招面经】之神策数据
    计算机组成原理(2)--进位计数制、BCD码,有符号数和无符号数、浮点数
    重装win11,个人记录详细步骤-干货
    L2研发工程师—牛客网
    Linux常⽤服务器构建-ssh和scp
    Chapter11 : Deep Learning in Structure-Based Drug Design
  • 原文地址:https://blog.csdn.net/qq_39295354/article/details/126513467