Как оптимальнее всего прочитать и обновить только конкретное поле в XML-файле?

1. Drivingblind 237 26.11.21 05:36 Сейчас в теме +1 $m
Всем привет! Есть задача, прочитать xml-файл, загрузить из него объекты данных, записать в этот файл идентификаторы (ГУИД) загруженных объектов в нужное поле и вернуть файл назад уже с записанными идентификаторами, ничего в нем больше не изменяя.
Вопрос: как наиболее быстро это сделать? Иными словами, можно ли обновить в xml-файле только нужное поле, не считывая/перезаписывая файл повторно целиком?
Вознаграждение за ответ
Показать полностью
Найденные решения
13. Drivingblind 237 03.12.21 06:47 Сейчас в теме
(2),
(5),
(12), Сделал следующим образом: у объекта ЗаписьXML есть метод "ЗаписатьТекущий", который записывает текущий элемент xml. На вход подается объект ЧтениеXML. Таким образом, можно записать XML и подменить только нужные поля.

// добавить нужные имена для замены
РезультатОбработкиСообщения = Новый Структура();
РезультатОбработкиСообщения.Вставить("СтатусОбработки", "");
РезультатОбработкиСообщения.Добавить("ОписаниеОшибки", "");

Пока ЧтениеXML.Прочитать() Цикл
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        
        УзелПишемЗначение    = РезультатОбработкиСообщения.Свойство(ЧтениеXML.ЛокальноеИмя);
        ЗначениеЗаписано    = Ложь;
        
        Если УзелПишемЗначение И ЗначениеЗаполнено(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]) Тогда
            ЗаписьXML.ЗаписатьНачалоЭлемента(ЧтениеXML.ЛокальноеИмя);
            
            //Убираем, если необходимо, атрибут "nil"
            Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
                Если ЧтениеXML.ЛокальноеИмя <> "nil" Тогда
                    ЗаписьXML.ЗаписатьАтрибут(ЧтениеXML.Префикс + ":" + ЧтениеXML.ЛокальноеИмя, ЧтениеXML.Значение);
                КонецЕсли;
            КонецЦикла;
            
            Продолжить;
            
        Иначе
            ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
        КонецЕсли;
        
    ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст И УзелПишемЗначение Тогда
        
        //Присваиваем новое значение тега XML 
        ЗаписьXML.ЗаписатьТекст(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]); 
        ЗначениеЗаписано = Истина;
        
    ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И УзелПишемЗначение Тогда
        
        //Если элемент был с пустым значением, оно будет записываться перед концом элемента
        Если НЕ ЗначениеЗаписано Тогда
            ЗаписьXML.ЗаписатьТекст(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]); 
            ЗначениеЗаписано = Истина;
        КонецЕсли;
        
        УзелПишемЗначение = Ложь;
        ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
        
    Иначе
        ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
    КонецЕсли;     

КонецЦикла;

Показать
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. laperuz 47 26.11.21 05:52 Сейчас в теме
Читать через ФабрикаXDTO, записывать ГУИД сразу же в момент создания объекта, в этот момент вы в цикле как раз будете иметь доступ к текущему объекту XDTO.

UPD: вот на коленке пример набросал.
Прикрепленные файлы:
ЧтениеИИзменениеXDTO.epf
Drivingblind; +1 Ответить 9
3. Drivingblind 237 26.11.21 06:07 Сейчас в теме
(2)
ФабрикаXDTO, записывать ГУИД сразу же в момент создания объекта, в этот момент вы в цикле как раз будете иметь доступ к текущему объекту XDTO.

