Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсач СПО (Емельянова).doc
Скачиваний:
8
Добавлен:
01.04.2025
Размер:
211 Кб
Скачать
☆

1.2 Формат файла проверки

Во время загрузки файла конфигурации производится его проверка при помощи XML Schema. XML Schema загружается из файла schema.xsd. Она определяет тип данных, использующиеся в аттрибутах свойств и элементов, последовательность элементов и их количество, допустимые значения для перечислений.

Перечисление определяется следующим образом:

<xs:attribute name="name" use="required">

<xs:simpleType>

<xs:restriction base="xs:string">

<xs:enumeration value="Plain"/>

<xs:enumeration value="Line Comments"/>

<xs:enumeration value="Block Comments"/>

<xs:enumeration value="Strings"/>

<xs:enumeration value="Directives"/>

<xs:enumeration value="Types"/>

<xs:enumeration value="Keywords"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

Здесь аттрибут name определён как обязательный (use="required"), значение может быть только текстовым (base="xs:string") и может быть одним из значений аттрибута value элемента xs:enumeration.

Корневой элемент language должен содержать 3 дочерних элемента: style, keywords и types. На языке XML Schema это правило записывается так:

<xs:element name="language">

<xs:complexType>

<xs:sequence>

<xs:element ref="style"/>

<xs:element ref="keywords"/>

<xs:element ref="types"/>

</xs:sequence>

<xs:attribute name="name" use="required" type="xs:string" fixed="C++"/>

</xs:complexType>

</xs:element>

Элемент types может содержать 1 или более дочерних элементов type, значения которых должны быть строкового типа. Данное правило реализуется при помощи следующей конструкции:

<xs:element name="types">

<xs:complexType>

<xs:sequence>

<xs:element ref="type" minOccurs="1" maxOccurs="unbounded"/>

</xs:sequence>

</xs:complexType>

</xs:element>

<xs:element name="type" type="xs:string"/>

Элемент style содержит 7 дочерних элементов entry, содержащих данные сложного типа. Правило для данного утверждения выглядит следующим образом:

<xs:element name="style">

<xs:complexType>

<xs:sequence>

<xs:element ref="entry" minOccurs="7" maxOccurs="7"/>

</xs:sequence>

</xs:complexType>

</xs:element>

2. Разработка программы

2.1 Загрузка файла конфигурации

Для начала создадим 3 переменных типа xmlChar:

xmlChar *uri;//используется для хранения аттрибутов

xmlChar *color;//используется для хранения значения цвета

xmlChar *font;//используется для хранения значения шрифта

Загрузка данных из XML файла происходит в функции loadHighlightingData():

void loadHighlightingData()

{

xmlDocPtr doc1;

const char * filename = "config.xml";

doc1 = xmlReadFile(filename, NULL, XML_PARSE_NONET);

if(is_valid(doc1, "schema.xsd") == 1)

{

int i = 0;

xmlDocPtr xmldoc = NULL;

xmlChar *uri;

if((xmldoc = xmlReadFile(filename, NULL, 0)) == NULL) return;

xmlNodePtr cur = xmlDocGetRootElement(xmldoc);

parseXMLDoc(xmldoc, "style", "entry");

parseXMLDoc(xmldoc, "keywords", "keyword");

parseXMLDoc(xmldoc, "types", "type");

xmlFree(uri);

xmlFree(color);

xmlFree(font);

}else

{

//Ошибка в XML

xmlErrorPtr XMLError;

XMLError = xmlGetLastError();

fl_alert(XMLError->message);

}

}

Сначала мы создаём указатель на XML документ командой xmlDocPtr doc1;, присваиваем имя загружаемого файла переменной filename. Затем считываем файл и проверяем его при помощи XML Schema. Проверку осуществляет функция is_valid (const xmlDocPtr doc, const char *schema_filename), получающая в качестве аргументов указатель на XML документ и имя файла XML Schema. В данной функции сначала загружается файл схемы:

xmlDocPtr schema_doc = xmlReadFile(schema_filename, NULL, XML_PARSE_NONET);

if (schema_doc == NULL) {

fl_alert("The schema cannot be loaded or is not well-formed");

return -1;

}

В случае невозможности загрузить файл выводится соответствующее сообщение при помощи функции fl_alert();

Далее создаётся указательна контекст парсера схемы, и также выводится сообщение о ошибке при невозможности его создания:

xmlSchemaParserCtxtPtr parser_ctxt = xmlSchemaNewDocParserCtxt(schema_doc);

if (parser_ctxt == NULL) {

fl_alert("Unable to create a parser context for the schema", "Ok");

xmlFreeDoc(schema_doc);

return -2;

}

Затем сама схема проверяется на корректность и также выдаётся сообщение о ошибке при нахождении ошибок в схеме:

xmlSchemaPtr schema = xmlSchemaParse(parser_ctxt);

if (schema == NULL) {

fl_alert("the schema itself is not valid", "Ok");

xmlSchemaFreeParserCtxt(parser_ctxt);

xmlFreeDoc(schema_doc);

return -3;

}

После этого создаётся контекст проверки:

xmlSchemaValidCtxtPtr valid_ctxt = xmlSchemaNewValidCtxt(schema);

