QT QXmlStreamReader流处理解析XML

本文介绍了一种利用Qt框架中的XML模块解析XML文件的方法。通过具体的代码示例,展示了如何逐层读取XML文档中的各个节点,并将其展示在一个树形控件中。此过程涉及读取文件、解析节点及跳过未知元素等步骤。

来源https://www.devbean.net/2013/07/qt-study-road-2-read-xml-with-stream/
建立XML文档

<bookindex>
    <entry term="sidebearings">
        <page>10</page>
        <page>34-35</page>
        <page>307-308</page>
    </entry>
    <entry term="subtraction">
        <entry term="of pictures">
            <page>115</page>
            <page>244</page>
        </entry>
        <entry term="of vectors">
            <page>9</page>
        </entry>
    </entry>
</bookindex>

在Pro文件中声明XML

QT       += core gui xml

头文件

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    //读取file
    bool readFile(const QString &fileName);

private:
    //读取截点
    //父节点
    //子节点(QTreeWidgetItem *parent)
    //读取bookindex节点
    void readBookindexElement();
    //读取entry节点
    void readEntryElement(QTreeWidgetItem *parent);
    //读取page节点
    void readPageElement(QTreeWidgetItem *parent);
    //无关节点跳过
    void skipUnknownElement();

    QTreeWidget *treeWidget;
    QXmlStreamReader reader;

方法依次为:
1.读取文件
2.读取父节点bookindex
3.读取子节点entry(接受传过来的父节点 bookindex)
4.读取子节点page(接受传过来的父节点 entry)
5.跳过无关节点
读取文件:

bool MainWindow::readFile(const QString &fileName)
{
    QFile file(fileName);

    if(!file.open(QFile::ReadOnly | QFile::Text)){
        QMessageBox::information(this,tr("open error"),tr("connot read file %1").arg(fileName));
        qDebug()<<"error";
        return false;
    }
    qDebug()<<QDir::currentPath();
    //将file设置为QXmlStreamReader的设备(Stream从file中读取内容)
    //Sets the current device to device.
    //Setting the device resets the stream to its initial state.
    reader.setDevice(&file);
    //判断文件是否读到末尾
    while(!reader.atEnd()){
        //判断是否是开始元素
        if(reader.isStartElement()){
            //判断读取的根标签是否是bookindex
            if(reader.name() == "bookindex"){
                //是bookindex 往下读取
                readBookindexElement();
            }else {
                reader.raiseError(tr("Not a valid book file"));
            }
        }else {
            reader.readNext();
        }
    }
    //文件记得关闭
    file.close();
    if(reader.hasError()){
        QMessageBox::information(this,tr("Error"),tr("Filed to parse file %1").arg(fileName));
        return false;
    }else if(file.error() != QFile::NoError){
        QMessageBox::information(this,tr("Error"),tr("Cannot read file %1").arg(fileName));
        return false;
    }
    return true;
}

读取bookindex节点:

void MainWindow::readBookindexElement()
{
    //Q_ASSERT()加断言  若进函数的时候 StartElement状态,或者说标签不是 bookindex,就认为出错
    Q_ASSERT(reader.isStartElement() && reader.name()=="bookindex");
    //往下读取
    reader.readNext();
    while (!reader.atEnd()) {
        //判断是结束节点,跳出
        if(reader.isEndElement()){
            reader.readNext();
            break;
        }

        if(reader.isStartElement()){
            //(bookindex的子元素为entry)开始处理entry
            if(reader.name() == "entry"){
                //读取entry节点,(隐藏根节点)
                readEntryElement(treeWidget->invisibleRootItem());
            }else {
                //没读到entry节点 跳过
                skipUnknownElement();
            }
        }else {
            reader.readNext();
        }
    }
}

读取entry节点

//接受一个QTreeWidgetItem指针作为根节点.这个节点被当做这个 entry 标签在QTreeWidget中的根节点。
void MainWindow::readEntryElement(QTreeWidgetItem *parent)
{
    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
    //item index=0 属性为"term"的值
    //QXmlStreamReader::attributes() Returns the attributes of a StartElement.
    item->setText(0,reader.attributes().value("term").toString());

    reader.readNext();

    while (!reader.atEnd()) {
        if(reader.isEndElement()){
            reader.readNext();
            break;
        }
        if(reader.isStartElement()){
            //读到entry节点
            if(reader.name() == "entry"){
                readEntryElement(item);
                //page节点
            }else if(reader.name() == "page"){
                readPageElement(item);
            }else{
                //无节点  跳过
                skipUnknownElement();
            }
        }else {
            reader.readNext();
        }
    }
}