и сразу после получения ГУИДа, пока объект XDTO еще существует, записывать его назад в файл?
Не знаю, подойдет ли этот вариант, т.к. в файле могут быть несколько разных пространств имен. Например, элемент <Head> относится к пространству имен "http://www.1c.ru/SSL/Exchange/Message", а <body> - свой кастомный пакет
4. laperuz 47 26.11.21 06:10 Сейчас в теме
(3)В файл записывать потом, сначала просто устанавливать значение свойства у объектаXDTO. Но это как вариант. Можно в принципе то же самое через DOMDocument организовать, но он помедленнее.
8. Drivingblind 237 26.11.21 06:22 Сейчас в теме
(4) подскажите, может, есть какой-то инструмент для одновременного и чтения, и записи xml?
9. laperuz 47 26.11.21 06:49 Сейчас в теме
(8)Вроде бы нет, поэтому придется читать в промежуточный объект, его читать/изменять и потом записывать. Ну это если есть задача за один проход все сделать.
Drivingblind; +1 Ответить
5. acces969 369 26.11.21 06:10 Сейчас в теме
(3)
А если не использовать тяжелые объекты чтения и обработки xml?
ЧтениеТекста, СтрНайти, Сред...
dehro; Drivingblind; +2 Ответить
6. laperuz 47 26.11.21 06:13 Сейчас в теме
(5)Кстати, как вариант) Иметь в файле заглушку в виде "#МЕСТОДЛЯИД#, в массиве хранить гуиды и просто по порядку вхождения заменять. Кстати, средства работы со строками даже на очень длинных строках(проверял на файлах с текстом по 50 Мб) работают мгновенно, чего не скажешь про средства работы с XML.
Drivingblind; +1 Ответить
7. Drivingblind 237 26.11.21 06:16 Сейчас в теме
(6)
#МЕСТОДЛЯИД#

Такой подход точно не подойдет, т.к. пакет валидируется по xsd-схеме. Изменять её тоже вряд ли кто-то будет.
10. acces969 369 26.11.21 06:51 Сейчас в теме
(7)Не обязтаельно заглушки втыкать. Можно вначале файла писать в узел атрибуты с нужными инструкциями, по которому обработчик будет обращаться сразу по нужным адресам в файле.
11. Drivingblind 237 26.11.21 08:33 Сейчас в теме
(10)
Можно вначале файла писать в узел атрибуты с нужными инструкциями

К сожалению, это тоже вряд ли подойдет, т.к. придется дорабатывать систему-отправитель
12. starik-2005 3170 26.11.21 14:55 Сейчас в теме
1. Прочитать файл, накопить объектные соответствия в соответствии (ИД из файла, ИД из программы).
2. Прочитать файл целиком в строку текста.
3. Для Каждого С ИЗ Соответствие Цикл Строка = СтрЗаменить(Строка, С.Ключ, С.Значение) КонецЦикла.
4. Записать файл. Старый для истории переименовать в .xmlold.
Drivingblind; +1 Ответить
13. Drivingblind 237 03.12.21 06:47 Сейчас в теме
(2),
(5),
(12), Сделал следующим образом: у объекта ЗаписьXML есть метод "ЗаписатьТекущий", который записывает текущий элемент xml. На вход подается объект ЧтениеXML. Таким образом, можно записать XML и подменить только нужные поля.

// добавить нужные имена для замены
РезультатОбработкиСообщения = Новый Структура();
РезультатОбработкиСообщения.Вставить("СтатусОбработки", "");
РезультатОбработкиСообщения.Добавить("ОписаниеОшибки", "");

Пока ЧтениеXML.Прочитать() Цикл
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        
        УзелПишемЗначение    = РезультатОбработкиСообщения.Свойство(ЧтениеXML.ЛокальноеИмя);
        ЗначениеЗаписано    = Ложь;
        
        Если УзелПишемЗначение И ЗначениеЗаполнено(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]) Тогда
            ЗаписьXML.ЗаписатьНачалоЭлемента(ЧтениеXML.ЛокальноеИмя);
            
            //Убираем, если необходимо, атрибут "nil"
            Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
                Если ЧтениеXML.ЛокальноеИмя <> "nil" Тогда
                    ЗаписьXML.ЗаписатьАтрибут(ЧтениеXML.Префикс + ":" + ЧтениеXML.ЛокальноеИмя, ЧтениеXML.Значение);
                КонецЕсли;
            КонецЦикла;
            
            Продолжить;
            
        Иначе
            ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
        КонецЕсли;
        
    ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст И УзелПишемЗначение Тогда
        
        //Присваиваем новое значение тега XML 
        ЗаписьXML.ЗаписатьТекст(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]); 
        ЗначениеЗаписано = Истина;
        
    ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И УзелПишемЗначение Тогда
        
        //Если элемент был с пустым значением, оно будет записываться перед концом элемента
        Если НЕ ЗначениеЗаписано Тогда
            ЗаписьXML.ЗаписатьТекст(РезультатОбработкиСообщения[ЧтениеXML.ЛокальноеИмя]); 
            ЗначениеЗаписано = Истина;
        КонецЕсли;
        
        УзелПишемЗначение = Ложь;
        ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
        
    Иначе
        ЗаписьXML.ЗаписатьТекущий(ЧтениеXML); 
    КонецЕсли;     

КонецЦикла;

Показать
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот