Comments.blogs

А как вы работаете с xml?

19 мар 2007 10:18
0
(Текст записи скрыт. Показать...)
Интересно, как сейчас в разных компаниях обстоит дело с работой с xml форматом? Используете или нет? Если да, то какие средства для чтения\записи? Какие именно фичи из xml используется?
Есть мнение, что мы изобретали в очередной раз свой велосипед – хотелось бы это обсудить и понять, так ли это .
Вкратце про эволюцию работы с xml у нас в Лесте читай в блоге...


Началась наша работа с xml с парсера TinyXml. Достаточно удобный и простой парсер. Его просто подключить, просто использовать. Его минусы проявляются только когда появляются огромные xml файлы или когда надо работать с частями этих файлов, хранить subNodes и т.п. – тут начинаются тормоза и проблемы с памятью. Также проблемой являлось то, что не было типизации – в любую ноду можно было записать все, что угодно и только в момент загрузки можно было сконвертировать в нужный тип из строки.
Вот кусок такого файла:

<IconName value="DE_PC1000"/>
<Icon value="TL/Icon/Ammo/DE_PC1000"/>
<ExploPower value="150"/>
<IsBomb value="true"/>

Дальнейшим шагом было написание товарищем Corvax (http://www.dtf.ru/person/info.php?id=1212) системы классов, имеющих у нас кодовое имя SMCC. Это фактически был набор классов, которые хранили в себе данные из xml и умели загружаться и сохраняться в него. Всё на умных указателях. Работать стало удобнее за счет того, что нам нужно было строго ограниченное число типов данных внутри xml (object, string, int, float, bool, wstring, data). Вот кусок такого файла:

<object name = "Second_Turret_155_Yamato">
<integer name = "Country" value = "2"/>
<string name = "Type" value = "Gun"/>
<boolean name = "Production" value = "false"/>
<float name = "Weight" value = "177"/>
</object>

Вот работа с ним:


for (CompoundObject::ConstIterator i = turrets->begin(),
iend = turrets->end();
i != iend;
++i
)
{
std::string name = i->first; // "Second_Turret_155_Yamato"
ObjectAttribute turret = i->second;

IntegerAttibute attrCountryId = turret->get("Country");
int attrCountryId = attrCountryId->getValue();

std::string turretType = turret->getAs<TypeId::String>("Gun")->getValue();

bool production = safeGetValue(turret, "Production", false);

Attribute attrWeight = turret->get("Weight");
double weight = As<TypeId::Float>(attrWeight)->getValue();
}


Этот файл уже имеет типизацию, которую можно проверять и выдавать Exception, если тип неправильный.
Минусом первого варианта системы SMCC было то, что она была надстройкой над TinyXml и вся загрузка и сохранение велась через нее.
Дальнейшей оптимизацией было создание своего парсера xml для нашего формата. Он легковесный и работает в несколько раз быстрее TinyXml.
Следующей мыслью было то, что у нас строго ограниченный набор типов в xml, а значит можно сделать и бинарный формат. Сделали. Получили прирост скорости парсинга xml еще в несколько раз. Например, файл сэйва занимал 50mb в xml, старый парсинг и сохранение могли занимать 10 и более секунд, а новый отрабатывает менее, чем за секунду.
Ну и недавно дошли руки до загрузки xml с помощью Loading inplace. Это вообще максимально быстрый алгоритм. Работает за счет того, что число типов ограничено.
Естественно, все форматы грузятся любым загрузчиком. Даже Loading inplace грузит обычный xml, правда медленно, т.к. сначала надо распарсить всю структуру.
Также пришлось написать утилиту, конвертирующую форматы xml в разные виды, чтобы можно было бинарные форматы конвертировать в текстовый для просмотра и редактирования, но т.к. большинство xml экспортятся из maya или базы данных, то делать это приходится нечасто.

В итоге сейчас мы имеем систему работы с xml, сочетающую в себе как плюсы бинарных файлов, так и удобство текстового xml формата.
А у вас есть такой велосипед?
Отправлено 19.03.2007 в 10:49
Отвечает на сообщение 186835
0
Alexey Baskakov wrote:
>
> boost::property_tree плюс своя небольшая
> надстройка, чтобы конвертить безконтурный граф
> полиморфных объектов в текстовое дерево и
> обратно.


А пример такого xml файла и кода для работы с ним можно?
Отправлено 19.03.2007 в 12:28
Отвечает на сообщение 186837
0
Oleg Fedorov wrote:
> А пример такого xml файла и кода для работы с ним
> можно?


Самый простой пример (без сохранения иерархии и relationship) - конфиг:

struct Config
{
enum Domain_e
{
 DOMAIN_ART = 0
, DOMAIN_GAME_DESIGN = 1
, DOMAIN_PROGRAMMING = 2
, DOMAIN_SOUND = 3
};

std::string m_sUser;
std::string m_sPassword;
Domain_e m_eDomain;

bool m_bFileSystemFlat;
boost::filesystem::path m_sMediaPath;

int m_iAutosavePeriod; // minutes
boost::filesystem::path m_sAutosavePath;

struct Layout_c : public serialization::Layout_c < Config >
{
Layout_c()
{
Simple ( "user", &Config::m_sUser, "" );
Simple ( "password", &Config::m_sPassword, "" );
Enum ( "domain", &Config::m_eDomain, DOMAIN_GAME_DESIGN )
.Enumerator( DOMAIN_ART, "art" )
.Enumerator( DOMAIN_GAME_DESIGN, "game_design" )
.Enumerator( DOMAIN_PROGRAMMING, "programming" )
.Enumerator( DOMAIN_SOUND, "sound" )
;
Simple ( "filesystem_flat", &Config::m_bFileSystemFlat, true );
Simple ( "media_path", &Config::m_sMediaPath, "" );
Simple ( "autosave_period", &Config::m_iAutosavePeriod, 10 );
Simple ( "autosave_path", &Config::m_sAutosavePath, "" );
}
};
};

<?xml version="1.0" encoding="windows-1251"?>
<SkyStudio>
<Configuration>
<user>loyso</user>
<domain>programming</domain>
<filesystem_flat>true</filesystem_flat>
<media_path>C:/Dev/Repositories/media</media_path>
<autosave_period>2</autosave_period>
<autosave_path>C:/autosave</autosave_path>
</Configuration>
</SkyStudio>

Сериализация иерархии полиморфных объектов, в данном случае - коллекция
полиморфных объектов:

class Primitive
{
};

class PrimFloat : public Primitive
{
};

struct PrimitiveSerializer : public serialization::SerializeAbstract_T < Primitive >
{
PrimitiveSerializer()
{
RegisterType < PrimFloat > ( "float" );
RegisterType < PrimInt > ( "int" );
RegisterType < PrimBool > ( "bool" );
RegisterType < PrimVec2 > ( "vec2" );
RegisterType < PrimVec3 > ( "vec3" );
RegisterType < PrimVec4 > ( "vec4" );
RegisterType < PrimTexRect > ( "texrect" );
RegisterType < PrimColor > ( "color" );
RegisterType < PrimString > ( "string" );
RegisterType < PrimFileName > ( "filename" );
RegisterType < PrimLink > ( "link" );
RegisterType < PrimEnum > ( "enum" );
}
};

class AttributeStruct
{
...
struct Layout : public serialization::Layout_c < AttributeStruct >
{
Layout()
{
ContainerPtr( "primitives", &AttributeStruct::m_Primitives, serialization::Serializer < PrimitiveSerializer > () );
}
}
...
typedef std::list < Primitive * > Primitives_t;
Primitives_t m_Primitives;
}

в xml:

...
<primitives>
<_ type="float">
<name>yaw</name>
<min>-3.1415</min>
<max>3.1415</max>
</_>
<_ type="bool">
<name>open</name>
<default>true<default>
</_>
</primitives>

В общем, если честно то сейчас я бы не стал все это на C++ писать. И даже на C# бы не стал. Сейчас я бы DSL забабахал для описания и создания диаграмм классов и объектов. И компонентных диаграмм. Не только с целью реализации сериализации разумеется.
Отправлено 20.03.2007 в 12:34
Отвечает на сообщение 186865
0
Alexey Baskakov wrote:
>
> Самый простой пример (без сохранения иерархии и
> relationship) - конфиг:
>


А вот интересно, сколько занимает парсинг 50мб файла таким парсером?
Насколько я понял из описания в Boost, этот парсер использует либо тот же TinyXml либо свой встроенный в Boost. Думаю медленный он.

> В общем, если честно то сейчас я бы не стал все
> это на C++ писать. И даже на C# бы не стал.
> Сейчас я бы DSL забабахал для описания и создания
> диаграмм классов и объектов. И компонентных
> диаграмм. Не только с целью реализации
> сериализации разумеется.


эээ. Можно подробнее? Это будет быстрее\удобнее? И в чем именно?
Отправлено 20.03.2007 в 13:19
Отвечает на сообщение 187076
0
Oleg Fedorov wrote:

> А вот интересно, сколько занимает парсинг 50мб
> файла таким парсером?
> Насколько я понял из описания в Boost, этот
> парсер использует либо тот же TinyXml либо свой
> встроенный в Boost. Думаю медленный он.

boost.ptree может использовать четыре разных xml парсера.
один из них (pugixml) - AFAIK самый быстрый из общедоступных. ну и плюс автор ptree сейчас пишет пятый, хочет pugixml обогнать.

на 50 мб файлах тормозит совсем не парсер, там уже тупо проблемы с памятью и чисто оверхеды SCL сказываются.

А откуда такие большие файлы? в интересах распараллеливания работ и versioning 1 файл должен представлять 1 unit работы одного человека (с целью минимизировать конфликты SVN/CVS например)

Плюс я не сторонник хранить проектные данные в xml (да и любом другом каноническом текстовом формате). Бинарные файлы со схемой данных (метаданными) в начале и прозрачной структурой - вот имхо то что надо. Ну и мерджилка своя для них. Разумеется все должно работать железно и стабильно.

> эээ. Можно подробнее? Это будет быстрее\удобнее?
> И в чем именно?

Ну вот эту прослойку (описание объектов и их структуры) можно будет не писать, так как она все равно уже есть на метауровне. А сгенерить по ней код, который будет заниматься сериализацией - проще простого. И никаких томрозов с компилянием навороченных C++ шаблонов.

Впрочем, у нас все равно приведенная работа с xml только в редакторе осталась.
Oleg Fedorov  20.03.2007 15:35
Alexey Baskakov  20.03.2007 15:53
Oleg Fedorov  20.03.2007 16:12
В ветке ещё 2 сообщения
Comments.blogs
Списки доступа
  • Подписчики [789]
Права доступа
У обсуждений в этой группе различные ограничения доступа.
Пользователи имеют персональные права доступа к обсуждениям.

Copyright © 2021 ООО "ДТФ.РУ". Все права защищены.

Воспроизведение материалов или их частей в любом виде и форме без письменного согласия запрещено.

Замечания и предложения отправляйте через форму обратной связи.

Пользовательское соглашение