[Qt教程] 第28篇 XML(二)使用DOM创建和操作XML文档

简介:
楼主
  发表于 2013-5-21 22:00:51  | 查看: 475 | 回复: 0
使用DOM创建和操作XML文档

版权声明

该文章原创于作者yafeilinux,转载请注明出处!


导语

在上一节中我们用手写的方法建立了一个XML文档,并且用DOM的方法对其进行了读取。现在我们使用代码来创建那个XML文档,并且对它实现查找、更新、插入等操作。


环境: Windows Xp + Qt 4.8.4+QtCreator 2.6.2


目录

一、创建文档
二、读取文档
三、添加节点
四、查找、删除、更新操作


正文


一、创建文档

1. 新建Qt Gui 应用,项目名称为myDom_2 ,基类为QMainWindow ,类名为MainWindow

2. 完成后打开myDom_2.pro ,然后将第一行代码更改为:
QT        += core  gui   xml
        保存该文件。

3. 双击mainwindow.ui 进入设计模式,往界面上添加Push Button Label Line Edit List Widget 等部件,设计界面如下图所示。

28-1.jpg

4. 完成后,打开mainwindow.cpp 文件,先包含头文件 #include   <QtXml> ,然后在构造函数中添加如下代码:
QFile   file("my.xml");
//  只写方式打开,并清空以前的信息
if (! file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return ;

QDomDocument   doc;
QDomProcessingInstruction   instruction;  // 添加处理指令
instruction = doc.createProcessingInstruction("xml", "version=\"1.0\"encoding=\"UTF-8\"");
doc.appendChild(instruction);
QDomElement   root = doc.createElement(tr(" 书库" ));
doc.appendChild(root); // 添加根元素

//  添加第一个book元素及其子元素
QDomElement   book = doc.createElement(tr(" 图书" ));
QDomAttr   id = doc.createAttribute(tr(" 编号" ));
QDomElement   title = doc.createElement(tr(" 书名" ));
QDomElement   author = doc.createElement(tr(" 作者" ));
QDomText   text;
id.setValue(tr("1"));
book.setAttributeNode(id);
text = doc.createTextNode(tr("Qt"));
title.appendChild(text);
text = doc.createTextNode(tr("shiming"));
author.appendChild(text);
book.appendChild(title);
book.appendChild(author);
root.appendChild(book);

//  添加第二个book元素及其子元素
book = doc.createElement(tr(" 图书" ));
id = doc.createAttribute(tr(" 编号" ));
title = doc.createElement(tr(" 书名" ));
author = doc.createElement(tr(" 作者" ));
id.setValue(tr("2"));
book.setAttributeNode(id);
text = doc.createTextNode(tr("Linux"));
title.appendChild(text);
text = doc.createTextNode(tr("yafei"));
author.appendChild(text);
book.appendChild(title);
book.appendChild(author);
root.appendChild(book);

QTextStream   out(&file);
doc.save(out,4); //  将文档保存到文件,4为子元素缩进字符数
file.close();

        这里先使用QDomDocument 类在内存中生成了一棵DOM 树,然后调用save() 函数利用QTextStream 文本流将DOM 树保存在了文件中。在生成DOM 树时主要使用了createElement() 等函数来生成各种节点,然后使用appendChild() 将各个节点依次追加进去。


5. 打开main.cpp 文件,先包含头文件: #include   <QTextCodec> ,然后在main() 函数第一行代码后面添加如下代码:
QTextCodec ::setCodecForTr( QTextCodec ::codecForName( "utf8" ));


6. 运行程序,可以看到在构建目录中生成了my.xml 文件,可以双击查看该文件的内容,效果如下图所示。

28-2.jpg


二、读取文档
        下面我们读取整个文档的内容,并显示在List Widget 部件上面,这里用的就是上一节讲到的内容。我们进入“查看全部信息”按钮单击信号槽,更改如下:
void   MainWindow ::on_pushButton_5_clicked()
{
     ui -> listWidget->clear(); // 先清空显示
     QFile   file( "my.xml" );
     if   (!file.open( QIODevice :: ReadOnly ))   return   ;
     QDomDocument   doc;
     if   (!doc.setContent(&file))
     {
        file.close();
        return   ;
     }
    file.close();

     // 返回根节点及其子节点的元素标记名
     QDomElement   docElem   =   doc.documentElement();    // 返回根元素
     QDomNode   n   =   docElem.firstChild();     // 返回根节点的第一个子节点
     while (!n.isNull())    // 如果节点不为空
     {
         if   (n.isElement())   // 如果节点是元素
        {
            QDomElement   e   =   n.toElement();   // 将其转换为元素
            ui -> listWidget->addItem(e.tagName()
                                                                           +e.attribute(tr("编号")));
            QDomNodeList   list   =   e.childNodes();
            for ( int   i= 0 ;   i<list.count();   i++)
            {
                 QDomNode   node   =   list.at(i);
                 if (node.isElement())
                    ui -> listWidget->addItem("   "
                                                                        +node.toElement().tagName()
                                     + " : " +node.toElement().text());
            }
        }
        n   =   n.nextSibling();    // 下一个兄弟节点
     }
}

        运行程序,效果如下图所示。
28-3.jpg


三、添加节点

1. 首先在设计模式,把书名和作者标签后面的Line Edit 部件的objectName 分别更改为lineEdit_title lineEdit_author 。如下图所示。

28-4.jpg 


2. 然后进入添加按钮的单击信号槽,添加如下代码:
void   MainWindow ::on_pushButton_4_clicked()
{
     ui -> listWidget ->clear();   // 我们先清空显示,然后显示“无法添加!”
     ui -> listWidget ->addItem(tr( " 无法添加!" ));
     QFile   file( "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(tr( " 图书" ));
     QDomAttr   id   =   doc.createAttribute(tr( " 编号" ));
     QDomElement   title   =   doc.createElement(tr( " 书名" ));
     QDomElement   author   =   doc.createElement(tr( " 作者" ));
     QDomText   text;
     //  我们获得了最后一个孩子结点的编号,然后加1,便是新的编号
     QString   num   =   root.lastChild().toElement().attribute(tr( " 编号" ));
     int   count   =   num.toInt()   + 1 ;
     id.setValue( QString ::number(count));
     book.setAttributeNode(id);
     text   =   doc.createTextNode( ui -> lineEdit_title ->text());
     title.appendChild(text);
     text   =   doc.createTextNode( ui -> lineEdit_author ->text());
     author.appendChild(text);
     book.appendChild(title);
     book.appendChild(author);
     root.appendChild(book);
     if (!file.open( QIODevice :: WriteOnly   |   QIODevice :: Truncate ))
        return   ;
     QTextStream   out(&file);
     doc.save(out, 4 );     // 将文档保存到文件,4为子元素缩进字符数
     file.close();
     ui -> listWidget ->clear();   // 最后更改显示为“添加成功!”
     ui -> listWidget ->addItem(tr( " 添加成功!" ));
}
这里先用只读方式打开XML文件,将其读入doc中,然后关闭。我们将新的节点加入到最后面,并使其“编号”为以前的最后一个节点的编号加1。最后我们再用只写的方式打开XML文件,将修改完的doc写入其中。运行程序,效果如下图所示。

28-5.jpg

        再次查看全部信息,可以看到新的节点已经添加了,如下图所示。

28-6.jpg


四、查找、删除、更新操作
因为这三个功能都要先利用“编号”进行查找,所以我们放在一起实现。

1. 首先将界面上“图书编号”后面的Line Edit 部件的objectName 更改为lineEdit_id


2. mainwindow.h 文件中添加public 类型的函数声明:
     void   doXml( const QString  operate);
我们使用这个函数来完成三种不同的操作,根据参数来判断不同的操作。


3. 然后到mainwindow.cpp 中添加该函数的定义:
void   MainWindow ::doXml( const   QString   operate)
{
     ui -> listWidget ->clear();
     ui -> listWidget ->addItem(tr( " 没有找到相关内容!" ));
     QFile   file( "my.xml" );
     if   (!file.open( QIODevice :: ReadOnly ))   return   ;
     QDomDocument   doc;
     if   (!doc.setContent(&file))
     {
        file.close();
        return   ;
     }
        file.close();

     QDomNodeList   list   =   doc.elementsByTagName(tr( " 图书" ));
     //  以标签名进行查找
     for ( int   i= 0 ;   i<list.count();   i++)
     {
        QDomElement   e   =   list.at(i).toElement();
        //  如果元素的“编号”属性值与我们所查的相同
        if (e.attribute(tr( " 编号" ))   ==   ui -> lineEdit_id ->text())
        {
             //  如果元素的“编号”属性值与我们所查的相同
            if (operate   ==   "delete" )    // 如果是删除操作
            {
                 QDomElement   root   =   doc.documentElement();   // 取出根节点
                 root.removeChild(list.at(i));    // 从根节点上删除该节点
                 QFile   file( "my.xml" );       // 保存更改
           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   child   =   list.at(i).childNodes();
                 // 找到它的所有子节点,就是“书名”和“作者”
                 child.at( 0 ).toElement().firstChild().setNodeValue( ui->lineEdit_title->text());
                 // 将它子节点的首个子节点(就是文本节点)的内容更新
                 child.at( 1 ).toElement().firstChild().setNodeValue( ui->lineEdit_author->text());
                 QFile   file( "my.xml" );       // 保存更改
           if (!file.open( QIODevice :: WriteOnly   |   QIODevice :: Truncate ))
                                    return ;
                 QTextStream   out(&file);
                 doc.save(out, 4 );     // 保存文档,4为子元素缩进字符数
                 file.close();
                 ui -> listWidget ->clear();
                 ui -> listWidget ->addItem(tr( " 更新成功!" ));
            }
            else   if (operate   ==   "find" )    // 如果是查找操作
            {
                 ui -> listWidget ->clear();
                 ui -> listWidget ->addItem(e.tagName() +e.attribute(tr("编号")));
                 QDomNodeList   list   =   e.childNodes();
                 for ( int   i= 0 ;   i<list.count();   i++)
                {
                     QDomNode   node   =   list.at(i);
                     if (node.isElement())
                         ui -> listWidget ->addItem( "   " +node.toElement().tagName()
                                  + " : " +node.toElement().text());
                 }
            }
        }
     }
}


4.  下面我们分别进入查找删除更新三个按钮的单击信号槽,更改如下:
// 查找
void MainWindow::on_pushButton_clicked()
{    
    doXml("find");
}

// 删除
void MainWindow::on_pushButton_2_clicked()
{    
      doXml("delete");
}

// 更新void 
MainWindow::on_pushButton_3_clicked()
{    
      doXml("update");
}

下面运行程序,查找操作结果如下图所示。

28-7.jpg


然后对编号为1 的图书进行更新,效果如下图所示。

28-8.jpg

更新后我们再次查看所有内容。如下图所示。

28-9.jpg


然后进行删除操作,如下图所示。


28-10.jpg


删除后再次查询所有内容。效果如下图所示。

28-11.jpg




结语

通过本节的例子可以看到使用DOM可以很方便的进行XML文档的随机访问,这也是它最大的优点。关于更多更详细的内容可以参考《Qt Creator快速入门》的相关章节。



涉及到的源码:  myDom_2.zip (4.21 KB, 下载次数: 12) 




相关文章
|
4月前
|
XML 数据采集 存储
使用Java和XPath在XML文档中精准定位数据
在数据驱动的时代,从复杂结构中精确提取信息至关重要。XML被广泛用于数据存储与传输,而XPath则能高效地在这些文档中导航和提取数据。本文深入探讨如何使用Java和XPath精准定位XML文档中的数据,并通过小红书的实际案例进行分析。首先介绍了XML及其挑战,接着阐述了XPath的优势。然后,提出从大型XML文档中自动提取特定产品信息的需求,并通过代理IP技术、设置Cookie和User-Agent以及多线程技术来解决实际网络环境下的数据抓取问题。最后,提供了一个Java示例代码,演示如何集成这些技术以高效地从XML源中抓取数据。
144 7
使用Java和XPath在XML文档中精准定位数据
|
4月前
|
XML JavaScript Java
【JAVA XML 探秘】DOM、SAX、StAX:揭秘 Java 中 XML 解析技术的终极指南!
【8月更文挑战第25天】本文详细探讨了Java中三种主流的XML解析技术:DOM、SAX与StAX。DOM将XML文档转换为树状结构,便于全方位访问和修改;SAX采取事件驱动模式,适用于大型文件的顺序处理;StAX则兼具DOM和SAX的优点,支持流式处理和随机访问。文中提供了每种技术的示例代码,帮助读者理解如何在实际项目中应用这些解析方法。
186 1
|
4月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
93 0
|
5月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
输出子节点的数量。结果取决于您所使用的浏览器。IE 浏览器会输出 4(提醒 4 个子节点),而其他浏览器会输出 9(提醒 9 个子节点)。
|
5月前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
遍历(Traverse)意味着在节点树中进行循环或移动。
|
5月前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
遍历(Traverse)意味着在节点树中进行循环或移动。
|
5月前
|
XML 存储 JavaScript
XML DOM - 访问节点
通过 DOM, 可全面访问 XML 文档的节点。实现这一目标有 3 种方法: - 使用 `getElementsByTagName()` 方法, - 循环遍历节点树, - 利用节点间关系进行导航。 `getElementsByTagName()` 返回一个 Node List,即一种节点数组形式。示例代码通过 `loadXMLDoc()` 函数加载 &quot;books.xml&quot; 文件到 `xmlDoc` 变量中,并随后在变量 `x` 中保存所需节点信息。
|
4月前
|
XML 数据格式
Dom4j 保存XML HL7-V3
Dom4j 保存XML HL7-V3
15 0
|
4月前
|
XML 数据格式
dom4j selectNodes 取不到值 因为XML带有命名空间 HL7
dom4j selectNodes 取不到值 因为XML带有命名空间 HL7
71 0
|
5月前
|
XML Web App开发 JavaScript
XML DOM 解析器
大多数浏览器内置了XML解析器,能将XML文档转换为可由JavaScript访问的XML DOM对象。DOM接口提供方法来遍历、访问、插入和删除XML树中的节点。加载XML文档涉及创建XMLHTTP对象,打开并发送请求给服务器,最后将响应设为DOM对象以供操作。