Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2225|回复: 4
打印 上一主题 下一主题

Qt XML读写操作

[复制链接]

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
跳转到指定楼层
楼主
发表于 2016-7-4 16:28:02 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
我们知道对XML的操作有两种方法,即DOM方式和SAX方式。二者主要区别是:DOM实现方式操作非常简单,但不适合处理过大文件;而SAX实现方式是能处理很大的XML文件,但是需要开发者写一些复杂的代码。Qt提供了对应于这两种用于读取、操作和编写XML的实现类,分别是QDomDocument类和QXmlStreamReader
回复

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
沙发
 楼主| 发表于 2016-7-4 18:14:19 | 只看该作者
本帖最后由 hechengjin 于 2016-7-4 18:15 编辑

http://blog.sina.com.cn/s/blog_a6fb6cc90101eupl.html

如何使用QXmlStreamReader来解析格式良好的XML,Qt的文档中指出,它是一种更快、更方便的Qt自己的SAX解析器(QXmlSimpleReader)的替代,它也较快,在某种情况下,比DOM(QDomDocument)更方便。
   XML文件:
  


    解析方法:



  1. void ParseXML::parseXML(QString file_name)
  2. {
  3. if(file_name.isEmpty())  
  4.         return;  
  5.   
  6.     QFile *file = new QFile(file_name);  
  7.     if(!file->open(QFile::ReadOnly | QFile::Text))
  8.         {  
  9.                 QMessageBox::information(NULL, QString("title"), QString("open error!"));

  10.         return;  
  11.     }  

  12.     //QXmlStreamReader操作任何QIODevice.
  13.     QXmlStreamReader xml(file);
  14.     QList> persons;

  15.     //解析XML,直到结束
  16.     while(!xml.atEnd() && !xml.hasError())
  17.         {
  18.         //读取下一个element.
  19.         QXmlStreamReader::TokenType token = xml.readNext();

  20.         //如果获取的仅为StartDocument,则进行下一个
  21.         if(token == QXmlStreamReader::StartDocument)
  22.                 {
  23.             continue;
  24.         }

  25.         //如果获取了StartElement,则尝试读取
  26.         if(token == QXmlStreamReader::StartElement)
  27.                 {
  28.             //如果为persons,直接进入下一个
  29.             if(xml.name() == "persons")
  30.                         {
  31.                 continue;
  32.             }
  33.             
  34.                         //如果为person,则对其进行解析
  35.             if(xml.name() == "person")
  36.                         {
  37.                 persons.append(this->parsePerson(xml));
  38.             }
  39.         }
  40.     }
  41.   
  42.     if(xml.hasError())
  43.         {
  44.         QMessageBox::information(NULL, QString("parseXML"), xml.errorString());
  45.         }
  46.                
  47.         //从reader中删除所有设备、数据,并将其重置为初始状态
  48.                 xml.clear();
  49. }

  50. QMap ParseXML::parsePerson(QXmlStreamReader& xml)
  51. {
  52.     QMap person;

  53.     //检查是否获取person
  54.     if(xml.tokenType() != QXmlStreamReader::StartElement &&
  55.             xml.name() == "person")
  56.         {
  57.         return person;
  58.     }

  59.     //获取person属性
  60.     QXmlStreamAttributes attributes = xml.attributes();
  61.     if(attributes.hasAttribute("id"))
  62.         {
  63.         person["id"] = attributes.value("id").toString();
  64.     }
  65.    
  66.         //操作下一个
  67.         xml.readNext();

  68.     while(!(xml.tokenType() == QXmlStreamReader::EndElement &&
  69.             xml.name() == "person"))
  70.         {
  71.         if(xml.tokenType() == QXmlStreamReader::StartElement)
  72.                 {
  73.             if(xml.name() == "name")
  74.                         {
  75.                 this->addElementDataToMap(xml, person);
  76.             }
  77.            
  78.             if(xml.name() == "age")
  79.                         {
  80.                 this->addElementDataToMap(xml, person);
  81.             }
  82.          
  83.             if(xml.name() == "email")
  84.                         {
  85.                 this->addElementDataToMap(xml, person);
  86.             }
  87.          
  88.             if(xml.name() == "website")
  89.                         {
  90.                 this->addElementDataToMap(xml, person);
  91.             }
  92.         }
  93.      
  94.         xml.readNext();
  95.     }

  96. QString id = person["id"];
  97.     QString name = person["name"];
  98.     QString age =  person["age"];
  99.     QString email = person["email"];
  100.     QString website = person["website"];

  101.     return person;
  102. }

  103. void ParseXML::addElementDataToMap(QXmlStreamReader& xml,
  104.                                       QMap& map) const
  105. {
  106.     if(xml.tokenType() != QXmlStreamReader::StartElement)
  107.         {
  108.         return;
  109.     }

  110.     QString elementName = xml.name().toString();
  111.     xml.readNext();
  112.    
  113.     if(xml.tokenType() != QXmlStreamReader::Characters)
  114.         {
  115.         return;
  116.     }
  117.    
  118.     map.insert(elementName, xml.text().toString());
  119. }
