Андрей Малкин где-то в 2001
Почти из жизни
Начальник – программисту: «Нужно данные из 1С импортировать, сделаешь?» Дальше возможны варианты.
- «Да какие проблемы-то? В чём там в 1С хранится, в dbf, что-ли? Да щас я её фоксом (ребусом, аксессом)» Час спустя: «А что такое SP2345?». Пауза.
- «Да какие проблемы-то? Да щас я DD-файл посмотрю, там все поля расписаны, а потом фоксом (ребусом, аксессом)». День спустя: «Не понял, вроде в справочнике пятнадцать реквизитов, а в де-бе-эфе всего 4 поля». Длительная пауза.
- «Да какие проблемы-то? Да щас я обработку напишу, да через Xbase данные выкину. А вы их что, в Сеть выкладываете? Так давайте я лучше вам web-server на V7 напишу. И экспортировать не надо!». Ступор.
Я слежу за публикациями в Интернете на тему импорта данных из V7 в другие системы более трёх лет и мне кажется, что исторически всё складывается примерно так, как описано выше. Сначала – безуспешные попытки взять данные «в лоб», затем – работа с 1cv7.dd, венцом которой был шлюз 1C-MSAccess Дмитрия Любимкова.
В 2000 году начинают появляться материалы по структуре MD-файла и кажется, что вот-вот появится инструмент/технология импорта – но нет: на cегодня существует масса решений, базирующихся на экспорте из V7 и практически нет законченных средств импорта из неё. Уточню, что под импортом я понимаю возможность доступа к данным V7, находясь не только вне этой системы, но и не имея на компьютере никаких её компонентов.
В этой публикации я не буду обосновывать необходимость (нужность, востребованность) подобного решения: будем считать, что мною движет исключительно стремление удовлетворить собственное любопытство. В качестве тестовых примеров будут использоваться комплексные конфигурации для версий 7.5 и 7.7.
Итак, постановка задачи: получить возможность доступа к данным V7, точнее к объектам хранения данных (справочникам, регистрам, перечислениям и т.д.). Решение (технология) должно поддерживать как версию 7.7, так и версию 7.5. Никакие компоненты V7 использоваться не должны: только *.dbf и 1cv7.md.
Исследуем MD
Те, кто читал жёлто-красные книжки, знают, что описания всех объектов системы хранятся в файле 1cv7.md. Сам он представляет собой так называемый Compound File – структуру, поддерживающую хранение разнородных данных в одном файле. Сначала, конечно, необходимо найти какое-то средство для ковыряния внутри него.
Самым известным инструментом для этой работы является FAR DocFile Browser Plugin by Igor Pavlov.
В последнее время появилось несколько новых инструментов, ориентированных не на абстрактный compound-file, а конкретно на 1cv7.md (compound.dll by Kostya Volkov, MD Editor by Павел Бычковяк, Visual MD Editor by Sergey Belov, и другие).
Мы будем использовать Compound Extractor by Denis Abrosimov. Тому, кто захочет узнать подробности об этой программе или пожелает заточить её под себя, необходимо обратиться к главе II, написанной Денисом (в ней меня особенно умиляют упоминания «поделок от Микрософт» ;-). Денис, кстати сказать, один из авторов описываемой технологии, видел софт от 1С только издали (ближе мы его не подпускаем, бережём ;-).
Внутри 1cv7.md нас будет интересовать исключительно файл Main Metadata Stream (далее просто MMS) из папки \Metadata. В зависимости от версии 1С, его кодировка либо OEM (для 7.5), либо ANSI (для 7.7).
Для извлечения MMS из MD-хранилища мы воспользуемся командой
compound_extr.exe 1cv7.md "\metadata\main metadata stream"
Compound Extractor создаст файл с аналогичным именем, который мы и будем анализировать в дальнейшем.
MMS изнутри
Даже поверхностный взгляд на MMS позволяет определить, что этот файл имеет регулярную структуру: группы символов в двойных кавычках (chr(34)), разделенные запятыми и ограниченные фигурными скобками (chr(123) и chr(125)). Подобные структуры часто встречаются в разных местах V7: файл выгрузки данных, файл синтакс-помощника, и практически всё, что записано в файле метаданных.
Что это: внутрифирменное описания объектной модели или какой-то стандарт – мне неведомо. Никаких материалов, реально описывающих структуру MMS, я не видел. Вполне возможно, что предложенный ниже доморощенный способ разбора MMS методически неверен, но результаты он даёт адекватные.
Для упрощения дальнейшего описания придётся ввести термин класс метаданных – это то, что в 1С называют «вид объекта метаданных» (понятия справочник, операция, табличная часть документа, и т.п.). Это иерархическая структура: все классы, кроме корневого (реально отсутствующего в MMS), имеют класс-родитель (например класс Документы – родитель для класса Табличная часть документа). Объект метаданных –просто экземпляр класса, определяемый набором свойств (реквизитов).
Естественно, что такая структура может быть легко представлена и обработана программой.
Теперь структуру MMS можно представить так:
- Простейший вариант: класс не имеет подклассов и не пуст (содержит как минимум один экземпляр – объект).
Как описано в MD |
Что это такое |
{"ClassName", |
строка с именем класса ("Const","Documents",…) |
{"IdObject_1","Prp_1",...,"Prp_n"},
{"IdObject_N","Prp_1",...,"Prp_n"}} |
Следующие строки – объекты (экземпляры) класса, представленные своими свойствами Prp_i (строки, заключенные в кавычки и разделенные запятыми). |
Пример: описание класса GenJrnlFldDef |
{"GenJrnlFldDef", |
Строка с именем класса |
{"1005","Фирма","Фирма","","B","0","0","13","0","0","1"}, … {"8137","Комментарий","Произвольный комментарий к документу","",". . . ","0"}}, |
Объекты класса |
- Другой вариант: пустой класс (не содержит ни одного экземпляра).
Как описано в MD |
Что это такое |
{"ClassName"}, |
строка с именем класса закрыта ограничителем '}'. |
Пример: пустой подкласс Params |
{"Params"}, |
|
- Третий вариант: класс имеет подклассы. (структура типа "Registers")
Как описано в MD |
Что это такое |
{"ClassName"}, |
строка с именем класса закрыта ограничителем '}'. |
{"IdObject_1","Prp_1",...,"Prp_n", |
первый объект (экземпляр)класса |
{"Sub_1_ClassName", |
имя подкласса 1 |
{"IdSub_1_Object_","Prp_1",...,"Prp_n"}, |
первый объект подкласса 1 |
…… |
|
{"IdSub_1_Object_N","Prp_1",...,"Prp_n"}}, |
последний объект подкласса 1 |
…… |
|
{"Sub_n_ClassName", |
имя последнего подкласса |
{"IdSub_n_Object_1","Prp_1",,...,"Prp_n"}, |
первый объект последнего подкласса |
…… |
|
{"IdSub_n_Object_N","Prp_1",...,"Prp_n"}}}, |
последний объект последнего подкласса – последний подкласс закрыт, первый объект класса описан полностью |
{"IdObject_2","Prp_1",...,"Prp_n", |
второй объект (экземпляр)класса |
Пример: описание объектов класса Registers |
{"Registers", |
Строка с именем класса Registers |
{"99","ОстаткиТоваров","","","0"," ","0","1", |
Объект "ОстаткиТоваров" класса Registers |
{"Props", |
Класс Registers, подкласс Props |
{"5858","Фирма","","","B","0","0","13","0","0","0","0"}, {"101","Товар","","","B","0","0","33","0","0","0","0"}, {"100","Склад","","","B","0","0","31","0","0","0","0"}}, |
Объекты подкласса Props |
{"Figures", |
Класс Registers, подкласс Figures |
{"102","ОстатокТовара","","","N","15","5","0","0","0"}}, |
Объект подкласса Figures |
{"Flds", |
Класс Registers, подкласс Flds |
{"1020","ФлагУчета",""," ","0","0"}}}, |
Объект подкласса Flds. Объект ОстаткиТоваров класса Registers описан полностью |
Предлагаемая интерпретация сильно упрощена. В MMS встречаются и фигурные скобки внутри строк-описателей объектов; структура ссылок Refers и форм Forms – более сложна. Но! Мне формы неинтересны, и я их без всяких угрызений совести исключаю из рассмотрения. Для целей описания объектов хранения предложенная структура минимально достаточна. Последуем совету Оккама и не будем множить сущности сверх необходимого ;-).
Объекты разных классов имеют различный набор свойств (реквизитов), но у всех первые четыре свойства одинаковы:
- идентификатор объекта (ID) – уникальный во всей конфигурации ключ объекта
- имя объекта (Sname)
- полное имя объекта или синоним (Lname)
- комментарий (Comment)
Теперь для построения таблиц-описателей объектов хранения нужно просканировать эту придуманную структуру классов/объектов и разобрать все объекты по свойствам. Естественно, что для этого необходимо знать имена нужных классов и наборы присущих им свойств. Об этом – в следующей части.
|