使用DOM读写XML文档

(Document Object Model,文档对象模型),是W3C的推荐标准,它提供了一个接口来访问和改变一个XML文件的内容、结构,可以将XML文档表示为一个存储在内存中具有层次的树视图。文档本身由QDomDocument对象来表示,而文档树中的所有的DOM节点都是QDomNode类的子类。

1 所使用类继承关系

QDomNode 
|----- QDomDocument ----- 文档本身
|----- QDomElement ----- 元素
|----- QDomProcessingInstruction -----XML说明
|----- QDomAttr ----- 属性
|----- QDomCharacterData
        |----- QDomText ----- 文本内容
        |----- QDomComment -----注释     <!-- this is a comment -->

QDomNode可以表示所有的DOM节点,比如这里的说明、元素、属性和文本等,然后使用对应的isProcessingInstruction()、isElement()、isAttr()和isText()等函数来判断是否是该类型的元素;如果是,可以使用toProcessingInstruction()、toElement()、toAttr()和toText()等函数转换为具体的节点类型。

2 使用DOM写入XML

    //生成xml文件
    QDomDocument doc;
    //添加处理指令即xml说明
    QDomProcessingInstruction instruction;        //说明的格式要正确,多或少写空格都会导致读取xml文件失败
    instruction = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);

    //添加根元素
    QDomElement root = doc.createElement("书库");
    doc.appendChild(root);

    //添加图书元素及其子元素
    QDomElement book = doc.createElement("图书");

    QDomAttr id = doc.createAttribute("编号");
    id.setValue(QString("1"));
    book.setAttributeNode(id);

    QDomElement title = doc.createElement("书名");
    QDomElement author = doc.createElement("作者");
    QDomText text;
    text = doc.createTextNode("Qt");
    title.appendChild(text);
    text = doc.createTextNode("shiming");
    author.appendChild(text);

    book.appendChild(title);
    book.appendChild(author);

    root.appendChild(book);

    //添加第二个图书元素及其子元素
    book = doc.createElement("图书");

    id = doc.createAttribute("编号");
    id.setValue(QString("2"));
    book.setAttributeNode(id);

    title = doc.createElement("书名");
    author = doc.createElement("作者");
    text = doc.createTextNode("Linxu");
    title.appendChild(text);
    text = doc.createTextNode("yafei");
    author.appendChild(text);

    book.appendChild(title);
    book.appendChild(author);

    root.appendChild(book);

    QFile file("../myDOM2/my.xml");
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
        return;
    QTextStream out(&file);
    //将文档保存到文件,4为子元素缩进字符数
    doc.save(out,4);
    file.close();

3 使用DOM读取XML文档

    QDomDocument doc;
    QFile file("../myDom1/my.xml");
    if(!file.open(QIODevice::ReadOnly))
    {
        return;
    }
    //将文件内容读取到doc中
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();

    //获得doc的第一个结点,即xml说明
    QDomNode firstNode = doc.firstChild();
    qDebug() << qPrintable(firstNode.nodeName()) << qPrintable(firstNode.nodeValue());
    //qDebug() << firstNode.nodeName() << "   " << firstNode.nodeValue();

    //返回根元素
    QDomElement docElem = doc.documentElement();

    //返回根元素的第一个子结点
    QDomNode n = docElem.firstChild();
    while(!n.isNull())
    {
        if(n.isElement())
        {
            //将其转换为元素
            QDomElement e = n.toElement();
            //返回元素标记和属性的值
            qDebug() << qPrintable(e.tagName()) << qPrintable(e.attribute("id"));
            //获取e元素的所有子结点列表
            QDomNodeList list = e.childNodes();
            for(int i = 0; i < list.count(); i++)
            {
                QDomNode node = list.at(i);
                if(node.isElement())
                {
                    qDebug() << "   " << qPrintable(node.toElement().tagName())
                             << qPrintable(node.toElement().text());
                }
            }
        }
        //转到下一个兄弟结点
        n = n.nextSibling();
    }

