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

1. Drivingblind 233 26.11.21 05:36 Сейчас в теме +1 $m
Всем привет! Есть задача, прочитать xml-файл, загрузить из него объекты данных, записать в этот файл идентификаторы (ГУИД) загруженных объектов в нужное поле и вернуть файл назад уже с записанными идентификаторами, ничего в нем больше не изменяя.
Вопрос: как наиболее быстро это сделать? Иными словами, можно ли обновить в xml-файле только нужное поле, не считывая/перезаписывая файл повторно целиком?
Вознаграждение за ответ
Показать полностью
Найденные решения
13. Drivingblind 233 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 Ответить
3. Drivingblind 233 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 233 26.11.21 06:22 Сейчас в теме
(4) подскажите, может, есть какой-то инструмент для одновременного и чтения, и записи xml?
9. laperuz 47 26.11.21 06:49 Сейчас в теме
(8)Вроде бы нет, поэтому придется читать в промежуточный объект, его читать/изменять и потом записывать. Ну это если есть задача за один проход все сделать.
Drivingblind; +1 Ответить
5. acces969 362 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 233 26.11.21 06:16 Сейчас в теме
(6)
#МЕСТОДЛЯИД#

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

К сожалению, это тоже вряд ли подойдет, т.к. придется дорабатывать систему-отправитель
12. starik-2005 3088 26.11.21 14:55 Сейчас в теме
1. Прочитать файл, накопить объектные соответствия в соответствии (ИД из файла, ИД из программы).
2. Прочитать файл целиком в строку текста.
3. Для Каждого С ИЗ Соответствие Цикл Строка = СтрЗаменить(Строка, С.Ключ, С.Значение) КонецЦикла.
4. Записать файл. Старый для истории переименовать в .xmlold.
Drivingblind; +1 Ответить
13. Drivingblind 233 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); 
	КонецЕсли;     

КонецЦикла;
Показать
Оставьте свое сообщение

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