读取page

void MainWindow::readPageElement(QTreeWidgetItem *parent)
{
    //获取文本
    QString page = reader.readElementText();
    if(reader.isEndElement()){
        reader.readNext();
    }

    //QTreeWidgetItem::text(int column)返回指定列的text
    QString allPages = parent->text(1);
    if(!allPages.isEmpty()){
        //用","分割
        allPages += ",";
    }
    allPages += page;
    parent->setText(1,allPages);
}

无关节点跳过

void MainWindow::skipUnknownElement()
{
    reader.readNext();
    //没有结束
    while (!reader.atEnd()) {
        //结束
        if(reader.isEndElement()){
            reader.readNext();
            break;
        }
        //继续跳过读取。
        if(reader.isStartElement()){
            skipUnknownElement();
        }else {
            reader.readNext();
        }
    }
}

在MainWindow函数中 声明

setWindowTitle(tr("xml reader"));
    treeWidget = new QTreeWidget(this);
    QStringList headers;
    //设置头 Items Pages
    headers<<"Items"<<"Pages";
    treeWidget->setHeaderLabels(headers);
    setCentralWidget(treeWidget);
    //读取不到  用绝对路径读取成功  添加到资源路径读取成功
    //readFile("D:/lei_project/qtproject/XMLdemo/books.xml");
    readFile(":/xml/books.xml");
    //readFile("books.xml")
### 三级标题:解析嵌套 XML 结构的方法 在 Qt解析嵌套的 XML 结构时,`QXmlStreamReader` 提供了灵活且高效的机制来处理复杂的 XML 层级结构。通过逐层读取 XML 元素,开发者可以利用 `QXmlStreamReader::StartElement` 和 `QXmlStreamReader::EndElement` 事件来识别嵌套层级,并在进入和退出嵌套结构时进行相应的处理。 解析嵌套 XML 的关键在于维护一个栈结构,用于记录当前所处的元素层级。每当遇到 `StartElement` 时,将该元素名称压入栈中;当遇到 `EndElement` 时,从栈中弹出该元素。通过栈的深度变化,可以判断当前是否处于嵌套结构中,从而实现对不同层级元素的区分处理。 以下是一个示例代码,展示了如何使用 `QXmlStreamReader` 解析嵌套结构的 XML 文件: ```cpp #include <QFile> #include <QXmlStreamReader> #include <QDebug> #include <stack> void parseNestedXML(const QString &filePath) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Failed to open file"; return; } QXmlStreamReader xml(&file); std::stack<QString> elementStack; while (!xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { QString elementName = xml.name().toString(); elementStack.push(elementName); qDebug() << "Start Element:" << elementName << "Depth:" << elementStack.size(); } else if (xml.isEndElement()) { QString elementName = xml.name().toString(); if (!elementStack.empty() && elementStack.top() == elementName) { elementStack.pop(); } else { qDebug() << "Mismatched End Element:" << elementName; } qDebug() << "End Element:" << elementName << "Depth:" << elementStack.size(); } if (xml.hasError()) { qDebug() << "XML Error:" << xml.errorString(); break; } } file.close(); } ``` 上述代码中,每当遇到一个开始标签时,将其名称压入栈中,并输出当前栈的深度以表示嵌套层级。当遇到结束标签时,检查栈顶元素是否匹配,并弹出栈顶元素以表示退出当前层级。这种方式可以有效跟踪嵌套结构的变化,并在出现标签不匹配时进行错误提示[^3]。 此外,`QXmlStreamReader` 还支持获取当前元素的属性、文本内容以及命名空间信息,开发者可以根据需要在不同层级中提取特定数据[^4]。例如,在遇到 `StartElement` 时,可以使用 `attributes()` 方法获取当前元素的属性列表,或者在 `Characters` 事件中提取文本内容。 通过这种方式,可以实现对复杂嵌套结构的 XML 文档进行高效、精确的解析,并在解析过程中保持良好的可读性和可维护性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值