和HTML的语法很相似,但不同之处在于: HTML 被设计用来显示数据,其关注的是数据的外观,XML 被设计用来传输和存储数据,其关注的是数据的内容,因此,XML主要用来作为数据的存储和共享。
XML文档是一种树的结构,从根部扩展到枝叶。以下是一个XML示例
<root>
<class name="Rect">
<object name="obj1">
<x1>10x1>
<y1>10y1>
<x2>50x2>
<y1>50y1>
<linewidth>2linewidth>
<scale>0scale>
<rotate>0rotate>
object>
class>
root>
其中第一行 是XML 声明。它定义 XML 的版本和所使用的编码格式,
为根节点的起始(在XML中可以自定义节点名称),
为子元素,其中name
为其属性,值为Rect
;每一个子元素都可以拥有子元素,故class
的子元素为object
,依次类推; 所有的元素都可以有文本内容和属性,如x1的文本为10,x2的文本为50。
使用QT自带的模块QXmlStreamWriter
QXmlStreamWriter有三种构造方式,分别是
QXmlStreamWriter::QXmlStreamWriter([QString](qstring.html) **string*);
QXmlStreamWriter::QXmlStreamWriter([QByteArray](qbytearray.html) **array*);
QXmlStreamWriter::QXmlStreamWriter([QIODevice](qiodevice.html) **device*)
第一种和第二种分别是创建一个QString和QByteArray对象,然后将xml流写入到其中,第三种则是创建一个文件设备将xml流写入其中,一般来说,第三种常用。
autoFormatting:bool量,表示是否自动格式化文档,其相关读写函数为:
void setAutoFormatting(bool enable)
bool autoFormatting() const
autoFormattingIndent:int变量,当自动格式化为真时,它表示缩进的空格或者制表符的数量,相关读写函数为:
int autoFormattingIndent() const
void setAutoFormattingIndent(int spacesOrTabs)
一般4个空格等于一个制表符,也就是说setAutoFormattingIndent(4)
的效果与setAutoFormattingIndent(-1)
的效果是一样的。
这里只介绍常用的一些方法。
1、自动格式化代码
void QXmlStreamWriter::setAutoFormatting(bool enable)
2、 设置文档编码
void QXmlStreamWriter::setCodec(QTextCodec *codec);
void QXmlStreamWriter::setCodec(const char *codecName)
默认是utf-8
,其它支持的编码格式如下:
Big5
Big5-HKSCS
CP949
EUC-JP
EUC-KR
GB18030
HP-ROMAN8
IBM 850
IBM 866
IBM 874
ISO 2022-JP
ISO 8859-1 to 10
ISO 8859-13 to 16
Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
KOI8-R
KOI8-U
Macintosh
Shift-JIS
TIS-620
TSCII
UTF-8
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
Windows-1250 to 1258
3、设置自动缩进值
void setAutoFormattingIndent(int spacesOrTabs)
4、开始写xml文档时,需要先设置xml的版本和所使用的编码,一般为1.0版本,编码为utf-8,相关函数为:
void QXmlStreamWriter::writeStartDocument();
void QXmlStreamWriter::writeStartDocument(const QString &version);
void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)
与其相对应的,关闭文档写入需要调用函数
void QXmlStreamWriter::writeEndDocument();
5、xml文档为树结构,其有一个根节点,根节点下面都挂在着许多元素,节点和元素设置都为以下函数
void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name);
void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
与其相对应的,关闭节点或元素需要调用函数
void QXmlStreamWriter::writeEndElement()
6、每一个元素都可以有若干个属性,写入带有名称和值的属性
void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value);
void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value);
void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute &attribute);
void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes &attributes);
7、写文本
void QXmlStreamWriter::writeCharacters(const QString &text);
8、写入带有名称和文本的元素
void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text);
void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text);
9、写注释
void QXmlStreamWriter::writeComment(const QString &text);
还有一些方法就不一一介绍了,以上已经可以写出一个完整的xml文档。
将一些图元的信息写入到xml文件中。
void MainWindow::on_btnWrite_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save File",
"./untitled.xml","Xml(*.xml)");
qDebug() << fileName;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "Save failed";
return;
}
/* 打开文件成功,开始写入 */
QXmlStreamWriter writer(&file);
writer.setCodec("utf-8");
writer.writeStartDocument("1.0");
writer.setAutoFormatting(true);
writer.setAutoFormattingIndent(-1);
writer.writeStartElement("root");
writer.writeComment("写入矩形图元的信息");
writer.writeStartElement("class");
writer.writeAttribute("name", "Rect");
writer.writeStartElement("object");
writer.writeAttribute("name", "obj1");
writer.writeTextElement("x1", QString::number(10));
writer.writeTextElement("y1", QString::number(10));
writer.writeTextElement("x2", QString::number(50));
writer.writeTextElement("y1", QString::number(50));
writer.writeTextElement("linewidth", QString::number(2));
writer.writeTextElement("scale", QString::number(0));
writer.writeTextElement("rotate", QString::number(0));
writer.writeEndElement();
writer.writeStartElement("object");
writer.writeAttribute("name", "obj2");
writer.writeTextElement("x1", QString::number(20));
writer.writeTextElement("y1", QString::number(30));
writer.writeTextElement("x2", QString::number(50));
writer.writeTextElement("y1", QString::number(60));
writer.writeTextElement("linewidth", QString::number(2));
writer.writeTextElement("scale", QString::number(0));
writer.writeTextElement("rotate", QString::number(90));
writer.writeEndElement();
writer.writeEndElement();
writer.writeComment("写入线图元的信息");
writer.writeStartElement("class");
writer.writeAttribute("name", "Line");
writer.writeStartElement("object");
writer.writeAttribute("name", "obj1");
writer.writeTextElement("x1", QString::number(10));
writer.writeTextElement("y1", QString::number(10));
writer.writeTextElement("x2", QString::number(50));
writer.writeTextElement("y1", QString::number(50));
writer.writeTextElement("linewidth", QString::number(2));
writer.writeTextElement("scale", QString::number(0));
writer.writeTextElement("rotate", QString::number(0));
writer.writeEndElement();
writer.writeStartElement("object");
writer.writeAttribute("name", "obj2");
writer.writeTextElement("x1", QString::number(10));
writer.writeTextElement("y1", QString::number(10));
writer.writeTextElement("x2", QString::number(50));
writer.writeTextElement("y1", QString::number(50));
writer.writeTextElement("linewidth", QString::number(2));
writer.writeTextElement("scale", QString::number(0));
writer.writeTextElement("rotate", QString::number(0));
writer.writeEndElement();
writer.writeEndElement();
writer.writeComment("写入椭圆图元信息");
writer.writeStartElement("class");
writer.writeAttribute("name", "Ellipse");
writer.writeCharacters("无椭圆图元");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
file.close();
}
最后构成的xml文档如下:
<root>
<class name="Rect">
<object name="obj1">
<x1>10x1>
<y1>10y1>
<x2>50x2>
<y1>50y1>
<linewidth>2linewidth>
<scale>0scale>
<rotate>0rotate>
object>
<object name="obj2">
<x1>20x1>
<y1>30y1>
<x2>50x2>
<y1>60y1>
<linewidth>2linewidth>
<scale>0scale>
<rotate>90rotate>
object>
class>
<class name="Line">
<object name="obj1">
<x1>10x1>
<y1>10y1>
<x2>50x2>
<y1>50y1>
<linewidth>2linewidth>
<scale>0scale>
<rotate>0rotate>
object>
<object name="obj2">
<x1>10x1>
<y1>10y1>
<x2>50x2>
<y1>50y1>
<linewidth>2linewidth>
<scale>0scale>
<rotate>0rotate>
object>
class>
<class name="Ellipse">无椭圆图元class>
root>
使用QT自带的模块QXmlStreamReader
可以通过
QXmlStreamReader(const char *data)
QXmlStreamReader(const QString &data)
QXmlStreamReader(const QByteArray &data)
QXmlStreamReader(QIODevice *device)
QXmlStreamReader()
namespaceProcessing:bool变量,指是否处理命名空间,相关读写函数为
bool namespaceProcessing() const
void setNamespaceProcessing(bool)
1、设置文件设备,如果你使用了无参的构造,则可以通过下面这个函数来设置要读取的文件
void setDevice(QIODevice *device)
2、读取下一个下一个标记
QXmlStreamReader::TokenType QXmlStreamReader::readNext();
读取xml文档主要就用这一个函数,通过其返回值 QXmlStreamReader::TokenType
来判断读取的是什么元素,枚举TokenType
如下
enum TokenType {
NoToken = 0,
Invalid,
StartDocument,
EndDocument,
StartElement,
EndElement,
Characters,
Comment,
DTD,
EntityReference,
ProcessingInstruction
};
error()
和errorString()
documentVersion()
和编码格式documentEncoding()
namespaceUri()
和name()
中,其属性值保存在attribute()
中。text()
中text()
中text()
中3、读取开始节点中的文本
QString QXmlStreamReader::readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour = ErrorOnUnexpectedElement)
这个函数用在当读取的标记为StartElement
之后,直接调用这个函数可以更方便的获取其内容
读取上面写入的文档,示例代码为:
void MainWindow::on_btnRead_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, "Save this file As"
, "./", "Xml(*.xml)");
qDebug() << fileName;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "Save failed";
return;
}
QXmlStreamReader reader(&file);
QXmlStreamReader::TokenType token;
QXmlStreamAttributes attribute;
QString str, attrStr;
while (!reader.atEnd()) {
token = reader.readNext();
if(token == QXmlStreamReader::StartElement)
{
str = reader.name().toString();
if(QString::compare(str, "root") == 0)
{
qDebug() << "这是根节点:"<< str;
qDebug() << "----------------";
}
else if(QString::compare(str, "class") == 0)
{
attribute = reader.attributes();
if(attribute.hasAttribute("name"))
{
attrStr.clear();
attrStr = attribute.value("name").toString();
}
qDebug() << "************************************************";
qDebug() << "这是元素:"<< str << ", 属性为" << attrStr;
}
else if(!QString::compare(str, "object"))
{
attribute = reader.attributes();
if(attribute.hasAttribute("name"))
{
attrStr.clear();
attrStr = attribute.value("name").toString();
}
qDebug() << "这是元素:" << str << ", 属性为" << attrStr;
}
else if(QString::compare(str, "x1") == 0)
{
qDebug() << attrStr << "对象的x1值为:" << reader.readElementText();
}
else if(QString::compare(str, "x2") == 0)
{
qDebug() << attrStr << "对象的x2值为:" << reader.readElementText();
}
else if(QString::compare(str, "y1") == 0)
{
qDebug() << attrStr << "对象的y1值为:" << reader.readElementText();
}
else if(QString::compare(str, "y2") == 0)
{
qDebug() << attrStr << "对象的y2值为:" << reader.readElementText();
}
else if(QString::compare(str, "linewidth") == 0)
{
qDebug() << attrStr << "对象的linewidth值为:" << reader.readElementText();
}
else if(QString::compare(str, "scale") == 0)
{
qDebug() << attrStr << "对象的scale值为:" << reader.readElementText();
}
else if(QString::compare(str, "rotate") == 0)
{
qDebug() << attrStr << "对象的rotate值为:" << reader.readElementText();
qDebug() << "----------------";
}
}
else if(token == QXmlStreamReader::Characters)
{
// qDebug() << reader.text().toString(); /* 会把换行符和制表符也给读出来 */
}
else if(token == QXmlStreamReader::Comment)
{
qDebug() << reader.text().toString(); /* xml注释 */
}
else if(token == QXmlStreamReader::Invalid)
{
qDebug() << "读取失败:" << reader.errorString();
}
}
}
打印输出结果如下:
"H:/robot_plus/tests/Xml/XML/bin/untitled1.xml"
这是根节点: "root"
----------------
"写入矩形图元的信息"
************************************************
这是元素: "class" , 属性为 "Rect"
这是元素: "object" , 属性为 "obj1"
"obj1" 对象的x1值为: "10"
"obj1" 对象的y1值为: "10"
"obj1" 对象的x2值为: "50"
"obj1" 对象的y1值为: "50"
"obj1" 对象的linewidth值为: "2"
"obj1" 对象的scale值为: "0"
"obj1" 对象的rotate值为: "0"
----------------
这是元素: "object" , 属性为 "obj2"
"obj2" 对象的x1值为: "20"
"obj2" 对象的y1值为: "30"
"obj2" 对象的x2值为: "50"
"obj2" 对象的y1值为: "60"
"obj2" 对象的linewidth值为: "2"
"obj2" 对象的scale值为: "0"
"obj2" 对象的rotate值为: "90"
----------------
"写入线图元的信息"
************************************************
这是元素: "class" , 属性为 "Line"
这是元素: "object" , 属性为 "obj1"
"obj1" 对象的x1值为: "10"
"obj1" 对象的y1值为: "10"
"obj1" 对象的x2值为: "50"
"obj1" 对象的y1值为: "50"
"obj1" 对象的linewidth值为: "2"
"obj1" 对象的scale值为: "0"
"obj1" 对象的rotate值为: "0"
----------------
这是元素: "object" , 属性为 "obj2"
"obj2" 对象的x1值为: "10"
"obj2" 对象的y1值为: "10"
"obj2" 对象的x2值为: "50"
"obj2" 对象的y1值为: "50"
"obj2" 对象的linewidth值为: "2"
"obj2" 对象的scale值为: "0"
"obj2" 对象的rotate值为: "0"
----------------
"写入椭圆图元信息"
************************************************
这是元素: "class" , 属性为 "Ellipse"
使用SAX方式进行读写XML文档更易上手,也更符合XML标准,不足之处在于仅支持迭代读写,如果你想要更改某个属性,只能重新开始写入。使用DOM方式进行解析则可以达到增删改查的操作。但是两者各有利弊。