复制代码


回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
板凳
 楼主| 发表于 2016-7-4 18:16:05 | 只看该作者
回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
地板
 楼主| 发表于 2016-7-5 14:41:06 | 只看该作者

一 API介绍

    readNext():从xml输入流中读取下一个记号

    name():记号的名称,即<名称></名称>

    isStartElement():判断当前已读取的记号是否为开始元素,开始元素即<>

    isEndElement():判断当前已读取的记号是否为结束元素,结束元素即</>

    readElementText():读取当前记号对应的文本值,<>文本值</>

    atEnd():判断是否为文件结尾


二 应用实例

对短信message.xml进行读取,xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<DATA>
    <Sms>
        <Name>wlc</Name>
        <Number>18725658147</Number>
        <Content>短信测试1</Content>
        <Time>2012-07-25 23:54:10</Time>
    </Sms>
    <Sms>
        <Name>rt</Name>
        <Number>13555555555</Number>
        <Content>短信测试2</Content>
        <Time>2012-07-26 00:21:24</Time>
    </Sms>
    <Sms>
        <Name>wzg</Name>
        <Number>18656765434</Number>
        <Content>短息测试3</Content>
        <Time>2012-07-26 00:22:03</Time>
    </Sms>
</DATA>
  

    读取代码如下:


  1. void read_message()
  2. {
  3.     QFile file(fi"message.xml");
  4.     if(file.open(QIODevice::ReadOnly | QIODevice::Text))
  5.     {
  6.         Message *message;
  7.         QXmlStreamReader reader(&file);
  8.         reader.readNext();
  9.         while (!reader.atEnd())
  10.         {
  11.             if(reader.isStartElement())
  12.             {
  13.                 if(reader.name() == "Sms")
  14.                 {
  15.                     message = new Message();
  16.                 }
  17.                 else if(reader.name() == "Name")
  18.                 {
  19.                     message->SetMsgName(reader.readElementText());
  20.                 }
  21.                 else if(reader.name() == "Number")
  22.                 {
  23.                     message->SetMsgPhone(reader.readElementText());
  24.                 }
  25.                 else if(reader.name() == "Content")
  26.                 {
  27.                     message->SetMsgContent(reader.readElementText());
  28.                 }
  29.                 else if(reader.name() == "Time")
  30.                 {
  31.                     message->SetMsgTime(reader.readElementText());
  32.                 }
  33.             }
  34.             else if(reader.isEndElement())
  35.             {
  36.                 if(reader.name() == "Sms")
  37.                 {
  38.                      message_map->insert(std::make_pair(message->GetMsgPhone(), message));
  39.                 }
  40.             }
  41.             reader.readNext();
  42.         }
  43.     }
  44.     else
  45.     {
  46.         //qDebug()<<"read inbox file error...";
  47.     }
  48.     file.close();
  49. }
