QtXml:QDomDocument、QDomNode
QDomDocument
一、描述
QDomDocument 类表示整个 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的主要访问。
由于元素、文本节点、注释、处理指令等不能存在于文档的上下文之外,因此文档类还包含创建这些对象所需的工厂函数。创建的节点对象有一个 ownerDocument() 函数,该函数将它们与创建它们的上下文中的文档相关联。
解析的 XML 在内部由对象树表示,可以使用各种 QDom 类访问这些对象树。所有 QDom 类只引用内部树中的对象。一旦最后一个引用它们的 QDom 对象或 QDomDocument 本身被删除,DOM 树中的内部对象将被删除。
元素、文本节点等的创建是使用此类中提供的各种工厂函数完成的。使用 QDom 类的默认构造函数只会导致无法操作或插入文档的空对象。
注意:如果 XML 文档很大,DOM 树最终可能会消耗大量内存。对于此类文档,QXmlStreamReader 类可能是更好的解决方案。
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()) << '\n';
n = n.nextSibling();
QDomElement elem = doc.createElement("img");
elem.setAttribute("src", "myimage.png");
docElem.appendChild(elem);
要使用 DOM 创建文档,请使用如下代码:
QDomDocument doc("mydocument");
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();
QFile file("demo.xml");
file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
QTextStream out(&file);
out.setCodec("UTF-8");
doc.save(out, 4, QDomNode::EncodingFromTextStream);
file.close();
二、成员函数
1、QDomDocument(const QDomDocument&x)
拷贝构造。副本的数据是共享的(浅拷贝),修改文档的一个节点另一个文档也会改变。
2、QDomDocument(const QDomDocumentType & doctype)
根据类型创建文档。
3、QDomDocument(const QString &name)
创建文档并将文档类型的名称设置为 name。
4、QDomDocument & operator=(const QDomDocument &x)
赋值操作。浅拷贝。
5、QDomAttr createAttribute(const QString &name)
创建名为 name 的新属性,该属性可以使用 QDomElement::setAttributeNode()插入到元素中。
如果name不是有效的XML名称,则此函数的行为由QDomImplementation::InvalidDataPolicy 控制。
QDomDocument doc;
QFile file("demo.xml");
if (!file.open(QIODevice::ReadOnly))
return 0;
if (!doc.setContent(&file))
file.close();
return 0;
file.close();
QDomElement docElem = doc.documentElement();
QDomAttr node = doc.createAttribute("test");
node.setValue("666");
docElem.setAttributeNode(node);
file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
QTextStream out(&file);
out.setCodec("UTF-8");
doc.save(out, 4, QDomNode::EncodingFromTextStream);
file.close();
6、QDomAttr createAttributeNS(const QString &nsURI, const QString &qName)
创建具有命名空间支持的新属性,该属性可以插入到元素中。 属性的名称是 qName,命名空间 URI 是 nsURI。
如果name不是有效的XML名称,则此函数的行为由QDomImplementation::InvalidDataPolicy 控制。
QDomDocument doc;
QFile file("demo.xml");
if (!file.open(QIODevice::ReadOnly))
return 0;
if (!doc.setContent(&file))
file.close();
return 0;
file.close();
QDomElement docElem = doc.documentElement();
auto nsattr = doc.createAttributeNS("url1", "p:at");//命名空间url1
docElem.setAttributeNodeNS(nsattr);
file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
QTextStream out(&file);
out.setCodec("UTF-8");
doc.save(out, 4, QDomNode::EncodingFromTextStream);
file.close();
auto nsattr = doc.createAttributeNS("url1", "p:at");//命名空间url1
nsattr.setValue("111");
docElem.setAttributeNodeNS(nsattr);
参考:
XML 命名空间
避免混合使用NS和非NS版本的DOM API
7、QDomCDATASection createCDATASection(const QString &value)
创建一个新的 CDATA 部分。
如果 value 包含不能存储在 CDATA 部分中的字符,则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
QDomCDATASection node = doc.createCDATASection(QObject::tr("This is a comment"));
docElem.insertBefore(node,docElem.firstChild());
8、QDomComment createComment(const QString &value)
创建注释。
如果 value 包含不能存储在 XML 注释中的字符,则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
QDomElement docElem = doc.documentElement();
QDomComment node = doc.createComment(QObject::tr("This is a comment"));
docElem.insertBefore(node,docElem.firstChild());
免费学习C++ Qt开发教程视频,点击下面链接免费报名领取视频学习资料
https:// ke.qq.com/course/444655? flowToken=1044418
9、QDomDocumentFragment createDocumentFragment()
创建一个新的文档片段,可用于保存文档的一部分。
QDomElement docElem = doc.documentElement();
QDomComment node = doc.createComment(QObject::tr("This is a comment"));
docElem.insertBefore(node,docElem.firstChild());
QDomDocumentFragment fragNode = doc.createDocumentFragment();
fragNode.appendChild(doc.createComment(QObject::tr("This is a Fragment comment")));
docElem.insertBefore(fragNode,docElem.firstChild());
10、QDomElement createElement(const QString &tagName)
创建一个名为 tagName 的新元素,它可以插入到 DOM 树中。
如果 tagName 不是有效的 XML 名称,则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
QDomElement docElem = doc.documentElement();
QDomElement node = doc.createElement("elementNode");
docElem.appendChild(node);
11、QDomElement createElementNS(const QString &nsURI, const QString &qName)
创建一个具有命名空间支持的新元素,可以插入到 DOM 树中。 元素的名称是 qName,命名空间 URI 是 nsURI。
如果 qName 为空字符串,则无论是否设置了无效数据策略,都返回空元素。
QDomElement docElem = doc.documentElement();
QDomElement ElementNSNode = doc.createElementNS("url1", "p:at");
ElementNSNode.setTagName("xxx");
ElementNSNode.setAttributeNS("url1", "p:at","666");
docElem.appendChild(ElementNSNode);
12、QDomEntityReference createEntityReference(const QString &name)
创建一个名为 name 的新实体引用,可以插入到文档中。
如果 name 不是有效的 XML 名称,则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
QDomElement docElem = doc.documentElement();
QDomEntityReference node = doc.createEntityReference("well");
docElem.appendChild(node);
13、QDomProcessingInstruction createProcessingInstruction(const QString &target, const QString &data)
创建可以插入文档的新处理指令。该函数将处理指令的目标设置为target,将数据设置为data。
如果目标不是有效的 XML 名称,或者数据如果包含不能出现在处理指令中的字符,则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
可参考:XML DOM - ProcessingInstruction 对象
14、QDomText createTextNode(const QString &value)
创建一个文本节点。
如果 value 包含不能存储为 XML 文档的字符数据的字符(即使以字符引用的形式),则此函数的行为由 QDomImplementation::InvalidDataPolicy 控制。
QDomElement docElem = doc.documentElement();
auto node = doc.createTextNode("well");
docElem.appendChild(node);
15、QDomDocumentType doctype()
返回此文档的文档类型。
16、QDomElement documentElement()
返回文档的根元素。
17、QDomNodeList elementsByTagName(const QString &tagname)
返回一个 QDomNodeList,它包含文档中名称为 tagname 的所有元素。节点列表的顺序是它们在元素树的先序遍历中遇到的顺序。
QDomElement docElem = doc.documentElement();
QDomNodeList list = doc.elementsByTagName("a");
for(int i = 0;i < list.count();++i)
QDomElement e = list.at(i).toElement();
qDebug()<<e.attribute("attr");
}
18、QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName)
返回一个 QDomNodeList,其中包含文档中具有本地名称 localName 和 nsURI 的命名空间 URI 的所有元素。节点列表的顺序是它们在元素树的先序遍历中遇到的顺序。
19、QDomNode importNode(const QDomNode &importedNode, bool deep)
将节点importedNode 从另一个文档导入到当前文档。此函数创建可在此文档中使用的副本。
该函数返回属于该文档的导入节点。 返回的节点没有父节点。
如果 deep 为真,则该函数不仅导入节点importedNode,还导入其整个子树。如果为false,则仅导入importedNode。参数 deep 对 QDomAttr 和 QDomEntityReference 节点没有影响,因为 QDomAttr 节点的后代总是被导入而 QDomEntityReference 节点的后代永远不会被导入。
根据节点类型,此函数的行为略有不同:
- QDomAttr:在生成的属性中,owner 元素设置为 0,指定标志设置为 true。始终为属性节点导入importNode 的整个子树:deep 无效。
- QDomDocument:无法导入文档节点。
- QDomDocumentFragment:如果 deep 为真,则该函数导入整个文档片段,否则它只会生成一个空的文档片段。
- QDomDocumentType:文档类型节点无法导入。
- QDomElement:仅导入 QDomAttr::specified() 为 true 的属性,不导入其他属性。如果 deep 为真,则该函数还导入了importedNode 的子树;否则它只导入元素节点。
- QDomEntity:实体节点可以导入,但无法使用。
- QDomEntityReference:实体引用节点的后代不会被导入,deep 没有效果。
- QDomNotation:Notation 节点可以被导入,但目前没有办法使用它们。
- QDomProcessingInstruction:将处理指令的目标和值复制到新节点。
- QDomText:将文本复制到新节点。
- QDomCDATASection:将文本复制到新节点。
- QDomComment:将文本复制到新节点。
20、bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
bool setContent(QIODevice *dev, bool namespaceProcessing, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
从字节数组/设备数据中解析 XML 文档并将其设置为文档的内容。它尝试按照 XML 规范的要求检测文档的编码。
如果namespaceProcessing 为true,解析器会识别XML 文件中的名称空间并将前缀名称、本地名称和名称空间URI 设置为适当的值。如果 namespaceProcessing 为 false,则解析器在读取 XML 文件时不进行命名空间处理。
如果发生解析错误,该函数返回false,错误信息放在*errorMsg 中,*errorLine 中的行号和*errorColumn 中的列号(除非关联的指针设置为0);否则此函数返回真。 QXmlParseException 类文档中描述了各种错误消息。请注意,如果您想向应用程序的用户显示这些错误消息,除非明确翻译,否则它们将以英文显示。
如果namespaceProcessing 为true,则函数QDomNode::prefix() 返回所有元素和属性的字符串。如果元素或属性没有前缀,则返回空字符串。
仅由空格组成的文本节点将被剥离并且不会出现在 QDomDocument 中。如果不需要这种行为,可以使用允许提供 QXmlReader 的 setContent() 重载。
21、bool setContent(const QString &text, bool namespaceProcessing, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
bool setContent(const QString &text, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
重载函数。由于文本已经是 Unicode 字符串,因此没有进行编码检测。
22、bool setContent(QXmlStreamReader *reader, bool namespaceProcessing, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
重载函数。该函数从 QXmlStreamReader 读取 XML 文档并对其进行解析。
23、QByteArray toByteArray(int indent = 1)
将解析后的文档转换回其文本表示,并返回包含编码为 UTF-8 的数据的 QByteArray。
使用 indent 作为缩进子元素的缩进量。
24、QString toString(int indent = 1)
将解析后的文档转换回其文本表示。使用 indent 作为缩进子元素的缩进量。如果缩进为 -1,则不添加空格。
QDomNode
一、描述
QDomNode是文档树的节点。
QDomNode 类的副本使用显式共享来共享它们的数据。这意味着修改一个节点将更改所有副本。
下面的示例查找 XML 文档中的第一个元素并打印作为其直接子元素的所有元素的名称。
QDomDocument d;
d.setContent(someXML);
QDomNode n = d.firstChild();
while (!n.isNull())
if (n.isElement())
QDomElement e = n.toElement();
cout << "Element name: " << e.tagName() << Qt::endl;
break;
n = n.nextSibling();
}
二、类型成员
1、enum QDomNode::EncodingPolicy:此枚举指定 save() 如何确定序列化时使用的编码。
- EncodingFromDocument:编码是从文档中获取的。
- EncodingFromTextStream:编码是从 QTextStream 中获取的。
2、enum QDomNode::NodeType:节点类型。
ElementNode
AttributeNode
TextNode
CDATASectionNode
EntityReferenceNode
EntityNode
ProcessingInstructionNode
CommentNode
DocumentNode
DocumentTypeNode
DocumentFragmentNode
NotationNode
BaseNode