if (valid_ctxt == NULL) {

fl_alert("unable to create a validation context for the schema", "Ok");

xmlSchemaFree(schema);

xmlSchemaFreeParserCtxt(parser_ctxt);

xmlFreeDoc(schema_doc);

return -4;

}

И наконец, происходит проверка XML документа:

int is_valid = (xmlSchemaValidateDoc(valid_ctxt, doc) == 0);

xmlSchemaFreeValidCtxt(valid_ctxt);

xmlSchemaFree(schema);

xmlSchemaFreeParserCtxt(parser_ctxt);

xmlFreeDoc(schema_doc);

return is_valid ? 1 : 0;

В случае, если загружаемый XML документ имеет ошибки, то выполняется следующий код:

xmlErrorPtr XMLError;

XMLError = xmlGetLastError();

fl_alert(XMLError->message);

Здесь мы создаём указатель указатель на структуру XMLError, заносим в эту структуру сведения о последней ошибке, и затем выдаём сообщение о ошибке при помощи функции fl_allert();.

Если проверка XML файла прошла успешно, то выполняется следующий код:

xmlDocPtr xmldoc = NULL;

if((xmldoc = xmlReadFile(filename, NULL, 0)) == NULL) return;

xmlNodePtr cur = xmlDocGetRootElement(xmldoc);

parseXMLDoc(xmldoc, "style", "entry");

parseXMLDoc(xmldoc, "keywords", "keyword");

parseXMLDoc(xmldoc, "types", "type");

xmlFree(uri);

xmlFree(color);

xmlFree(font);

Здесь мы создаём указатель на XML документ, загружаем его из файла, получаем указатель на корневой элемент документа и заполняем таблицу стилей данными из XML документа при помощи функции parseXMLDoc(xmlDocPtr doc, char *nodeName, char *curNode). Эта функция вызывается 3 раза: для чтения данных подсветки, для получения списка ключевых слов и списка типов. Рассмотрим эту функцию подробнее:

void parseXMLDoc(xmlDocPtr doc, char *nodeName, char *curNode)

{

xmlNodePtr cur;

cur = xmlDocGetRootElement(doc);

cur = cur->xmlChildrenNode;

while (cur != NULL)

{

if ((!xmlStrcmp(cur->name, (const xmlChar *) nodeName)))

{

parseNodes(doc, cur, curNode);

}

cur = cur->next;

}

}

Сначала создаётся указатель на элемент документа и ему присвается значение корневого элемента. Затем устанавливается режим дочерних элементов и в цикле осуществляется поиск элемента, заданного вторым параметром функции. При его нахождении выполняется функция parseNodes(xmlDocPtr doc, xmlNodePtr cur, char *curNode), которая и производит загрузку значений в таблицы стилей, ключевых слов и типов. Данная функция реализована следующим образом:

void parseNodes(xmlDocPtr doc, xmlNodePtr cur, char *curNode)

{

xmlChar *key;

int exit(0);

cur = cur->xmlChildrenNode;

while(cur != NULL)

{

if((!xmlStrcmp(cur->name, (const xmlChar *) curNode)))

{

if((!xmlStrcmp(cur->name, (const xmlChar *) "entry")))

{

parseStyles(doc, cur, "Plain");

parseStyles(doc, cur, "Line Comments");

parseStyles(doc, cur, "Block Comments");

parseStyles(doc, cur, "Strings");

parseStyles(doc, cur, "Directives");

parseStyles(doc, cur, "Types");

parseStyles(doc, cur, "Keywords");

return;

}else

{

key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);

if(strcmp(curNode, "type") == 0)

{

code_types.push_back((const char *) key);

}else

{

code_keywords.push_back((const char *) key);

}

xmlFree(key);

}

}

cur = cur->next;

}

return;

}

Данная функция состоит из 2 частей: первая часть прдназначена для загрузки таблицы стилей, вторая для загрузки ключевых слов и типов. Загрузка стилей осуществляется функцией parseStyles(xmlDocPtr doc, xmlNodePtr cur, const char *name), в которой все 7 элементов описаны следующим образом:

if((!xmlStrcmp(uri, (const xmlChar *) "Plain")))

{

color = xmlGetProp(cur, (const xmlChar *)"color");

font = xmlGetProp(cur, (const xmlChar *)"font");

stylebuftemp.color = XMLValue2FLColor(color);

stylebuftemp.font = XMLValue2FLfont(font);

stylebuftemp.size = TS;

styletable[0] = stylebuftemp;

}

Функции XMLValue2FLfont(const xmlChar* XMLvalue) и XMLValue2FLColor(const xmlChar* XMLvalue) получают указатель на строку и проверяют, является ли она значением FLCOLOR или FLFONT следующим образом:

if((!xmlStrcmp(XMLvalue, (const xmlChar *)"FL_BLACK")))

{

return FL_BLACK;

}

или

if((!xmlStrcmp(XMLvalue, (const xmlChar *)"FL_COURIER")))

{

return FL_COURIER;

}

Если функция parseNodes получает указатель на элемент, содержащий значения ключевых слов, то они загружаются в массив следующим образом:

code_keywords.push_back((const char *) key). Таким же образом загружаются и типы: code_types.push_back((const char *) key).