Qt XML

我们知道对XML的操作有两种方法,即DOM方式和SAX方式。二者主要区别是:DOM实现方式操作非常简单,但不适合处理过大文件;而SAX实现方式是能处理很大的XML文件,但是需要开发者写一些复杂的代码。Qt提供了对应于这两种用于读取、操作和编写XML的实现类,分别是QDomDocument类和QXmlStreamReader类,由于在项目中涉及的文件不大,因此我们选用QDomDocument类来处理。

项目中涉及便签的增删改查,对应于XML文件中相应标记的读、写和修改,下面分别介绍:

1. 创建节点,将其写入XML文件,主要操作包括:

1).创建根节点:QDomElement root = doc.documentElement("rootName " );

2).创建元素节点:QDomElement element = doc.createElement("nodeName");

3).添加元素节点到根节点:root. appendChild(element);

4).创建元素文本:QDomText nodeText=doc.createTextNode("text");

5).添加元素文本到元素节点:element. appendChild(nodeText);

在本项目中,假设便签的属性有序号、名字、内容、字体、字号、颜色、粗细、斜体、下划线这几项,则在文件中添加一个便签节点的操作如下:

QDomDocument doc;

instruction = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");

doc.appendChild(instruction);

QDomElement root = doc.createElement("Notes");

doc.appendChild(root);

QDomElement note = doc.createElement("note");

root.appendChild(note);

QDomElement no = doc.createElement("no");

note.appendChild(no);

...

...

QDomText no_text = doc.createTextNode("001");

...

...

则得到一个便签节点,将其保存到test.xml文件中,代码如下:

QFile file("test.xml");

if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text))

     return ;

QTextStream out(&file);

out.setCodec("UTF-8");

doc.save(out,4,QDomNode::EncodingFromTextStream);

file.close();

则test.xml文件:

<?xml version="1.0" encoding="UTF-8"?>

<Notes>

    <note>

        <no>001</no>

        <name>2010-05-10(13:53:24)</name>

        <content>A meeting!</content>

        <font>Script MT Bold</font>

        <fontSize>16</fontSize>

        <color> #00ffff</color>

        <weight>0</weight>

        <fontItalic>true</fontItalic>

        <fontUnderline>true</fontUnderline>

    </note>

</Notes>

上面是创建一个便签节点,若要继续添加便签节点,则需要在已有节点后增加一个新节点,并重写入XML文件。

2. 加载、查找便签时要读取XML文档中的节点信息,DOM实现方式是将整个文档当作一个对象来装入内存进行处理,然后开发者可以访问这个对象中的每一个节点,每一个节点对应XML文件里的一个标记。

       主要操作包括:

       1).读取根节点:QDomElement root = doc.documentElement();

2).读取第一个子节点:QDomNode node = root.firstChild();

3).读取下一个子节点:node = node.nextSibling();

4).匹配结点标记:node.toElement().tagName() == "note"

5).读取节点文本:no = childNode.toText().data();

以下是项目中读取便签属性的函数实现代码:

void MainWindow::parseAttr(const QDomElement &element)

{

    QString no,name,content,font,fontSize,color;

    QDomNode node = element.firstChild();

    while (!node.isNull()) {

        if (node.toElement().tagName() == "note") {//匹配note节点

            parseAttr(node.toElement());

        } else if (node.toElement().tagName() == "no") {//匹配属性no

            QDomNode childNode = node.firstChild();

                if (childNode.nodeType() == QDomNode::TextNode) {

                     no = childNode.toText().data();

                }

        }

        else if (node.toElement().tagName() == "name") //匹配属性name

                  ...

                  ...

        node = node.nextSibling();//读取兄弟节点

    }

}

3. 删除便签时,要删除相应的XML节点,用到的主要函数为:root.removeChild(node); 但在删除某个节点后要重写整个文件。

以上对XML文件的重写操作是必须的,因此在文件的打开方式中要加上QIODevice::Truncate,表示覆盖重写。目前还没有找到可以直接修改文件的方法,但若文件很大的情况下,必须考虑相应的效率问题。

由于本项目在启动时需要将所有便签加载到内存,因此选用DOM方式比较合适,但如果处理的XML文件很大,而且不需要全部读到内存时,可以用SAX实现方式,它按阶段将文档读取到内存中,在碰到标签或者其它阶段的时候,可以调用开发者预先设计好的回调函数去处理,这样效率比DOM方式更高。

### QT框架中的XML处理 QT 提供了一组强大的工具来解析和操作 XML 数据。这些工具主要分为两类:基于 DOM 的 API 和 基于 SAX 的 API。 #### 使用 QXmlStreamReader 进行流式读取 `QXmlStreamReader` 是一个高效的类,用于逐节点解析大型 XML 文件而不占用过多内存资源[^1]。它通过事件驱动的方式工作,在每次遇到新的标签、属性或其他结构时触发相应的信号。下面是一个简单的例子展示如何利用 `QXmlStreamReader` 来遍历并打印出所有的元素名称: ```cpp #include <QFile> #include <QXmlStreamReader> void readXml(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QXmlStreamReader xml(&file); while(!xml.atEnd()) { xml.readNext(); if(xml.isStartElement()) qDebug() << "Start Element:" << xml.name(); } if (xml.hasError()) qDebug() << "Error:" << xml.errorString(); } ``` #### 利用 QDomDocument 构建整个文档树模型 对于较小规模或者需要频繁随机访问的情况,则可以考虑采用 `QDomDocument` 类构建完整的文档对象模型(DOM)。这种方式允许开发者像操纵一棵树一样轻松定位任意位置的数据项[^1]。这里给出一段创建新 XML 文档并将数据写入文件的例子: ```cpp #include <QDomDocument> #include <QFile> bool writeXml(const QString &fileName, const QString &rootName, const QStringList &elements) { QDomDocument doc; QDomElement root = doc.createElement(rootName); doc.appendChild(root); foreach(QString element, elements){ QDomElement el = doc.createElement(element); root.appendChild(el); } QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return false; QTextStream out(&file); doc.save(out, 4); // Indentation level is set to '4' return true; } ``` 上述两部分分别介绍了两种不同的 XML 解析方式及其应用场景下的实现细节。无论是针对大数据量还是复杂查询需求,Qt 都提供了灵活且易用的支持方案。 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值