复制代码


回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
5#
 楼主| 发表于 2016-7-6 14:26:31 | 只看该作者
http://mobile.51cto.com/symbian-268953.htm

本文介绍的是在Qt使用QDomDocument类实现XML文件的操作,QDomNode类是一个父类,QDomDocument是QDomNode的一个子类,鉴于大部分QDomNode的类型都是QDomDocument。

XML,全称为扩展标记语言(extensible markup language).是一种非常方便的数据交换工具。现在Blog的订阅系统输出格式就是满足XML规范的RSS格式,还有SVG矢量图形也使用了XML格式。

我们在取得一个XML格式的文件后,需要作句法分析去提取发布方提供的信息。而QtXML提供了很好的支持,包括DOM的实现和SAX的实现。

DOM是Document Object Model的简称,其实现方式是将整个文档当作一个对象来装入内存进行处理,然后开发者可以访问这个对象中的每一个节点,每一个节点对应XML文件里的一个标记。这种方式的优点是操作非常简单,缺点是需要将整个文件放入内存,不适合处理过大文件。这种方式在Qt中的实现类是QDomDocument,也是本文将要讲解的。以Blog为代表的RSS文件都不会很大,适合用这种方式来处理。

SAX是Simple API for XML的简称,其实现方式是按阶段将文档读取到内存中,在碰到标签或者其它阶段的时候,调用开发者预先设计好的回调函数去处理。这种方式的缺点是需要开发者写回调函数去处理不同标签,代码复杂一些,优点是能处理很大的XML文件。这种方式在Qt中的实现类叫QXmlStreamReader。

下面部分是代码讲解

(1)如果需要使用QDomDocument,那么请在你的项目.pro文件里加上一句”QT += xml”,不然无法编译通过。

(2)

  • QDomDocument doc;  
  • QFile file(”rss.xml”);  
  • QString errorStr;  
  • int errorLine;  
  • int errorCol;  
  • //setContent是将指定的内容指定给QDomDocument解析,第一参数可以是QByteArray或者是文件名等  
  • if(!doc.setContent(&file,true,&errorStr,&errorLine,&errorCol))  
  • {  
  • //如果出错,则会进入这里。errorStr得到的是出错说明  
  • //errorLine和errorCol则是出错的行和列  
  • }

如果上面的步骤没出错,那么恭喜你,你已经得到了一个完整的QDomDocument对象doc,你只要访问doc的子节点或子子节点就可以取得XML中所有标记上的内容了。

(3)

可以通过doc.childNodes()获得doc的所有的子节点列表QDomNodeList。比如

  • QDomNodeList list=doc.childNodes();  
  • for(int i=0;i<list.count();i++){  
  • QDomNode node=list.at(i);//好的风格当然是把定义写在外面  
  • //qDebug()<<”node name is “<<node.nodeName();  
  • //qDebug()<<”node type is “<<.nodeType();  
  • }

通过上面的方法你就能知道每个节点的名字和类型了,节点名字就是标记的名字。打印出来对照着xml文件看就很容易明白了。QDomNode类是一个父类,QDomDocument是QDomNode的一个子类,鉴于大部分QDomNode的类型都是QDomDocument.那么你可以使用toDocument()函数将QDomNode类型转换成QDomDocument.

  • QString text=node.toElement().text();

上面的语句可以将一个节点里的文本取出,也就是标记内的文本部分。使用该函数获得的编码就已经是unicode格式了,不需要再做转换。

小结:对于Qt使用QDomDocument操作XML文件的内容讲解完了,希望本篇文章对你有所帮助吧。


回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|firemail ( 粤ICP备15085507号-1 )

GMT+8, 2024-11-23 03:19 , Processed in 0.067083 second(s), 22 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表