XML - статьи

Реализация классов


Для наглядности в данном подразделе текст модуля cbr_ed201.cpp разделен на части, с комментариями перед каждой его частью.

В конструкторе узлового класса CEDRefID задаются пространство имен nodeNamespace и его префикс nodePrefix. Это не обязательно. Можно опустить либо оба присвоения (тогда действует ранее объявленное или пространство имен по-умолчанию), либо опустить префикс. Если не задавать префикс, тогда он будет формироваться в соответствии с областью действия пространства имен в форме «n1», «n2» и т.д.: // cbr_ed201.cpp

#include "cbr_ed201.h" #include <QXmlAttributes> #include <QXmlStreamWriter> //----------------------------------------------------------------------

// EDRefID CEDRefID::CEDRefID(){ // пространство имен nodeNamespace = "urn:cbr-ru:ed:v2.0"; nodePrefix = "ed"; }

Так выполняется присвоение реквизитов объекта, являющихся аналогом атрибутов XML-документа (для текстовых элементов будет показано ниже): // инициализация реквизитов документа при чтении ЭД void CEDRefID::setRequisites(const QString &,const QXmlAttributes &attributes){ EDNo=attributes.value("EDNo"); EDDate=attributes.value("EDDate"); EDAuthor=attributes.value("EDAuthor"); }

Поскольку EDRefID является элементом исходного документа (узлом), для него определен метод writeNode(), начинающийся с записи открывающего тега writeStartElement() и заканчивающийся записью закрывающего тега writeEndElement(): bool CEDRefID::writeNode(QXmlStreamWriter& writer,const QString& nsUri){ writer.writeStartElement(nsUri,nodeName); writer.writeAttribute("EDNo", EDNo); writer.writeAttribute("EDDate", EDDate); writer.writeAttribute("EDAuthor", EDAuthor); writer.writeEndElement(); return true; }

Для узловых классов задаем имя nodeName, совпадающее с именем открывающего тега элемента исходного документа. Для вложенных элементов надо придерживаться правила – если элементы одинакового типа встречаются в документах с разными именами, то nodeName задается в конструкторе класса-владельца, если везде имена одинаковые – то в своем конструкторе. Однако, чтобы избежать ошибок, предпочтителен первый способ: // ED201 CED201::CED201(){ nodeName="ED201"; EDRefID.nodeName="EDRefID"; }


В методе setRequisites() приведен пример инициализации текстового реквизита Annotation, об этой особенности уже упоминалось выше. Если опустить первое условие, то после инициализации текстового реквизита произойдет очистка остальных реквизитов, т.к. аргумент attributes их не содержит.

Инициализацию реквизитов класса-родителя CEDRefID можно выполнить либо явным образом, как и остальные реквизиты (что может привести к проблемам при изменении формата документа), либо вызовом метода с явным разыменованием (предпочтительно): // инициализация реквизитов документа при чтении ЭД void CED201::setRequisites(const QString &name,const QXmlAttributes &attributes){ if(name=="Annotation") Annotation=attributes.value(name); else{ // инициализация реквизитов базового класса CEDRefID::setRequisites(name,attributes);

CtrlCode=attributes.value("CtrlCode"); CtrlTime=attributes.value("CtrlTime"); } }

Этот метод должен быть определен в двух случаях – если класс содержит вложенные объекты (в нашем случае – EDRefID), либо если в классе есть реквизиты, являющиеся аналогом текстовых элементов (Annotation): CNode* CED201::getNode(const QString &name){ if(name==nodeName name=="Annotation") return this; else if(name=="EDRefID") return &EDRefID; else return 0; }

Для класса, содержащего реквизиты – аналог текстовых элементов, нужно определить этот метод: bool CED201::isTextElement(const QString &name){ return (name=="Annotation"); }

В данном примере есть небольшая особенность. Реквизиты EDNo, EDDate, EDAuthor наследуются от класса СEDRefID, но использовать метод СEDRefID::writeNode() мы не можем, т.к. в этом случае сформируются открывающий и закрывающий теги элемента. Поэтому запись этих реквизитов выполняется так, как если бы они были объявлены в CED201: bool CED201::writeNode(QXmlStreamWriter& writer,const QString& nsUri){ writer.writeStartElement(nsUri,nodeName); writer.writeAttribute("EDNo", EDNo); writer.writeAttribute("EDDate", EDDate); writer.writeAttribute("EDAuthor", EDAuthor); writer.writeAttribute("CtrlCode", CtrlCode); writer.writeAttribute("CtrlTime", CtrlTime); writer.writeTextElement(nsUri,"Annotation", Annotation); EDRefID.writeNode(writer,nsUri); writer.writeEndElement(); return true; }

В заключение несколько слов о записи необязательных реквизитов. Если какой-либо атрибут может отсутствовать в XML-документе, то его запись нужно выполнять, используя альтернативные методы интерфейсного класса CNode::writeAttribute(),CNode::writeTextElement(). Например, запись writer.writeAttribute("EDNo", EDNo);

надо заменить на следующую: writeAttribute(writer, "EDNo", EDNo);


Содержание раздела