После инициализации нами элемента QTreeWidgetItem мы выполняем цикл по дочерним узлам элемента QDomElement, который соответствует текущему тегу <entry>.
Если элементом является <entry>, мы вызываем функцию parseEntry(), передавая текущий элемент в качестве второго аргумента. Затем будет создан новый элемент QTreeWidgetItem, в качестве родительского элемента которого выступает внешний элемент QTreeWidgetItem.
Если элементом является <page>, мы просматриваем список дочерних элементов для поиска узла Text. После его обнаружения мы вызываем функцию toText() для преобразования его в объект типа QDomText и функцию data() для получения текста в виде строки типа QString. Затем мы добавляем текст в разделяемый запятыми список номеров страниц в столбце 1 элемента QTreeWidgetItem.
Давайте теперь посмотрим, как мы можем использовать класс DomParser для синтаксического анализа файла:
01 void parseFile(const QString &fileName)
02 {
03 QStringList labels;
04 labels << QObject::tr("Terms") << QObject::tr("Pages");
05 QTreeWidget *treeWidget = new QTreeWidget;
06 treeWidget->setHeaderLabels(labels);
07 treeWidget->setWindowTitle(QObject::tr("DOM Parser"));
08 treeWidget->show();
09 QFile file(fileName);
10 DomParser(&file, treeWidget);
11 }
Мы начинаем с настройки QTreeWidget. Затем мы создаем объекты QFile и DomParser. При выполнении конструктора DomParser осуществляется синтаксический анализ файла и пополняется виджет дерева.
Как и в предыдущем примере, для сборки приложения с библиотекой QtXml в файл .pro необходимо добавить следующую строку:
QT += xml
Как показывает наш пример, проход по дереву DOM может быть достаточно непростым делом. Простая операция по извлечению текста между тегами <page> и </page> требует обработки в цикле элементов списка при помощи функций firstChild() и nextSibling() класса QDomNode. Программисты, которым очень часто приходится использовать интерфейс DOM, создают свои собственные высокоуровневые функции—оболочки для упрощения выполнения таких наиболее распространенных операций, как извлечение текста между открывающими и закрывающими тегами.
Запись документов XML
Существует два основных подхода к формированию файлов XML в приложениях Qt:
• мы можем построить дерево DOM и вызвать для него функцию save();
• мы можем сформировать файл XML вручную.
Выбор между этими подходами часто не зависит от типа используемого нами интерфейса для чтения документов XML: SAX или DOM.
Ниже приводится фрагмент программного кода, который иллюстрирует способ создания дерева DOM и его записи при помощи QTextStream:
const int Indent = 4;
QDomDocument doc;
QDomElement root = doc.createElement("doc");
QDomElement quote = doc.createElement("quote");
QDomElement translation = doc.createElement("translation");
QDomText latin = doc.createTextNode("Ars longa vita brevis");
QDomText english = doc.createTextNode("Art is long, life is short");
doc.appendChild(root);
root.appendChild(quote);
root.appendChild(translation);
quote.appendChild(latin);
translation.appendChild(english);
QTextStream out(&file);
doc.save(out, Indent);
Второй аргумент функции save() задает размер отступа. При ненулевом его значении читаемость сформированного файла будет лучше. Ниже приводится полученный на выходе файл XML:
<doc>
....<quote>Ars longa vita brevis</quote>
....<translation>Art is long, life is short</translation>
</doc>
Порядок действий будет другим, если в приложении дерево DOM используется в качестве главной структуры данных. В таких случаях приложения обычно считывают документы XML, применяя интерфейс DOM, затем модифицируют в памяти дерево DOM и, наконец, вызывают функцию save() для обратного преобразования дерева в документ XML.
По умолчанию функция QDomDocument::save() использует для генерации файла кодировку UTF-8. Мы можем применить другую кодировку, если добавить XML—объявление, например такое, как
<?xml version="1.0" encoding="ISO-8859-1"?>
в начало дерева DOM. Следующий фрагмент программного кода показывает, как это делать:
QTextStream out(&file);
QDomNode xmlNode = doc.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"ISO-8859-1\"");