#(62):保存 XML
前面幾章我們討論了讀取 XML 文檔的三種方法。雖然各有千秋,但是 Qt 推薦的是使用`QXmlStreamReader`。與此同時,許多應用程序不僅需要讀取 XML,還需要寫入 XML。為此,Qt 同樣提供了三種方法:
1. 使用`QXmlStreamWriter`;
2. 構造一個 DOM 樹,然后掉其`save()`函數;
3. 使用`QString`手動生成 XML。
可以看出,無論我們使用哪種讀取方式,這幾種寫入的方法都與此無關。這是因為 W3C 僅僅定義了如何處理 XML 文檔,并沒有給出如何生成 XML 文檔的標準方法(盡管當我們使用 DOM 方式讀取的時候,依舊可以使用同樣的 DOM 樹寫入)。
如同 Qt 所推薦的,我們也推薦使用`QXmlStreamWriter`生成 XML 文檔。這個類幫助我們做了很多工作,比如特殊字符的轉義。接下來我們使用`QXmlStreamWriter`將前面幾章使用的 XML 文檔生成出來:
~~~
QFile file("bookindex.xml");
if (!file.open(QFile::WriteOnly | QFile::Text)) {
qDebug() << "Error: Cannot write file: "
<< qPrintable(file.errorString());
return false;
}
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("bookindex");
xmlWriter.writeStartElement("entry");
xmlWriter.writeAttribute("term", "sidebearings");
xmlWriter.writeTextElement("page", "10");
xmlWriter.writeTextElement("page", "34-35");
xmlWriter.writeTextElement("page", "307-308");
xmlWriter.writeEndElement();
xmlWriter.writeStartElement("entry");
xmlWriter.writeAttribute("term", "subtraction");
xmlWriter.writeStartElement("entry");
xmlWriter.writeAttribute("term", "of pictures");
xmlWriter.writeTextElement("page", "115");
xmlWriter.writeTextElement("page", "224");
xmlWriter.writeEndElement();
xmlWriter.writeStartElement("entry");
xmlWriter.writeAttribute("term", "of vectors");
xmlWriter.writeTextElement("page", "9");
xmlWriter.writeEndElement();
xmlWriter.writeEndElement();
xmlWriter.writeEndDocument();
file.close();
if (file.error()) {
qDebug() << "Error: Cannot write file: "
<< qPrintable(file.errorString());
return false;
}
// ...
~~~
首先,我們以只寫方式創建一個文件。然后基于該文件我們創建了`QXmlStreamWriter`對象。`setAutoFormatting()`函數告訴`QXmlStreamWriter`要有格式輸出,也就是會有標簽的縮進。我們也可以使用`QXmlStreamWriter::setAutoFormattingIndent()`設置每個縮進所需要的空格數。接下來是一系列以 write 開始的函數。這些函數就是真正輸出時需要用到的。注意這些函數以 write 開始,有 Start 和 End 兩個對應的名字。正如其名字暗示那樣,一個用于寫入開始標簽,一個用于寫入結束標簽。`writeStartDocument()`開始進行 XML 文檔的輸出。這個函數會寫下
~~~
<?xml version="1.0" encoding="UTF-8"?>
~~~
一行。與`writeStartDocument()`相對應的是最后的`writeEndDocument()`,告訴`QXmlStreamWriter`,這個 XML 文檔已經寫完。下面我們拿出一段典型的代碼:
~~~
xmlWriter.writeStartElement("entry");
xmlWriter.writeAttribute("term", "of vectors");
xmlWriter.writeTextElement("page", "9");
xmlWriter.writeEndElement();
~~~
顯然,這里我們首先寫下一個 entry 的開始標簽,然后給這個標簽一個屬性 term,屬性值是 of vectors。`writeTextElement()`函數則會輸出一個僅包含文本內容的標簽。最后寫入這個標簽的關閉標簽。這段代碼的輸出結果就是:
~~~
<entry term="of vectors">
<page>9</page>
</entry>
~~~
其余部分與此類似,這里不再贅述。這樣,我們就輸出了一個與前面章節所使用的相同的 XML 文檔:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<bookindex>
<entry term="sidebearings">
<page>10</page>
<page>34-35</page>
<page>307-308</page>
</entry>
<entry term="subtraction">
<entry term="of pictures">
<page>115
<page>224
</entry>
<entry term="of vectors">
<page>9</page>
</entry>
</entry>
</bookindex>
~~~
盡管我們推薦使用`QXmlStreamWriter`生成 XML 文檔,但是如果現在已經有了 DOM 樹,顯然直接調用`QDomDocument::save()`函數更為方便。在某些情況下,我們需要手動生成 XML 文檔,比如通過`QTextStream`:
~~~
//!!! Qt4
QTextStream out(&file);
out.setCodec("UTF-8");
out << "<doc>\n"
<< " <quote>" << Qt::escape(quoteText) << "</quote>\n"
<< " <translation>" << Qt::escape(translationText)
<< "</translation>\n"
<< "</doc>\n";
//!!! Qt5
QTextStream out(&file);
out.setCodec("UTF-8");
out << "<doc>\n"
<< " <quote>" << quoteText.toHtmlEscaped() << "</quote>\n"
<< " <translation>" << translationText.toHtmlEscaped()
<< "</translation>\n"
<< "</doc>\n";
~~~
這種辦法是最原始的辦法:我們直接除了字符串,把字符串拼接成 XML 文檔。需要注意的是,quoteText 和 translationText 都需要轉義,這是 XML 規范里面要求的,需要將文本中的 以及 & 進行轉義。不過,轉義函數在 Qt4 中是`Qt::escape()`,而 Qt5 中則是`QString::toHtmlEscaped()`,需要按需使用。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)