转载自:http://blog.csdn.net/liang19890820/article/details/52805902
XML(EXtensible Markup Language - 可扩展标记语言)是一种用于记录多种数据类型的标记语言。使用 XML 可以将各类型的文档定义为容易读取的格式,便于用户读取。而且,在应用程序中使用 XML,可以轻松实现数据交换。
简述使用 XML 模块XML 的访问方式 DOMSAX SAX2 介绍 XML 流 QXmlStreamReaderQXmlStreamWriter 使用哪种方式更多参考要链接到 XML 模块,需要在 qmake 项目文件 .pro 中添加:
QT += xml包含模块中类的定义,使用:
#include <QtXml>Qt 提供了两种访问 XML 文档的方式:DOM 和 SAX。
DOM 方式:将 XML 文档转换为树形结构存储到内存中,再进行读取,消耗的内存比较多。此外,由于文档都已经存储到内存,所以需要频繁实现修改等操作时,使用起来比较方便。
SAX 方式:相比于 DOM,SAX 是一种速度更快,更有效的方法,它逐行扫描文档,一边扫描一边解析(由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中,这对于大型文档的解析是个巨大优势)。而且相比于 DOM,SAX 可以在解析文档的任意时刻停止解析。但操作复杂,很难修改 XML 数据。
DOM Level 2 是用于 XML 接口的一个 W3C 推荐标准,将 XML 文档的组成映射为一个树结构。DOM Level 2 的规范可以在 http://www.w3.org/DOM/ 上找到。
DOM 提供了一个访问和更改 XML 文件内容和结构的接口。它创建了一个文档的分层视图(树视图),因此,与 SAX2 接口相反,在解析之后,文档的对象模型常驻在内存中,这使得操作变得更加容易。 文档树中的所有 DOM 节点都是 QDomNode 的子类,文档本身由 QDomDocument 对象表示。
Qt 为 DOM 提供了用于操作 XML 的多种 C++类,均以 QDom 开头:
类描述QDomAttr表示一个 QDomElement 的属性QDomCDATASection表示一个 XML CDATA 部分QDomCharacterData表示 DOM 中的一个通用字符串QDomComment表示一个 XML 注释QDomDocument表示一个 XML 文档QDomDocumentFragmentQDomNodes 树,通常不是一个完整的 QDomDocumentQDomDocumentType表示文档树中的 DTDQDomElement表示 DOM 树中的一个元素QDomEntity代表一个 XML 实体QDomEntityReference代表一个 XML 实体引用QDomImplementationDOM 实现的功能的信息QDomNamedNodeMap包含一个节点集合,节点可以通过名字来访问QDomNode一个 DOM 树中所有节点的基类QDomNodeListQDomNode 对象列表QDomNotation代表一个 XML 表示法QDomProcessingInstruction代表 XML 处理指令QDomText表示解析的 XML 文档中的文本数据QDom 类通常使用如下:
QDomDocument doc("mydocument"); QFile file("mydocument.xml"); if (!file.open(QIODevice::ReadOnly)) return; if (!doc.setContent(&file)) { file.close(); return; } file.close(); // 打印出作为最外层元素的所有直接子元素的元素名称 QDomElement docElem = doc.documentElement(); QDomNode n = docElem.firstChild(); while(!n.isNull()) { QDomElement e = n.toElement(); // 尝试将节点转换为元素 if(!e.isNull()) { cout << qPrintable(e.tagName()) << endl; // 节点真的是一个元素 } n = n.nextSibling(); } // 这里,我们在文档的末尾添加一个新元素 QDomElement elem = doc.createElement("img"); elem.setAttribute("src", "myimage.png"); docElem.appendChild(elem);一旦 doc 和 elem 超出范围,代表 XML 文档的整个内部树被删除。
要使用 DOM 创建文档,请使用如下代码:
QDomDocument doc("MyML"); QDomElement root = doc.createElement("MyML"); doc.appendChild(root); QDomElement tag = doc.createElement("Greeting"); root.appendChild(tag); QDomText t = doc.createTextNode("Hello World"); tag.appendChild(t); QString xml = doc.toString();有关文档对象模型的更多信息,请参阅文档对象模型(DOM)Level 1 和evel 2 Core 核心规范。
SAX 是用于 XML 解析器的基于事件的标准接口。XML 类的设计遵循 SAX2 Java interface,名称适合 Qt 的命名约定。对于任何使用 SAX2 的人来说,使用 Qt XML 类应该非常容易。
SAX2 接口是一种事件驱动的机制,能够为用户提供文档信息。这里提到的“事件”意味着解析器报告的东西。例如,它遇到了一个开始标记,或者结束标记等。
为了使它不那么抽象,考虑以下示例:
<quote>A quotation</quote>在读取(SAX2 解析器通常被称为“读取器”)时,上述文档将触发三个事件:
出现开始标记(<quote>)。找到字符数据(即文本)“A quotation”。解析结束标记(</ quote>)。每次发生这样的事件时,解析器就会报告它,可以设置事件处理程序来响应这些事件。
虽然这是一种快速、简单地读取 XML 文档的方法,但是操作困难,因为数据不存储,而是串行处理并丢弃。DOM 接口读取并以树结构存储整个文档,这需要更多的内存,但更容易操作文档的结构。
Qt XML 模块提供了一个抽象类 QXmlReader,它定义了潜在的 SAX2 读取器的接口,它有一个简单的 XML 读取器的实现 - QXmlSimpleReader(目前只有这一个,在将来的版本中,可能有更多的具有不同属性的读取器。例如:验证解析器),通过子类化,很容易适应。
读取器通过特殊的 handler 类来报告解析事件:
Handler 类描述QXmlContentHandler报告与文档内容相关的事件(例如:开始标签或字符)QXmlDTDHandler报告与 DTD 相关的事件(例如:符号声明)QXmlErrorHandler报告解析期间发生的错误或警告(QXmlParseException 用于向使用 QXmlErrorHandler 的接口报告错误)QXmlEntityResolver在解析期间报告外部实体,并允许用户解析外部实体本身,而不是将其留给读取器。QXmlDeclHandler报告进一步的 DTD 相关事件(例如:属性声明)QXmlLexicalHandler报告与文档的词法结构相关的事件(DTD 的开头、注释等)由于处理程序类只描述接口,因此必须实现所有函数。Qt 提供了 QXmlDefaultHandler 类使之变得更容易:它实现所有函数的默认行为(不做任何操作),所以可以子类化它,只需要实现感兴趣的函数即可。
要读取输入的 XML 数据,需要使用特殊类 QXmlInputSource(QXmlReader 子类的输入数据)。
除了已经提到的,以下 SAX2 支持类还提供了其他有用的功能:
类描述QXmlAttributes用于向来是元素事件中传递属性QXmlLocator用于获取事件的实际解析位置QXmlNamespaceSupport用于为读取器实现命名空间支持。注意:命名空间不会更改解析行为,它们只通过处理程序进行报告。从 4.3 版本开始,Qt 提供了两个新的类来读写 XML:QXmlStreamReader 和 QXmlStreamWriter。
流读取器将 XML 文档报告为标记流。这与 SAX 不同,因为 SAX 应用程序提供处理程序从解析器接收 XML 事件,而 QXmlStreamReader 驱动循环,在需要时从读取器中提取标记。这种拉取方法使得构建递归下降解析器成为可能,允许 XML 解析代码被拆分成不同的方法或类。
QXmlStreamReader 是一个格式良好的 XML 1.0 解析器,排除外部解析实体。因此,只要没有错误发生,应用程序代码就可以确保由 QXmlStreamReader 提供的数据满足 W3C 对于格式良好的 XML 的标准。否则,可以使用诸如 atEnd()、error() 和 hasError() 的函数来检查和查看错误。
应用程序中,QXmlStreamReader 类比用于 SAX 解析的 QXmlSimpleReader 类速度更快,且更好用。QXmlStreamReader 类用于读取数据,他可以通过 QIODevice 和 QByteArray 读取列数据。
一个典型的 QXmlStreamReader 循环:
QXmlStreamReader xml; ... while (!xml.atEnd()) { xml.readNext(); ... // 做处理 } if (xml.hasError()) { ... // 做错误处理 }QXmlStreamWriter 类仅通过数据流写入 XML 数据,该类由成员函数 setDevice() 指定的 QIODevice 运行。
下面的简化代码片段,显示了该类用缩进编写格式化 XML 的基本用法:
QXmlStreamWriter stream(&output); stream.setAutoFormatting(true); stream.writeStartDocument(); ... stream.writeStartElement("bookmark"); stream.writeAttribute("href", "http://qt-project.org/"); stream.writeTextElement("title", "Qt Project"); stream.writeEndElement(); // bookmark ... stream.writeEndDocument();虽然 Qt XML 模块提供了 XML 对 SAX 和 DOM 标准的 C++ 实现,但是助手中有这么一句话:
The module is not actively maintained anymore. Please use the QXmlStreamReader and QXmlStreamWriter classes in Qt Core instead.
此模块不再进行积极地维护,请使用Qt Core 中的 QXmlStreamReader 和 QXmlStreamWriter 类代替。
也就是说,助手更建议我们使用 QXmlStreamReader 和 QXmlStreamWriter 类,而非 XML 模块。