XF - это лёгкий и переносимый текстовый формат обмена данными. Он лаконичен и гибок, что позволяет его использовать в файлах конфигурации ПО. XF полностью поддерживает стандарт Unicode что делает его пригодным для создания локализованных приложений.
Есть конфигурационный файл для нашей программы:
Conf {
Limits {
MaxMemory = 1024;
MaxUsers = 200;
MaxThreads = 100;
}
Info {
Title = "Sample Application 1.0";
WelcomeMessage = "You are welcome!!!";
}
Users {
Maxim {
Password = "passwd";
LastLogin = "25.05.2007";
}
Andrew {
Password = "mysecret";
LastLogin = "23.08.2007";
}
}
}
Раздел Limits содержит ограничения на размер памяти, число пользователей, потоков и т п. Раздел Users содержит список пользователей с паролями, и датой последнего входа.
Для начала попробуем считать файл конфигурации conf.xf. Для работы с XF будем использовать библиотеку XFLib (она работает в Windows и Linux, а также любой Unix-системе, поддерживающей GCC). Скачать XFLib можно здесь: http://xfhome.org/?page=soft
Для подключения библиотеки XFLib к проекту, необходимо включить её в проект (для Windows - подключить файл xflib.lib к проекту), и включить в проект заголовочные файл xf.h и xf_api.h (из каталога lib в папке с XFLib).
xfMap *conf;
int result;
conf = xfCreate();
if (conf) { printf("Недостаточно памяти для чтения конфигурации"); exit(1); }
result = xfReadFile(conf, "conf.xf");
if (result) {
printf("Ошибка чтения конфигурации: %S (строка %i колонка %i)\n",
xfError(conf),xfErrorLine(conf),xfErrorCol(conf));
exit(1);
}
Здесь мы инициализировали структуру conf типа xfMap (которая будет содержать разобранный документ XF), считали в неё файл "conf.xf". Как видно из примера, мы выводим сведения о возможной ошибке разбора (если конфигурационный файл не является корректным документом XF).
Далее нам надо проанализировать содержимое считанного документа. Каждый документ XF - это дерево элементов, и его анализ заключается в прохождении дерева или отдельных его участков. Элемент документа в XFLib имеет тип xfNode, а для указания на элемент используется указатель xfNode*. Указатель на корень дерева XF (это несуществующий на самом деле глобальный элемент без названия, из которого исходят глобальные элементы) находится в поле root структур xfMap.
Работа с элементом производится по его указателю. Имея указатель на элемент можно получить или изменить его название, класс, значение, удалить элемент или получить доступ к его потомкам. Попробуем получить значение некоторых элементов:
xfNode *c;
int MaxMemory, MaxUsers, MaxThreads;
xfChar *Title, *WelcomeMessage;
c = conf->root;
c = xfEnter(c, L"Conf");
c = xfEnter(c, L"Limits");
MaxMemory = xfDecToInt(xfGet(xfEnter(c, L"MaxMemory")));
MaxUsers = xfDecToInt(xfGet(xfEnter(c, L"MaxThreads")));
MaxThreads = xfDecToInt(xfGet(xfEnter(c, L"MaxUsers")));
c = conf->root;
c = xfEnter(c, L"Conf");
c = xfEnter(c, L"Info");
Title = xfDecToInt(xfGet(xfEnter(c, L"Title")));
WelcomeMessage = xfDecToInt(xfGet(xfEnter(c, L"WelcomeMessage")));
Обратите внимание, XFLib оперирует с Unicode-строоками, потому перед строками ставится символ L (как принято в языке Си для Unicode-строк). Кстати, вывод Unicode-сток в printf-подобных функциях производится спецификатором %S (а не %s).
В примере мы получили указатель на корень документа (conf->root), затем получили указатель на его потомка (xfEnter возвращает указатель на дочерний элемент по указателю на элемент-предок и имя дочернего элемента). Функция xfGet получает значение элемента по его указателю, xfDecToInt - специальные функции преобразования Unicode-строки в целое число.
Теперь у нас есть ещё одна задача: получить все элементы-потоки Users (они являются логинами пользователей нашей программы). Для получения первого потомка элемента есть функция xfChild():
c = xfEnter(xfEnter(c->root, L"Conf"), L"Users");
xfNode *p = xfChild(с);
Если возвращён нулевой указатель (XF_NULL), значит элемент не имеет потомков. Для получения брата элемента (следующего потомка общего родителя) есть функция xfNext(). Если возвращён нулевой указатель (XF_NULL), значит текущий элемент является последним потомком своего родителя.
Попробуем вывести список пользователей нашей программы (имя элемента получаем функцией xfName()):
c = xfEnter(xfEnter(c->root, L"Conf"), L"Users");
xfNode *p = xfChild(с);
while (p) {
printf("%S\n",xfName(c));
c = xfNext(c);
}
Как видите, не очень удобно углубляться в дерево документа при помощи функции xfEnter - за один её вызов можно углубиться лишь на один уровень - до потомка текущего элемента. В XFLib есть функция xfEnterPath(), которая позволяет углубиться в дерево сразу на несколько элементов:
xfNode *p = xfEnterPath(conf->root, L"Conf Users");
int size = xfGet(xfEnterPath(conf->root, L"Conf Limits MaxMemory"));
Как видно, формат XF можно использовать для хранения конфигурации приложений. Он достаточно гибок для хранения любых структур данных, и при этом просто читается и легко обрабатывается.
Любые вопросы по XF и XFLib можете направлять на электронную почту max@xfhome.org (Волков Максим).