zoukankan      html  css  js  c++  java
  • Qt---Xml文件解析

    本文我们通过一个读取Xml文件的小例子来学习QXmlStreamReader。

    Xml 简介

    Xml的全称是可扩展标记语言(EXtensible Markup Language),同HTML一样是一种标记语言。但是与HTML不同,XML:

    • 被设计为具有自我描述性
    • 没有预定义标签,需要使用者自行定义。
    • 设计宗旨是传输数据,而非显示数据(HTML)。大多数Android App开发都用Xml文件作为界面开发的数据载体。

    QXmlStreamReader 简介

    QXmlStreamReader is a faster and more convenient replacement for Qt's own SAX parser (see QXmlSimpleReader).

    官方宣称这是一个比Qt的SAX(Simple API for XML)解析器更快、更方便的替代,也就是说建议你优先使用它来解析Xml文件。

    QXmlStreamReader和SAX的工作原理类似,都是以Token为单位对Xml文件进行读取解析。使用QXmlStreamReader基本上有两种模式:

    mode-pic

    这两种方法的区别就是处理单位的不同,分别以Token、Element为单位:前者粒度更细,把控可以更精准,但相对的需要花更多的功夫在细节处理上;后者只关注元素,对于简单的处理使用起来很方便。在QXmlStreamReader中,读取Token需要调用QXmlStreamReader::readNext()函数,该函数返回读取到的Token,不同的Token类型需要调用不同的函数来获取相关的内容,详细内容参见Qt官方链接;而读取元素则是调用QXmlStreamReader::readNextStartElement()函数,注意此函数简单地区别头元素和尾元素,如果是头元素则返回true,否则(尾元素或出错)返回false。

    解析Xml 元素

    Xml中的元素与HTML一样:

    <title>Colombia Earthquake</title>
    

    这就是一个title元素,包含一些文本内容。我们通过调用QXmlStreamReader::readNextStartElement()来读取它,当读取的是一个元素的时候,QXmlStreamReader::name()函数返回元素的名字,QXmlStreamReader::readElementText()返回元素内的文本。

    解析Xml 文档元素

    <?xml version="1.0" encoding="ISO-8859-1"?>
    

    Xml文档元素包含常见的xml版本、编码、独立文档(standalone)等元数据,这些属性分别对应QXmlStreamReader的documentVersion()documentEncoding()isStandaloneDocument()等函数,但是在调用这些函数前我们需要先调用readNext()函数让解析器先去读取这个特殊元素。

    void MainWindow::readDocumentElement()
    {
        m_xmlReader.readNext();
        if (m_xmlReader.isStartDocument()) {
            auto item = new QTreeWidgetItem(
                        QStringList("Document Element"));
            item->setText(1, "xml version:" + m_xmlReader.documentVersion().toString() +
                        "    encoding:" + m_xmlReader.documentEncoding().toString() +
                        "    is standalone:" + (m_xmlReader.isStandaloneDocument() ? QString("true") : QString("false")));
            item->setBackgroundColor(1, QColor(Qt::green));
            m_treeWidget.addTopLevelItem(item);
        }
    }
    

    解析Xml CDATA

    CDATA(Character Data) 代表字符数据,这个区段中的文本不会被Xml 解析器解析,而是原样保留输出。CDATA区段以<![CDATA[开始,以]]>结束,这两个标记符号中间的文本可以是]]>以外的任何字符。CDATA经常被用来存储那些包含特殊字符(Xml关键字或者保留字符)的文本,如下:

    <![CDATA[ This is a <CDATA> section text! ]]>
    

    <在Xml是特殊字符,用来标识元素的开始,如果上面这段文字不写在CDATA区段中,这块内容就会被解析为头元素;通过CDATA区段,Xml 解析器会把这块内容原样输出。使用QXmlStreamReader,我们的代码类似如下:

    void MainWindow::readCDATA()
    {
        while (!m_xmlReader.isCDATA()) {
            m_xmlReader.readNext();
        }
        auto item = new QTreeWidgetItem(QStringList("[CDATA]"));
        item->setText(1, m_xmlReader.text().toString());
        item->setBackgroundColor(1, QColor(Qt::cyan));
        m_treeWidget.addTopLevelItem(item);
    }
    

    因为CDATA区段不是元素,因此我们需要调用QXmlStreamReader::readNext()函数。

    解析Xml DTD

    文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。

    简而言之,DTD是用来描述Xml文档的结构的,语法如下:

    <!DOCTYPE 根元素 [元素声明]>
    

    例如下面这个DTD:

    <!DOCTYPE note [
        <!ELEMENT note (to,from,heading,body)>
        <!ELEMENT to      (#PCDATA)>
        <!ELEMENT from    (#PCDATA)>
        <!ELEMENT heading (#PCDATA)>
        <!ELEMENT body    (#PCDATA)>
    ]>
    <note>
    <to>George</to>
    <from>John</from>
    <heading>Reminder</heading>
    <body>Don't forget the meeting!</body>
    </note>
    

    该DTD 解释如下:

    !DOCTYPE note (第1行)定义此文档是 note 类型的文档。
    !ELEMENT note (第2行)定义 note 元素有四个元素:"to、from、heading,、body"
    !ELEMENT to (第3行)定义 to 元素为 "#PCDATA" 类型
    !ELEMENT from (第4行)定义 from 元素为 "#PCDATA" 类型
    !ELEMENT heading (第5行)定义 heading 元素为 "#PCDATA" 类型
    !ELEMENT body (第6行)定义 body 元素为 "#PCDATA" 类型

    用QXmlStreamReader解析DTD也非常方便,方法与解析CDATA一样,只是换了个判断函数:

    while (!m_xmlReader.isDTD()) {
        m_xmlReader.readNext();
    }
    auto item = new QTreeWidgetItem(QStringList("[DTD]"));
    item->setText(1, m_xmlReader.text().toString());
    item->setBackgroundColor(1, QColor(Qt::darkMagenta));
    m_treeWidget.addTopLevelItem(item);
    

    解析Xml 注释

    Xml 的注释也与HTML相同,<!-- XXXXXXXXXXXXXXXXXXX -->,代码与上一小节基本一样,只是判断处改用了QXmlStreamReader::isComment()

    while (!m_xmlReader.isComment()) {
        m_xmlReader.readNext();
    }
    ...
    

    解析Xml Processing Instruction

    XMl PI(Processing Instruction) 处理指令使用这种格式<?PITarget PIContent?>,前一部分是Target,后一部分是Content。Processing Instruction用来告诉Xml应用程序进行一些Xml以外的操作,例如在有一些应用中,Xml文件需要包含一些CSS文件用以应用样式来渲染自身:

    <?xml-stylesheet type="text/css" href="tutorials.css"?>
    

    在QXmlStreamReader中,好像紧贴<?的被识别位Target,后面的内容都被认为是Content:

    while (!m_xmlReader.isProcessingInstruction()) {
        m_xmlReader.readNext();
    }
    auto item = new QTreeWidgetItem(QStringList("[ProcessingInstruction]"));
    item->setText(1, "target: " + m_xmlReader.processingInstructionTarget().toString() +
                     "    content: " + m_xmlReader.processingInstructionData().toString());
    item->setBackgroundColor(1, QColor(Qt::yellow));
    m_treeWidget.addTopLevelItem(item);
    

    获取PI相关内容需要分别调用QXmlStreamReader::processingInstructionTarget()QXmlStreamReader::processingInstructionData()

    示例运行结果

    因为Xml的元素是自定义的,这就意味着往往不同的Xml内部的元素结构都不一样,不同的约定格式需要编写不同的逻辑代码处理。这个示例我们用QTreeWidget来展示解析出来的结构和内容:

    result-link

    完整代码见链接

  • 相关阅读:
    为什么MySQL数据库索引选择使用B+树?
    nginx负载均衡策略
    视频笔记
    mysql show full processlist 分析问题
    Git利用命令行提交代码步骤
    zend studio远程自动上传代码并执行
    CentOS7 通过YUM安装MySQL5.7 linux
    PHP的按位运算符是什么意思
    git 分支操作
    php 技术知识点汇总
  • 原文地址:https://www.cnblogs.com/lgxZJ/p/7966091.html
Copyright © 2011-2022 走看看