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

1. Drivingblind 227 26.11.21 05:36 Сейчас в теме +1 $m
Всем привет! Есть задача, прочитать xml-файл, загрузить из него объекты данных, записать в этот файл идентификаторы (ГУИД) загруженных объектов в нужное поле и вернуть файл назад уже с записанными идентификаторами, ничего в нем больше не изменяя.
Вопрос: как наиболее быстро это сделать? Иными словами, можно ли обновить в xml-файле только нужное поле, не считывая/перезаписывая файл повторно целиком?
Вознаграждение за ответ
Показать полностью
Найденные решения
13. Drivingblind 227 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 46 26.11.21 05:52 Сейчас в теме
Читать через ФабрикаXDTO, записывать ГУИД сразу же в момент создания объекта, в этот момент вы в цикле как раз будете иметь доступ к текущему объекту XDTO.

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

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

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

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

КонецЦикла;
Показать
Оставьте свое сообщение
Вакансии
Программист 1С
Казань
зарплата от 150 000 руб.
Полный день

Программист 1С:ERP
Москва
зарплата от 100 000 руб.
Полный день

Разработчик 1С
Москва
зарплата от 200 000 руб. до 300 000 руб.
Полный день

Программист 1С (удаленно)
Самара
зарплата от 230 000 руб. до 230 000 руб.
Полный день

Руководитель группы разработки 1С
Москва
зарплата от 250 000 руб. до 250 000 руб.
Полный день