← Февраль 2006 → | ||||||
1
|
2
|
3
|
4
|
5
|
||
---|---|---|---|---|---|---|
6
|
7
|
9
|
10
|
11
|
12
|
|
13
|
14
|
16
|
17
|
18
|
19
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
27
|
28
|
За последние 60 дней ни разу не выходила
Открыта:
26-03-2002
Статистика
0 за неделю
Волшебство программирования на 1С:Предприятие 7.7 и 8.0. Выпуск 98
Уважаемые программисты !
Компания "1-й Архитектор бизнеса" - одна из самых динамичных команд в 1С-бизнесе - дает вам шанс влиться в наши ряды. Работа по реализации проектов на платформе 1С Предприятие 7.7. и 8.0.
Наши правила:
∙ Профессиональный подход к делу
∙ Человечное отношение друг к другу
∙ Стремление к общему будущему
Что вас ожидает?
∙ Постоянно растущий объем интересной работы
∙ Непрерывное обучение и профессиональный рост
∙ Прогрессирующий заработок
Мы поможем:
∙ с жильем,
∙ оплатой метро,
∙ корпоративным мобильным
Если Вы:
∙ знаете типовые конфигурации на платформе 7.7 и 8.0.
∙ имеете опыт программирования в среде 1С
∙ и являетесь обладателем сертификатов 1С.
Звоните: 8 (495) 937-66-35
Резюме присылайте по электронной почте: padev@1ab.ru
Наш сайт: http://1ab.ru/
Волшебство
программирования на 1С:Предприятие 7.7 и 8.0
Выпуск 98 / 15.02.2006
Чтение и запись текстовых файлов XML средствами 1С:Предприятие 7.7
В этой статье приведены примеры последовательного (не нагружающего память) чтения и записи текстовых файлов в формате XML средствами встроенного языка (без внешних компонент).
Автор статьи: romix (Роман Чертанов)
URL: http://kb.mista.ru/article.php?id=73
Почему не 8.0? Потому что в 8.0 похожий XML-парсер уже есть. Вы
найдете почти полное сходство между этим последовательным парсером
XML (видимо, заимствованным из .NET, класс XmlTextReader и XmlTextWriter)
и приведенными ниже библиотечными функциями (вы можете вынести их,
например, в глобальный модуль, снабдив ключевым словом Экспорт,
а можете этого не делать).
Почему я избегаю использовать штатные средства 1С 7.7? Потому что
они потребляют память примерно 10-кратно по сравнению с объемом
исходного файла XML. Это значит, что по мере роста файла XML будут
расти "тормоза", вплоть до момента, когда память не будет исчерпана
полностью (либо приведет к ситуации, когда загрузка уйдет "в своп").
Модель DOM (которую применяет 1С:Предприятие 7.7) расчитана на обработку
небольших документов XML, которые должны располагаться в памяти
целиком.
Конечно, внешней компонентой делать то же самое намного аккуратнее,
и соблюдается принцип объектной ориентированности. Пример компоненты,
сделанной средствами .NET приведен в этой статье:
Написание
внешних компонент для 1С на VB.NET и C# (статья)
Однако, если внешние компоненты по каким-то причинам неприменимы
(постоянно сталкиваюсь со страхом перед внешними компонентами, который
я назвал бы "компонентофобия"), то примерно то же самое делает и
приведенный ниже программный код на языке 1С.
Кроме того, модель DOM намного сложнее (по сравнению, например,
с файлами DBF) - поэтому приходится сталкиваться еще и с XML-фобией:
для обмена применяют все, что угодно, но не XML. Но это удобный,
консервативный - происходит от древнего языка разметки SGML - и
простой по своей сути формат (намного удобнее и приятнее DBF) -
"тормоза" и непрактичность (в случае потоковой выгрузки) ему придает
именно модель DOM. Всякому инструменту - свое применение, и вряд
ли стоит применять объектную модель там, где подойдет простое последовательное
чтение или запись текстового файла.
Имена функций я сделал такие же, как в 1С:Предприятие 8.0. Я предполагаю,
что мало кто страдает "восьмеркофобией", и сможет понять способ
парсинга (разбора) текстовых файлов XML (на примере справочника
товаров). Тем более, что парсер занимает меньше строк кода, чем
можно было бы предположить: фактически, он предельно прост.
//Ограничения на входящие файлы XML: //1) В первой строке обязателен заголовок XML вида <?xml version="1.0" encoding="windows-1251"?> //2) Каждый тег должен быть записан в отдельной строке. Возможны отступы от начала строки и пустые строки. //3) Значения атрибутов - строго в двойных кавычках. //4) Не поддерживаются текстовые значения (любые значения можно передавать только через атрибуты). //5) Комментарии и "подобные им" элементы XML не поддерживаются. перем xml_fso; перем xml_file; перем xml_ИмяТега; перем xml_СписокАтрибутов; перем xml_сз; /////////////////////////////////////////////////////////////////////// //Открывает XML-файл в режиме "только чтение" Процедура xml_ОткрытьФайл(прм_ИмяФайла) //прм_ИмяФайла - имя файла XML (укажите полный путь и расширение .XML). xml_fso=СоздатьОбъект("Scripting.FileSystemObject"); xml_file=xml_fso.OpenTextFile(прм_ИмяФайла, 1, 0, 0); //Открываем файл в режиме "только чтение" стр=xml_file.ReadLine(); //Читаем заголовок XML вида <?xml version="1.0" encoding="windows-1251"?> Если Найти(стр,"<?xml")=0 Тогда Сообщить("Неправильный файл XML "+прм_ИмяФайла,"!"); а=10/0; КонецЕсли; Если Найти(стр,"windows-1251")=0 Тогда Сообщить("Требуется кодировка windows-1251 файла XML "+прм_ИмяФайла,"!"); а=10/0; КонецЕсли; xml_СписокАтрибутов=СоздатьОбъект("СписокЗначений"); xml_сз=СоздатьОбъект("СписокЗначений"); КонецПроцедуры // xml_ОткрытьФайл /////////////////////////////////////////////////////////////////////// //Считывает следующий тег XML. //Возвращает 1, если тег прочитан и 0 - если был достигнут конец файла. //Заполняет переменную xml_ИмяТега именем считанного тега в формате "<ИмяТега>" Функция xml_Прочитать(прм_ОжидаемыеТеги="") //Если вы используете параметр прм_ОжидаемыеТеги, то заполните его списком тегов //через запятую, которые могут быть считаны в данный момент (это позволяет проверять //структуру файла XML и сделать более ясным считывающий код). xml_СписокАтрибутов.УдалитьВсе(); стр=""; Пока стр="" Цикл Если xml_file.AtEndOfStream=1 Тогда Возврат 0; //тег не был прочитан, т.к. достигнут конец файла КонецЕсли; стр=СокрЛП(xml_file.ReadLine()); КонецЦикла; //цикл, чтобы пропустить пустые строки Если Найти(стр,"=")=0 Тогда //Случай, когда нет атрибутов xml_ИмяТега=СокрЛП(стр); Иначе //Разбиваем тег на структуру, удобную для ИзСтрокиСРазделителями() стр=СтрЗаменить(стр,"""",""","""); стр=""""+стр+""""; сз=xml_сз; сз.УдалитьВсе(); сз.ИзСтрокиСРазделителями(стр); //В первом элементе списка у нас и имя тега, и имя первого атрибута. Разделим их. зн=сз.ПолучитьЗначение(1); поз=Найти(зн , " "); xml_ИмяТега =СокрЛП(Лев(зн, поз)); //Выделим имя тега xml_ИмяТега =xml_ИмяТега+">"; //Выделим и обновим имя первого атрибута зн =СокрЛП(Сред(зн, поз)); сз.УстановитьЗначение(1,зн); //Удаляем завершающий элемент списка /> или > сз.УдалитьЗначение(сз.РазмерСписка()); //Переводим наш список значений в более удобный формат i=1; //позиция в списке сз рс=сз.РазмерСписка(); Пока i<=рс Цикл имя=сз.ПолучитьЗначение(i); имя=СокрЛП(СтрЗаменить(имя,"=","")); зн=сз.ПолучитьЗначение(i+1); //Заменяем спецсимволы XML зн=СтрЗаменить(зн,""",""""); зн=СтрЗаменить(зн,"'","'"); зн=СтрЗаменить(зн,"",""); зн=СтрЗаменить(зн,">",">"); зн=СтрЗаменить(зн,"&","&"); xml_СписокАтрибутов.ДобавитьЗначение(зн,имя); i=i+2; КонецЦикла; КонецЕсли; Если ПустаяСтрока(прм_ОжидаемыеТеги)=0 Тогда //Проверяем наличие имени тега в списке ожидаемых тегов (если надо контролировать структуру) Если Найти(прм_ОжидаемыеТеги,xml_ИмяТега)=0 Тогда Сообщить("Неожиданный тег "+xml_ИмяТега+" в строке "+xml_file.line); a=10/0; КонецЕсли; КонецЕсли; Возврат 1; //успешное чтение тега КонецФункции // xml_Прочитать /////////////////////////////////////////////////////////////////////// //Получает значение атрибута считанного тега по имени атрибута. //Если надо получить атрибут по его номеру, читайте список значений xml_СписокАтрибутов Функция xml_ПолучитьАтрибут(прм_ИмяАтрибута) Возврат xml_СписокАтрибутов.Получить(прм_ИмяАтрибута); КонецФункции // xml_ПолучитьАтрибут /////////////////////////////////////////////////////////////////////// //Закрывает открытый файл XML. По завершении работы с файлом его необходимо закрыть. Функция xml_Закрыть() xml_file.Close(); КонецФункции // xml_Закрыть //******************************************* //Тестовая процедура, которая считывает XML файл в справочник Товаров. Процедура Выполнить() стрИмяФайла=КаталогИБ()+"XML\tovar.xml"; спр=СоздатьОбъект("Справочник.Товары"); НачатьТранзакцию(); //Для ускорения сч=0; //Для ускорения Сообщить("Начало чтения XML: "+ТекущееВремя()); xml_ОткрытьФайл(стрИмяФайла); xml_Прочитать("<Товары>"); спрР=СоздатьОбъект("Справочник.Товары"); Пока xml_Прочитать("<Элемент>,</Товары>")=1 Цикл сч=сч+1; //Для ускорения Если сч%1000=0 Тогда //Для ускорения ЗафиксироватьТранзакцию(); //Для ускорения НачатьТранзакцию(); //Для ускорения КонецЕсли; //Для ускорения Если xml_ИмяТега="</Товары>" Тогда Прервать; КонецЕсли; Код=Число(xml_ПолучитьАтрибут("Код")); Наименование=xml_ПолучитьАтрибут("Наименование"); Единица=xml_ПолучитьАтрибут("Единица"); Цена=Число(xml_ПолучитьАтрибут("Цена")); ЭтоГруппа=Число(xml_ПолучитьАтрибут("ЭтоГруппа")); КодГруппы=Число(xml_ПолучитьАтрибут("Группа")); спрР.НайтиПоКоду(КодГруппы,0); Если спр.НайтиПоКоду(Код)=0 Тогда спр.ИспользоватьРодителя(спрР.ТекущийЭлемент()); Если ЭтоГруппа=1 Тогда спр.НоваяГруппа(); Иначе спр.Новый(); КонецЕсли; спр.Код = Код; КонецЕсли; спр.Родитель=спрР.ТекущийЭлемент(); спр.Наименование = Наименование; спр.Цена = Цена; спр.Единица = Единица; спр.Записать(); КонецЦикла; //по элементам XML xml_Закрыть(); Сообщить("Обработка завершена! "+ТекущееВремя(),"i"); ЗафиксироватьТранзакцию(); //Для ускорения КонецПроцедуры |
Это был пример обработки, которая читает файл XML, и создает многоуровневый
справочник товаров.
А теперь приведу пример записи того же самого файла XML.
перем xml_fso; перем xml_file; перем xml_СтекТегов; перем xml_ТегОткрыт; перем xml_Отступы; /////////////////////////////////////////////////////////////////////// //Открывает файл XML в режиме записи. Если файл существовал, перезаписывает его. //Принимает параметр прм_ИмяФайла - имя файла (укажите полный путь и расширение .XML) Процедура xml_СоздатьФайл(прм_ИмяФайла) xml_fso=СоздатьОбъект("Scripting.FileSystemObject"); xml_file=xml_fso.CreateTextFile(прм_ИмяФайла, -1, 0); //создать файл, перезаписывая существующий xml_file.WriteLine("<?xml version=""1.0"" encoding=""windows-1251""?>"); //Пишем заголовок XML xml_СтекТегов=СоздатьОбъект("СписокЗначений"); xml_Отступы=""; xml_ТегОткрыт=0; КонецПроцедуры /////////////////////////////////////////////////////////////////////// //Записывает начало элемента (тега XML). Имя можно указывать в угловых скобках. Процедура xml_ЗаписатьНачалоЭлемента(прм_ИмяТега) перем стр; Если xml_ТегОткрыт=1 Тогда xml_ТегОткрыт=0; xml_file.WriteLine(">"); xml_Отступы=xml_Отступы+" "; КонецЕсли; стр=прм_ИмяТега; стр=СтрЗаменить(стр, "<", ""); стр=СтрЗаменить(стр, ">", ""); xml_СтекТегов.ДобавитьЗначение(стр); xml_file.Write(xml_Отступы+"<"+стр); xml_ТегОткрыт=1; КонецПроцедуры /////////////////////////////////////////////////////////////////////// //Записывает атрибут (параметр) тега XML. Процедура xml_ЗаписатьАтрибут(прм_ИмяАтрибута, прм_ЗначениеАтрибута) Если xml_ТегОткрыт=0 Тогда Сообщить("Перед записью атрибута необходимо записать начало элемента!","!"); а=10/0; КонецЕсли; стр=прм_ЗначениеАтрибута; стр=СтрЗаменить(стр, "&", "&"); стр=СтрЗаменить(стр, """", """); стр=СтрЗаменить(стр, "", ""); стр=СтрЗаменить(стр, ">", ">"); стр=СтрЗаменить(стр, "'", "'"); xml_file.Write(" "+прм_ИмяАтрибута+"="+""""+стр+""""); КонецПроцедуры // xml_ЗаписатьЗаписатьАтрибут /////////////////////////////////////////////////////////////////////// //Записывает конец элемента (тега XML). Имя закрываемого тега можно указывать в угловых скобках, //а можно - не указывать вовсе. Процедура xml_ЗаписатьКонецЭлемента(прм_ОжидаемоеИмяТега="") перем стрИмяТега, а; Если xml_СтекТегов.РазмерСписка()<1 Тогда Сообщить("Попытка закрыть неоткрытый элемент!","!"); а=10/0; КонецЕсли; стрИмяТега=xml_СтекТегов.ПолучитьЗначение(xml_СтекТегов.РазмерСписка()); Если ПустаяСтрока(прм_ОжидаемоеИмяТега)=0 Тогда стр=прм_ОжидаемоеИмяТега; стр=СтрЗаменить(стр, "", ""); стр=СтрЗаменить(стр, ">", ""); стр=СтрЗаменить(стр, "/", ""); Если стр<>стрИмяТега Тогда Сообщить("Ожидается имя тега "+стр+", а закрыто "+стрИмяТега,"!"); а=10/0; КонецЕсли; КонецЕсли; xml_СтекТегов.УдалитьЗначение(xml_СтекТегов.РазмерСписка()); Если xml_ТегОткрыт=1 Тогда xml_ТегОткрыт=0; xml_file.WriteLine("/>"); Возврат; КонецЕсли; xml_Отступы=лев(xml_Отступы, СтрДлина(xml_Отступы)-2); xml_file.WriteLine(xml_Отступы+"</"+стрИмяТега+">"); КонецПроцедуры // xml_ЗаписатьКонецЭлемента /////////////////////////////////////////////////////////////////////// //Закрывает открытый файл XML. После окончания работы с файлом его необходимо закрыть. Функция xml_Закрыть() xml_file.Close(); Если xml_СтекТегов.РазмерСписка()<>0 Тогда Сообщить("Имеются незакрытые элементы XML!","!"); а=10/0; КонецЕсли; КонецФункции // xml_Закрыть //******************************************* Процедура Выполнить() стрИмяФайла=КаталогИБ()+"XML\tovar_out.xml"; Сообщить("Начало записи: "+стрИмяФайла); Сообщить("Время начала: "+ТекущееВремя()); xml_СоздатьФайл(стрИмяФайла); xml_ЗаписатьНачалоЭлемента("<Товары>"); спр=СоздатьОбъект("Справочник.Товары"); спр.ВыбратьЭлементы(); Пока спр.ПолучитьЭлемент()=1 Цикл xml_ЗаписатьНачалоЭлемента("<Элемент>"); xml_ЗаписатьАтрибут("Код", спр.Код); xml_ЗаписатьАтрибут("Наименование", СокрЛП(спр.Наименование)); Если спр.ЭтоГруппа()=1 Тогда xml_ЗаписатьАтрибут("ЭтоГруппа", "1"); Иначе xml_ЗаписатьАтрибут("Единица", СокрЛП(спр.Единица)); xml_ЗаписатьАтрибут("Цена", СокрЛП(спр.Цена)); КонецЕсли; Если ПустоеЗначение(спр.Родитель)=0 Тогда xml_ЗаписатьАтрибут("Группа", спр.Родитель.Код); КонецЕсли; xml_ЗаписатьКонецЭлемента("</Элемент>"); КонецЦикла; xml_ЗаписатьКонецЭлемента("</Товары>"); xml_Закрыть(); Сообщить("Конец записи: "+ТекущееВремя()); КонецПроцедуры |
Как видим, весь алгоритм записи файла XML занимает 100 строк, а
весь алгоритм чтения (парсинга) XML - 116 строк (учитывая комментарии
и пустые строчки, которые я добавил в код для ясности).
Чтение и запись XML в этом примере происходит намного быстрее, и
не потребляет память, по сравнению с тем, как это делает парсер
DOM (от которого, напомню, фирма 1С отказалась в версии 1С:Предприятие
8.0, и применила более простые средства последовательного доступа
к XML). Имена библиотечных функций, приведенных выше я сделал такими
же, как в 8-ке. Удалось даже, на мой взгляд, несколько улучшить
алгоритм. А именно, методы для чтения элемента и для записи завершающего
элемента принимают "контрольные" параметры - ожидаемый тег или список
ожидаемых тегов.
Пока xml_Прочитать("<Элемент>,</Товары>")=1 Цикл //... xml_ЗаписатьКонецЭлемента("</Элемент>");Это, на мой взгляд, помогает сделать код яснее.
Ссылка на файл с работающим примером конфигурации для 1С 7.7:
http://x-romix.narod.ru/XML_doc.rar
(скачивать левой кнопкой мыши, 288К)
Официальный
сайт рассылки - www.mista.ru
Волшебный форум - www.forum.mista.ru
Книга
знаний - www.kb.mista.ru
С уважением,
Станислав Митичкин (Волшебник)
stasmit@mail.ru
В избранное | ||