Всем привет! Есть задача, прочитать xml-файл, загрузить из него объекты данных, записать в этот файл идентификаторы (ГУИД) загруженных объектов в нужное поле и вернуть файл назад уже с записанными идентификаторами, ничего в нем больше не изменяя.
Вопрос: как наиболее быстро это сделать? Иными словами, можно ли обновить в xml-файле только нужное поле, не считывая/перезаписывая файл повторно целиком?
---
,
(5),
(12), Сделал следующим образом: у объекта ЗаписьXML есть метод "ЗаписатьТекущий", который записывает текущий элемент xml. На вход подается объект ЧтениеXML. Таким образом, можно записать XML и подменить только нужные поля.

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

    Пока Чтение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);
    КонецЕсли;

    КонецЦикла;
```
---
Читать через ФабрикаXDTO, записывать ГУИД сразу же в момент создания объекта, в этот момент вы в цикле как раз будете иметь доступ к текущему объекту XDTO.

UPD: вот на коленке пример набросал.
---
ФабрикаXDTO, записывать ГУИД сразу же в момент создания объекта, в этот момент вы в цикле как раз будете иметь доступ к текущему объекту XDTO.
и сразу после получения ГУИДа, пока объект XDTO еще существует, записывать его назад в файл?
Не знаю, подойдет ли этот вариант, т.к. в файле могут быть несколько разных пространств имен. Например, элемент <Head> относится к пространству имен "http://www.1c.ru/SSL/Exchange/Message", а <body> - свой кастомный пакет
---
В файл записывать потом, сначала просто устанавливать значение свойства у объектаXDTO. Но это как вариант. Можно в принципе то же самое через DOMDocument организовать, но он помедленнее.
---
подскажите, может, есть какой-то инструмент для одновременного и чтения, и записи xml?
---
Вроде бы нет, поэтому придется читать в промежуточный объект, его читать/изменять и потом записывать. Ну это если есть задача за один проход все сделать.
---
А если не использовать тяжелые объекты чтения и обработки xml?
ЧтениеТекста, СтрНайти, Сред...
---
Кстати, как вариант) Иметь в файле заглушку в виде "#МЕСТОДЛЯИД#, в массиве хранить гуиды и просто по порядку вхождения заменять. Кстати, средства работы со строками даже на очень длинных строках(проверял на файлах с текстом по 50 Мб) работают мгновенно, чего не скажешь про средства работы с XML.
---
#МЕСТОДЛЯИД#
Такой подход точно не подойдет, т.к. пакет валидируется по xsd-схеме. Изменять её тоже вряд ли кто-то будет.
---
Не обязтаельно заглушки втыкать. Можно вначале файла писать в узел атрибуты с нужными инструкциями, по которому обработчик будет обращаться сразу по нужным адресам в файле.
---
Можно вначале файла писать в узел атрибуты с нужными инструкциями
К сожалению, это тоже вряд ли подойдет, т.к. придется дорабатывать систему-отправитель
---
1. Прочитать файл, накопить объектные соответствия в соответствии (ИД из файла, ИД из программы).
2. Прочитать файл целиком в строку текста.
3. Для Каждого С ИЗ Соответствие Цикл Строка = СтрЗаменить(Строка, С.Ключ, С.Значение) КонецЦикла.
4. Записать файл. Старый для истории переименовать в .xmlold.
---
,
(5),
(12), Сделал следующим образом: у объекта ЗаписьXML есть метод "ЗаписатьТекущий", который записывает текущий элемент xml. На вход подается объект ЧтениеXML. Таким образом, можно записать XML и подменить только нужные поля.

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

    Пока Чтение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);
    КонецЕсли;

    КонецЦикла;
```