Работа с SAX
Оглавление
Ввиду большого расхода памяти, работа с моделью DOM не всегда желательна или возможна. Существует принципиально другой способ для анализа XML-документов — это SAX.
SAX (Simple API for XML, простой API для XML) является стандартом JavaAPI для считывания XML-документов. SAX применяется для последовательного считывания XML-данных, что позволяет без проблем работать с очень большими файлами.
Чтение XML-документа
Класс QXmlSimpleReader представляет собой XML-анализатор, базирующийся на SAX. Он читает XML-документ блоками и сообщает о том, что было найдено, с помощью соответствующих методов.
{рисунок}
В этом и состоит его основное преимущество: в память помещаются только фрагменты, а не весь XML-документ. Но это и недостаток, так как информация не считывается вся сразу и невозможно получить иерархию XML-документа. Класс QXmlContentHandler должен использоваться для соединения с объектом класса QXmlSimpleReader. Другие классы, такие как QXmlEntityResolver, QXmlDTDHandler, QXmlErrorHandler, QXmlDeclHandler и QXmlLexicalHandler, просто содержат определения виртуальных методов, соответствующих различным событиям анализа XML-документа.
В большинстве случаев, для считывания XML-документа можно прекрасно обойтись двумя классами: QXmlContentHandier и QXmlErrorHandler. Интерфейс класса QContentHandler содержит методы, связанные с отслеживанием структуры документа, вызов которых происходит в следующем порядке:
- метод startDocument() вызывается при начале чтения XML-документа;
- метод startElement() вызывается при начале чтения элемента;
- метод characters () вызывается при чтении данных элемента;
- метод endElement() вызывается при завершении обработки элемента;
- метод endDocument() вызывается при завершении обработки документа.
Для удобства существует класс QXmlDefaultHandler, который унаследован от всех шести классов. Он содержит пустые реализации виртуальных методов этих классов. Для чтения XML-документа нужно унаследовать его и перезаписать следующие методы: startDocument(), startElement(), characters(), endElement(), endDocument() и fatalError(). Определение последнего метода унаследовано от класса QXmlErrorHandler. Если эти методы возвращают значение true, то это говорит объекту класса QXmlSimpleReader о том, что он должен продолжить анализ файла. Значение false говорит об ошибке, а чтобы отобразить соответствующее сообщение о ней — необходимо перезаписать метод errorString().
Программа, приведенная в листингах, производит чтение XML-документа.
int main()
{
AddressBookParser handler;
QFile file("addressbook.xml");
QXmlInputSource source(&file);
QXmlSimpleReader reader;
reader.setContentHandler(&handler);
reader.parse(source);
return 0;
}
В основной программе создаются объекты классов AddressBookParser, QFile (для чтения файла) и QXmlSimpleReader (для анализа файла). Чтобы поместить XML-документ в SAX-анализатор, нужно создать объект класса QXmlInputSource, передав ему указатель на QIODevice. Созданный объект нужно передать в метод parse() объекта класса QXmlSimpleReader. Этот метод запустит процесс анализа XML-документа. До его вызова необходимо установить в методе setContenHandler() объект класса AddressBookparser, который производит отображение XML-документа.
class AddressBookParser : public QXmlDefaultHandler {
private:
QString m_strText;
public:
bool startElement(const QString&,
const QString&,
const QString&,
const QXmlAttributes& attrs
)
{
for(int i = 0; i < attrs.count(); i++) {
if(attrs.localName(i) == "number") {
qDebug() << "Attr:" << attrs.value(i);
}
}
return true;
}
bool characters(const QString& strText)
{
m_strText = strText;
return true;
}
bool endElement(const QString&, const QString&, const QString& str)
{
if (str != "contact" && str != "addressbook") {
qDebug() << "TagName:" << str
<< "\tText:" << m_strText;
}
return true;
}
bool fatalError(const QXmlParseException& exception)
{
qDebug() << "Line:" << exception.lineNumber()
<< ", Column:" << exception.columnNumber()
<< ", Message:" << exception.message();
return false;
}
};
Класс AddressBookParser реализует виртуальные методы, которые вызываются при прохождении по XML-документу. При нахождении тегов вызываются соответствующие методы startElement() и endElement(), которые должны быть перезаписаны для того, чтобы реагировать надлежащим образом. Метод startElement() вызывается тогда, когда при считывании встречается открытие тега. Третий параметр, передаваемый в этот метод, — это имя тега. Четвертый — это список атрибутов. В нашем случае, если название атрибута совпадает со строкой number, то производится вывод его значения. Метод characters() производит запись содержимого текущего элемента в переменную m_strText, а это необходимо для того, чтобы можно было получить доступ к этому содержимому из любого метода класса AddressBookParser. Метод endElement() вызывается всегда, когда при чтении встречается закрытие тега. Третий параметр, передаваемый в этот метод,— имя тега. В случае несовпадения его со строками contact и addressbook, производится отображение данных элемента. Метод fatalError() вызывается в том случае, если не удается проанализировать XML-документ. В этом случае метод производит отображение предупреждающего сообщения с указанием номера строки и столбца XML-документа, в котором произошел сбой и текст ошибки анализатора.
Qt предоставляет два способа работы с XML-документам и — DOM и SAX. Первый представляет данные XML-документа в виде иерархии (древовидной структуры), что очень удобно для работы. Второй способ считывает данные из XML-документа блоками и сообщает о результатах в определенные виртуальные методы.
При выборе следует учитывать, что SAX — это низкоуровневый способ и поэтому более быстрый. Его лучше всего применять в тех случаях, когда не требуется проведение очень сложных операций. Также следует применять его для считывания больших XML-документов, так как он более экономно расходует ресурсы памяти.
Читать далее: Динамические библиотеки и система расширений