4 添加一个节点

    ui->listWidget->clear();
    ui->listWidget->addItem(tr("无法添加!"));

    QFile file("../myDOM2/my.xml");
    if(!file.open(QIODevice::ReadOnly))
        return;
    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();

    QDomElement root = doc.documentElement();
    QDomElement book = doc.createElement("图书");
    QDomAttr id = doc.createAttribute("编号");
    QDomElement title = doc.createElement("书名");
    QDomElement author = doc.createElement("作者");
    QDomText text;

    QString num = root.lastChild().toElement().attribute("编号");
    int count = num.toInt() + 1;

    id.setValue(QString::number(count));
    book.setAttributeNode(id);

    text = doc.createTextNode(ui->lineEdit_bookName->text());
    title.appendChild(text);
    text = doc.createTextNode(ui->lineEdit_author->text());
    author.appendChild(text);
    book.appendChild(title);
    book.appendChild(author);
    root.appendChild(book);

    //QFile file("../myDOM2/my.xml");
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
        return;
    QTextStream out(&file);
    //将文档保存到文件,4为子元素缩进字符数
    doc.save(out,4);
    file.close();

    ui->listWidget->clear(); //最后更改显示为添加成功
    ui->listWidget->addItem(tr("添加成功"));

5 查找、更新、删除

    ui->listWidget->clear();
    ui->listWidget->addItem(tr("没有找到相关内容"));
    QFile file("../myDOM2/my.xml");
    if(!file.open(QIODevice::ReadOnly))
        return;
    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();

    QDomNodeList list = doc.elementsByTagName("图书");
    for(int i = 0; i < list.count(); i++)
    {
        QDomElement e = list.at(i).toElement();
        if(e.attribute("编号") == ui->lineEdit_id->text())
        {
            if(operate == "delete")
            {
                QDomElement root = doc.documentElement();
                root.removeChild(list.at(i));

                if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
                    return ;
                QTextStream out(&file);
                doc.save(out,4);
                file.close();
                ui->listWidget->clear();
                ui->listWidget->addItem(tr("删除成功!"));
            }
            else if(operate == "update")
            {
                QDomNodeList childList = list.at(i).childNodes();
                childList.at(0).toElement().firstChild().setNodeValue(ui->lineEdit_bookName->text());
                childList.at(1).toElement().firstChild().setNodeValue(ui->lineEdit_author->text());

                if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
                    return ;
                QTextStream out(&file);
                doc.save(out,4);
                file.close();
                ui->listWidget->clear();
                ui->listWidget->addItem(tr("更新成功!"));
            }
            else if(operate == "find")
            {
                ui->listWidget->clear();
                ui->listWidget->addItem(e.tagName() + e.attribute("编号"));

                QDomNodeList childList = e.childNodes();
                for(int i = 0; i < list.count(); i++)
                {
                    QDomNode node = childList.at(i);
                    if(node.isElement())
                    {
                        ui->listWidget->addItem("   " + node.toElement().tagName() + ":"
                                                      + node.toElement().text());
                    }
                }
            }
        }
    }

6 使用中遇到的问题

问题1:setcontent()  读取mxl文件失败
<?xml version="1.0" encoding="UTF-8"?>  xml说明格式不正确,中间少了或多了空格

问题2:QDomElement  如果没有孩子或者内容就显示单标签,否则就是标签对

问题3:当xml文件以gb2312方式编码时,含有中文标签或属性时,使用setContext方式读取

文件时会失败。解决方式:使用读取文本文件的方式读入xml内容,再构造QDomDocument。

保存xml文件时需要指定保存编码格式,使用流的方式。

    //读xml
    QFile file("F:/example/vs2010/txt/gbk.xml");
	if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
	return;
	}
	QTextStream in(&file);
	in.setCodec("gb2312");
	QString s = in.readAll();
    QDomDocument doc = QDomDocument(s);


    QDomDocument doc;
	//添加处理指令即xml说明
	QDomProcessingInstruction instruction;        //说明的格式要正确,多或少写空格都会导致读取xml文件失败
	instruction = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"gb2312\"");
	doc.appendChild(instruction);

    //写xml
    QFile file("F:/example/vs2010/txt/gbk.xml");
	if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
		return;
	QTextStream out(&file);
	//将文档保存到文件,4为子元素缩进字符数
	out.setCodec("gb2312");
	//doc.save(out,4);
	QString str = doc.toString(4);
	out << str;
	//doc.save(out,4,QDomNode::EncodingFromTextStream);
	file.close();

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