Qt4_写入XML

写入XML

能读取XML文件的大多数应用程序也需要写人XML文件。一般来说,主要有三种由Qt应用程序生成XML文件的方法:
● 使用QXmIStreamWriter
● 构建DOM树并对它调用save()
● 手动生成XML
实际上,这三种方法的选取通常与是否使用QXmlStreamWriter、DOM或SAX来读取XML文档并无关系,尽管数据保留在DOM树中时直接保存这个DOM树是完全说得通的。

利用QXmlStreamWrite类来写入XML文件非常容易,因为它将时刻为我们关注那些特殊的转义字符。如果想利用QXmlStreamWrite从QTreeWidget中输出书刊索引数据,只需要使用两个函数。第一个函数获得文件名和一个QTreeWidget*,并且将遍历树中所有的顶级项:

bool writeXml(const QString &fileName, QTreeWidget *treeWidget)
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(fileName) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    QXmlStreamWriter xmlWriter(&file);
    xmlWriter.setAutoFormatting(true);
    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("bookindex");
    for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
        writeIndexEntry(&xmlWriter, treeWidget->topLevelItem(i));
    xmlWriter.writeEndDocument();

    file.close();
    if (file.error()) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(fileName) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }
    return true;
}

如果开启了自动格式编辑功能,XML文档将以更友好易读的格式输出,在每一行都有明确显示数据递归结构的缩进。writeStartDocument()函数则写下XML文档首行:

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

writeStartElement()函数随给定的标签文本生成一个新的开始标签。writeStartDocument()函数则关闭任何打开的开始标签。对于每一个顶级项,我们调用writeIndexEntry()函数,并将QXmlStreamWriter和要输出的项传递给writeIndexEntry()函数。下面是writeIndexEntry()的代码:

void writeIndexEntry(QXmlStreamWriter *xmlWriter, QTreeWidgetItem *item)
{
    xmlWriter->writeStartElement("entry");
    xmlWriter->writeAttribute("term", item->text(0));
    QString pageString = item->text(1);
    if (!pageString.isEmpty()) {
        QStringList pages = pageString.split(", ");
        foreach (QString page, pages)
            xmlWriter->writeTextElement("page", page);
    }
    for (int i = 0; i < item->childCount(); ++i)
        writeIndexEntry(xmlWriter, item->child(i));
    xmlWriter->writeEndElement();
}

writeIndexEntry()函数创建一个对应于QTreeWidgetltem的<entry>元素并将其作为参数接收。 writeAttribute()函数则为刚刚写入的标签添加一个属性。例如,它可以将<entry>转变为<entry tenr="sidebearings">。如果其中有页码,那么页码将以逗号-空格分隔,并且对于每一个页码数,会有一个单独的<page>...</page>标签对与其间的页码文本一起被写入。这些都可以通过调用writeTextElement()以及将标签名以及开始和结束标签之间的文本传递给writeTextElement()来实现。在所有的情况中XmlStreamWriter都考虑了特殊的XML转义字符的处理,我们不必为此担心。

如果项中有子项就对每一个子项递归调用writelndexEntry()。最后我们调用writeEndElement()来输出</entry>

使用QXmlStreamWirter是写入XML文档最容易最安全的方式但如果已经在一个DOM树中有XML文档的话,则只需要在QDomDocument对象上调用save()函数并要求这个DOM树输出相关的XML即可。默认情况下save()使用UTF8作为所生成文件的编码方式。我们可以通过为DOM树预先进行<?xml?>声明,而使用其他种类的编码方式,例如:

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

下面的代码段给出了其完成过程:

const int Indent = 4;
QDomDocument doc;
...
QTextStream out(&file);
QDomNode xmlNode = doc.createProcessingInstruction("xml", "version=\"1.0\" enconding=\"ISO-8895-1\"");
doc.insertBefore(xmlNode, doc.firstChild());
doc.save(out, Indent);

从Qt4.3开始一个替代的方式就是利用setCodec()对 QTextStream设置编码,并将 QDomNode::EncodingFromTextStream作为第三个参数传递给save()。

手动生成XML文件并不比利用DOM生成XML文件更加困难。我们可以使用QTextStream并且写入字符串就像写入其他任何文本文件一样。最需要慎重对待的部分就是转义在文本和属性值中的特殊字符。Qt::escape()函数可以转义“<”“>”和“&"等特殊字符。以下是一个使用它的代码:

QTextStream out(&file);
out.setCodec("UTF-8");
out << "<doc>\n"
    << "    <quote>" << Qt::escape(quoteText) << "</quote>\n"
    <<"     <translation>" << Qt::escape(translationText)
    << "</translation>\n"
    << "</doc>\n";

当采用这样的方式生成 XML 文件时,除了必须写入正确的 <?xml?> 声明并设置正确的编码外,还必须记得对写入的文本进行转义。如果使用了属性值,还必须转义其中的单引号或双引号。不过,使用 XmlStreamWriter 就会简单得多了,因为它将为我们处理上述所需注意的一切。

xmlstremwriter.cpp

#include <QtGui>
#include <QtXml>
#include <iostream>

void populateTree(QTreeWidget *treeWidget)
{
    QStringList labels;
    labels << QObject::tr("Terms") << QObject::tr("Pages");

    treeWidget->setHeaderLabels(labels);
    treeWidget->header()->setResizeMode(QHeaderView::Stretch);
    treeWidget->setWindowTitle(QObject::tr("XML Stream Writer"));
    treeWidget->show();

    (void) new QTreeWidgetItem(treeWidget,
            QStringList() << "sidebearings" << "10, 34-35, 307-308");
    QTreeWidgetItem *subterm = new QTreeWidgetItem(treeWidget,
            QStringList() << "subtraction");
    (void) new QTreeWidgetItem(subterm,
            QStringList() << "of pictures" << "115, 244");
    (void) new QTreeWidgetItem(subterm,
            QStringList() << "of vectors" << "9");
}

void writeIndexEntry(QXmlStreamWriter *xmlWriter, QTreeWidgetItem *item)
{
    xmlWriter->writeStartElement("entry");
    xmlWriter->writeAttribute("term", item->text(0));
    QString pageString = item->text(1);
    if (!pageString.isEmpty()) {
        QStringList pages = pageString.split(", ");
        foreach (QString page, pages)
            xmlWriter->writeTextElement("page", page);
    }
    for (int i = 0; i < item->childCount(); ++i)
        writeIndexEntry(xmlWriter, item->child(i));
    xmlWriter->writeEndElement();
}

bool writeXml(const QString &fileName, QTreeWidget *treeWidget)
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(fileName) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    QXmlStreamWriter xmlWriter(&file);
    xmlWriter.setAutoFormatting(true);
    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("bookindex");
    for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
        writeIndexEntry(&xmlWriter, treeWidget->topLevelItem(i));
    xmlWriter.writeEndDocument();

    file.close();
    if (file.error()) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(fileName) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }
    return true;
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTreeWidget treeWidget;
    populateTree(&treeWidget);
    writeXml("out1.xml", &treeWidget);
    return app.exec();
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值